1 /* 2 * Copyright 2013-2015, Rene Gollent, rene@gollent.com. 3 * Distributed under the terms of the MIT License. 4 */ 5 #include "ImageStopConfigView.h" 6 7 #include <Button.h> 8 #include <CheckBox.h> 9 #include <LayoutBuilder.h> 10 #include <ListView.h> 11 #include <MenuField.h> 12 #include <ScrollView.h> 13 14 #include <AutoDeleter.h> 15 #include <AutoLocker.h> 16 17 #include "AppMessageCodes.h" 18 #include "FunctionInstance.h" 19 #include "Image.h" 20 #include "ImageDebugInfo.h" 21 #include "MessageCodes.h" 22 #include "UserInterface.h" 23 24 25 enum { 26 MSG_SET_STOP_FOR_ALL_IMAGES = 'sfai', 27 MSG_SET_STOP_FOR_CUSTOM_IMAGES = 'sfci', 28 MSG_IMAGE_NAME_SELECTION_CHANGED = 'insc', 29 MSG_ADD_IMAGE_NAME = 'anin', 30 MSG_REMOVE_IMAGE_NAME = 'arin', 31 MSG_IMAGE_NAME_INPUT_CHANGED = 'inic' 32 }; 33 34 35 static int SortStringItems(const void* a, const void* b) 36 { 37 BStringItem* item1 = *(BStringItem**)a; 38 BStringItem* item2 = *(BStringItem**)b; 39 40 return strcmp(item1->Text(), item2->Text()); 41 } 42 43 44 ImageStopConfigView::ImageStopConfigView(::Team* team, 45 UserInterfaceListener* listener) 46 : 47 BGroupView(B_VERTICAL), 48 fTeam(team), 49 fListener(listener), 50 fStopOnImageLoad(NULL), 51 fStopImageConstraints(NULL), 52 fStopImageNames(NULL), 53 fStopImageNameInput(NULL), 54 fAddImageNameButton(NULL), 55 fRemoveImageNameButton(NULL), 56 fCustomImageGroup(NULL), 57 fStopOnLoadEnabled(false), 58 fUseCustomImages(false) 59 { 60 SetName("Images"); 61 fTeam->AddListener(this); 62 } 63 64 65 ImageStopConfigView::~ImageStopConfigView() 66 { 67 fTeam->RemoveListener(this); 68 } 69 70 71 ImageStopConfigView* 72 ImageStopConfigView::Create(::Team* team, UserInterfaceListener* listener) 73 { 74 ImageStopConfigView* self = new ImageStopConfigView(team, listener); 75 76 try { 77 self->_Init(); 78 } catch (...) { 79 delete self; 80 throw; 81 } 82 83 return self; 84 } 85 86 87 void 88 ImageStopConfigView::AttachedToWindow() 89 { 90 fAddImageNameButton->SetEnabled(false); 91 fRemoveImageNameButton->SetEnabled(false); 92 93 fStopImageConstraints->Menu()->SetTargetForItems(this); 94 fStopOnImageLoad->SetTarget(this); 95 fAddImageNameButton->SetTarget(this); 96 fRemoveImageNameButton->SetTarget(this); 97 fStopImageNames->SetTarget(this); 98 fStopImageNameInput->SetTarget(this); 99 100 AutoLocker< ::Team> teamLocker(fTeam); 101 _UpdateStopImageState(); 102 103 BGroupView::AttachedToWindow(); 104 } 105 106 107 void 108 ImageStopConfigView::MessageReceived(BMessage* message) 109 { 110 switch (message->what) { 111 case MSG_SET_STOP_FOR_ALL_IMAGES: 112 { 113 fListener->SetStopOnImageLoadRequested( 114 fStopOnImageLoad->Value() == B_CONTROL_ON, 115 false); 116 break; 117 } 118 119 case MSG_SET_STOP_FOR_CUSTOM_IMAGES: 120 { 121 fListener->SetStopOnImageLoadRequested( 122 fStopOnImageLoad->Value() == B_CONTROL_ON, 123 true); 124 break; 125 } 126 127 case MSG_IMAGE_NAME_SELECTION_CHANGED: 128 { 129 if (!fUseCustomImages) 130 break; 131 132 fRemoveImageNameButton->SetEnabled( 133 fStopImageNames->CurrentSelection() >= 0); 134 break; 135 } 136 137 case MSG_IMAGE_NAME_INPUT_CHANGED: 138 { 139 BString imageName(fStopImageNameInput->Text()); 140 imageName.Trim(); 141 fAddImageNameButton->SetEnabled(!imageName.IsEmpty()); 142 break; 143 } 144 145 case MSG_STOP_ON_IMAGE_LOAD: 146 { 147 fListener->SetStopOnImageLoadRequested( 148 fStopOnImageLoad->Value() == B_CONTROL_ON, 149 fUseCustomImages); 150 break; 151 } 152 153 case MSG_STOP_IMAGE_SETTINGS_CHANGED: 154 { 155 _UpdateStopImageState(); 156 break; 157 } 158 159 case MSG_ADD_IMAGE_NAME: 160 { 161 BString imageName(fStopImageNameInput->Text()); 162 imageName.Trim(); 163 AutoLocker< ::Team> teamLocker(fTeam); 164 if (fTeam->StopImageNames().HasString(imageName)) 165 break; 166 167 fStopImageNameInput->SetText(""); 168 fListener->AddStopImageNameRequested(imageName.String()); 169 break; 170 } 171 172 case MSG_STOP_IMAGE_NAME_ADDED: 173 { 174 const char* imageName; 175 if (message->FindString("name", &imageName) != B_OK) 176 break; 177 178 BStringItem* item = new(std::nothrow) BStringItem(imageName); 179 if (item == NULL) 180 break; 181 182 ObjectDeleter<BStringItem> itemDeleter(item); 183 if (!fStopImageNames->AddItem(item)) { 184 break; 185 } 186 itemDeleter.Detach(); 187 fStopImageNames->SortItems(SortStringItems); 188 break; 189 } 190 191 case MSG_REMOVE_IMAGE_NAME: 192 { 193 BStringItem* item; 194 int32 selectedIndex; 195 AutoLocker< ::Team> teamLocker(fTeam); 196 int32 i = 0; 197 while ((selectedIndex = fStopImageNames->CurrentSelection(i++)) 198 >= 0) { 199 item = (BStringItem*)fStopImageNames->ItemAt(selectedIndex); 200 fListener->RemoveStopImageNameRequested(item->Text()); 201 } 202 break; 203 } 204 205 case MSG_STOP_IMAGE_NAME_REMOVED: 206 { 207 const char* imageName; 208 if (message->FindString("name", &imageName) != B_OK) 209 break; 210 211 for (int32 i = 0; i < fStopImageNames->CountItems(); i++) { 212 BStringItem* item = (BStringItem*)fStopImageNames->ItemAt(i); 213 if (strcmp(item->Text(), imageName) == 0) { 214 fStopImageNames->RemoveItem(i); 215 delete item; 216 } 217 } 218 break; 219 } 220 221 222 default: 223 BGroupView::MessageReceived(message); 224 break; 225 } 226 227 } 228 229 230 void 231 ImageStopConfigView::StopOnImageLoadSettingsChanged( 232 const Team::ImageLoadEvent& event) 233 { 234 BMessage message(MSG_STOP_IMAGE_SETTINGS_CHANGED); 235 message.AddBool("enabled", event.StopOnImageLoad()); 236 message.AddBool("useNameList", event.StopImageNameListEnabled()); 237 BMessenger(this).SendMessage(&message); 238 } 239 240 241 void 242 ImageStopConfigView::StopOnImageLoadNameAdded( 243 const Team::ImageLoadNameEvent& event) 244 { 245 BMessage message(MSG_STOP_IMAGE_NAME_ADDED); 246 message.AddString("name", event.ImageName()); 247 BMessenger(this).SendMessage(&message); 248 } 249 250 251 void 252 ImageStopConfigView::StopOnImageLoadNameRemoved( 253 const Team::ImageLoadNameEvent& event) 254 { 255 BMessage message(MSG_STOP_IMAGE_NAME_REMOVED); 256 message.AddString("name", event.ImageName()); 257 BMessenger(this).SendMessage(&message); 258 } 259 260 261 void 262 ImageStopConfigView::_Init() 263 { 264 BMenu* stopImageMenu = new BMenu("stopImageTypesMenu"); 265 266 stopImageMenu->AddItem(new BMenuItem("All", 267 new BMessage(MSG_SET_STOP_FOR_ALL_IMAGES))); 268 stopImageMenu->AddItem(new BMenuItem("Custom", 269 new BMessage(MSG_SET_STOP_FOR_CUSTOM_IMAGES))); 270 271 fStopImageNames = new BListView("customImageList", 272 B_MULTIPLE_SELECTION_LIST); 273 fStopImageNames->SetSelectionMessage( 274 new BMessage(MSG_IMAGE_NAME_SELECTION_CHANGED)); 275 276 fCustomImageGroup = new BGroupView(); 277 BLayoutBuilder::Group<>(fCustomImageGroup, B_VERTICAL, 0.0) 278 .Add(new BScrollView("stopImageScroll", fStopImageNames, 279 0, false, true)) 280 .Add(fStopImageNameInput = new BTextControl("stopImageName", 281 "Image:", NULL, NULL)) 282 .AddGroup(B_HORIZONTAL) 283 .SetInsets(B_USE_SMALL_SPACING) 284 .AddGlue() 285 .Add(fAddImageNameButton = new BButton("Add", 286 new BMessage(MSG_ADD_IMAGE_NAME))) 287 .Add(fRemoveImageNameButton = new BButton("Remove", 288 new BMessage(MSG_REMOVE_IMAGE_NAME))) 289 .End(); 290 291 BLayoutBuilder::Group<>(this, B_VERTICAL) 292 .SetInsets(B_USE_SMALL_SPACING) 293 .Add(fStopOnImageLoad = new BCheckBox("stopOnImage", 294 "Stop when an image is loaded", 295 new BMessage(MSG_STOP_ON_IMAGE_LOAD))) 296 .Add(fStopImageConstraints = new BMenuField( 297 "stopTypes", "Types:", stopImageMenu)) 298 .Add(fCustomImageGroup); 299 300 font_height fontHeight; 301 be_plain_font->GetHeight(&fontHeight); 302 float minListHeight = 5 * (fontHeight.ascent + fontHeight.descent 303 + fontHeight.leading); 304 fStopImageNames->SetExplicitMinSize(BSize(B_SIZE_UNSET, minListHeight)); 305 306 stopImageMenu->SetLabelFromMarked(true); 307 fStopImageNameInput->SetModificationMessage( 308 new BMessage(MSG_IMAGE_NAME_INPUT_CHANGED)); 309 } 310 311 312 void 313 ImageStopConfigView::_UpdateStopImageState() 314 { 315 fStopOnLoadEnabled = fTeam->StopOnImageLoad(); 316 fStopOnImageLoad->SetValue( 317 fStopOnLoadEnabled ? B_CONTROL_ON : B_CONTROL_OFF); 318 fUseCustomImages = fTeam->StopImageNameListEnabled(); 319 fStopImageConstraints->Menu() 320 ->ItemAt(fUseCustomImages ? 1 : 0)->SetMarked(true); 321 322 fStopImageNames->MakeEmpty(); 323 const BStringList& imageNames = fTeam->StopImageNames(); 324 for (int32 i = 0; i < imageNames.CountStrings(); i++) { 325 BStringItem* item = new(std::nothrow) BStringItem( 326 imageNames.StringAt(i)); 327 if (item == NULL) 328 return; 329 item->SetEnabled(fUseCustomImages); 330 ObjectDeleter<BStringItem> itemDeleter(item); 331 if (!fStopImageNames->AddItem(item)) 332 return; 333 itemDeleter.Detach(); 334 } 335 336 fStopImageConstraints->SetEnabled(fStopOnLoadEnabled); 337 fStopImageNameInput->SetEnabled(fUseCustomImages); 338 } 339