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