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
SortStringItems(const void * a,const void * b)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
ImageStopConfigView(::Team * team,UserInterfaceListener * listener)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
~ImageStopConfigView()65 ImageStopConfigView::~ImageStopConfigView()
66 {
67 fTeam->RemoveListener(this);
68 }
69
70
71 ImageStopConfigView*
Create(::Team * team,UserInterfaceListener * listener)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
AttachedToWindow()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
MessageReceived(BMessage * message)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
StopOnImageLoadSettingsChanged(const Team::ImageLoadEvent & event)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
StopOnImageLoadNameAdded(const Team::ImageLoadNameEvent & event)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
StopOnImageLoadNameRemoved(const Team::ImageLoadNameEvent & event)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
_Init()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
_UpdateStopImageState()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