xref: /haiku/src/kits/interface/Control.cpp (revision be3db2942c0e8dda63cdd226ec3c99309d3eab0c)
1 /*
2  * Copyright 2001-2006, Haiku Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Marc Flerackers (mflerackers@androme.be)
7  */
8 
9 /*!	BControl is the base class for user-event handling objects. */
10 
11 
12 #include <Control.h>
13 #include <PropertyInfo.h>
14 #include <Window.h>
15 
16 #include <stdlib.h>
17 #include <string.h>
18 
19 
20 static property_info sPropertyList[] = {
21 	{
22 		"Enabled",
23 		{ B_GET_PROPERTY, B_SET_PROPERTY },
24 		{ B_DIRECT_SPECIFIER },
25 		NULL, 0,
26 		{ B_BOOL_TYPE }
27 	},
28 	{
29 		"Label",
30 		{ B_GET_PROPERTY, B_SET_PROPERTY },
31 		{ B_DIRECT_SPECIFIER },
32 		NULL, 0,
33 		{ B_STRING_TYPE }
34 	},
35 	{
36 		"Value",
37 		{ B_GET_PROPERTY, B_SET_PROPERTY },
38 		{ B_DIRECT_SPECIFIER },
39 		NULL, 0,
40 		{ B_INT32_TYPE }
41 	},
42 	{}
43 };
44 
45 
46 BControl::BControl(BRect frame, const char *name, const char *label,
47 	BMessage *message, uint32 resizingMode, uint32 flags)
48 	: BView(frame, name, resizingMode, flags)
49 {
50 	InitData(NULL);
51 
52 	SetLabel(label);
53 	SetMessage(message);
54 }
55 
56 
57 BControl::~BControl()
58 {
59 	free(fLabel);
60 	SetMessage(NULL);
61 }
62 
63 
64 BControl::BControl(BMessage *archive)
65 	: BView(archive)
66 {
67 	InitData(archive);
68 
69 	BMessage message;
70 	if (archive->FindMessage("_msg", &message) == B_OK)
71 		SetMessage(new BMessage(message));
72 
73 	const char *label;
74 	if (archive->FindString("_label", &label) != B_OK)
75 		SetLabel(label);
76 
77 	int32 value;
78 	if (archive->FindInt32("_val", &value) != B_OK)
79 		SetValue(value);
80 
81 	bool toggle;
82 	if (archive->FindBool("_disable", &toggle) != B_OK)
83 		SetEnabled(!toggle);
84 
85 	if (archive->FindBool("be:wants_nav", &toggle) != B_OK)
86 		fWantsNav = toggle;
87 }
88 
89 
90 BArchivable *
91 BControl::Instantiate(BMessage *archive)
92 {
93 	if (validate_instantiation(archive, "BControl"))
94 		return new BControl(archive);
95 
96 	return NULL;
97 }
98 
99 
100 status_t
101 BControl::Archive(BMessage *archive, bool deep) const
102 {
103 	status_t status = BView::Archive(archive, deep);
104 
105 	if (status == B_OK && Message())
106 		status = archive->AddMessage("_msg", Message ());
107 
108 	if (status == B_OK && fLabel)
109 		status = archive->AddString("_label", fLabel);
110 
111 	if (status == B_OK && fValue != B_CONTROL_OFF)
112 		status = archive->AddInt32("_val", fValue);
113 
114 	if (status == B_OK && !fEnabled)
115 		status = archive->AddBool("_disable", true);
116 
117 	return status;
118 }
119 
120 
121 void
122 BControl::WindowActivated(bool active)
123 {
124 	BView::WindowActivated(active);
125 
126 	if (IsFocus())
127 		Invalidate();
128 }
129 
130 
131 void
132 BControl::AttachedToWindow()
133 {
134 	if (Parent()) {
135 		// inherit the color from parent
136 		rgb_color color = Parent()->ViewColor();
137 
138 		SetViewColor(color);
139 		SetLowColor(color);
140 	}
141 
142 	if (!Messenger().IsValid())
143 		SetTarget(Window());
144 
145 	BView::AttachedToWindow();
146 }
147 
148 
149 void
150 BControl::MessageReceived(BMessage *message)
151 {
152 	if (message->what == B_GET_PROPERTY || message->what == B_SET_PROPERTY) {
153 		BMessage reply(B_REPLY);
154 		bool handled = false;
155 
156 		BMessage specifier;
157 		int32 index;
158 		int32 form;
159 		const char *property;
160 		if (message->GetCurrentSpecifier(&index, &specifier, &form, &property) == B_OK) {
161 			if (strcmp(property, "Label") == 0) {
162 				if (message->what == B_GET_PROPERTY) {
163 					reply.AddString("result", fLabel);
164 					handled = true;
165 				} else {
166 					// B_GET_PROPERTY
167 					const char *label;
168 					if (message->FindString("data", &label) == B_OK) {
169 						SetLabel(label);
170 						reply.AddInt32("error", B_OK);
171 						handled = true;
172 					}
173 				}
174 			} else if (strcmp(property, "Value") == 0) {
175 				if (message->what == B_GET_PROPERTY) {
176 					reply.AddInt32("result", fValue);
177 					handled = true;
178 				} else {
179 					// B_GET_PROPERTY
180 					int32 value;
181 					if (message->FindInt32("data", &value) == B_OK) {
182 						SetValue(value);
183 						reply.AddInt32("error", B_OK);
184 						handled = true;
185 					}
186 				}
187 			} else if (strcmp(property, "Enabled") == 0) {
188 				if (message->what == B_GET_PROPERTY) {
189 					reply.AddBool("result", fEnabled);
190 					handled = true;
191 				} else {
192 					// B_GET_PROPERTY
193 					bool enabled;
194 					if (message->FindBool("data", &enabled) == B_OK) {
195 						SetEnabled(enabled);
196 						reply.AddInt32("error", B_OK);
197 						handled = true;
198 					}
199 				}
200 			}
201 		}
202 
203 		if (handled) {
204 			message->SendReply(&reply);
205 			return;
206 		}
207 	}
208 
209 	BView::MessageReceived(message);
210 }
211 
212 
213 void
214 BControl::MakeFocus(bool focused)
215 {
216 	if (focused == IsFocus())
217 		return;
218 
219 	BView::MakeFocus(focused);
220 
221  	if (Window()) {
222 		fFocusChanging = true;
223 		Invalidate(Bounds());
224 		Flush();
225 		fFocusChanging = false;
226 	}
227 }
228 
229 
230 void
231 BControl::KeyDown(const char *bytes, int32 numBytes)
232 {
233 	if (*bytes == B_ENTER || *bytes == B_SPACE) {
234 		if (!fEnabled)
235 			return;
236 
237 		SetValue(Value() ? B_CONTROL_OFF : B_CONTROL_ON);
238 		Invoke();
239 	} else
240 		BView::KeyDown(bytes, numBytes);
241 }
242 
243 
244 void
245 BControl::MouseDown(BPoint point)
246 {
247 	BView::MouseDown(point);
248 }
249 
250 
251 void
252 BControl::MouseUp(BPoint point)
253 {
254 	BView::MouseUp(point);
255 }
256 
257 
258 void
259 BControl::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
260 {
261 	BView::MouseMoved(point, transit, message);
262 }
263 
264 
265 void
266 BControl::DetachedFromWindow()
267 {
268 	BView::DetachedFromWindow();
269 }
270 
271 
272 void
273 BControl::SetLabel(const char *label)
274 {
275 	if (label != NULL && !label[0])
276 		label = NULL;
277 
278 	// Has the label been changed?
279 	if ((fLabel && label && !strcmp(fLabel, label))
280 		|| ((fLabel == NULL || !fLabel[0]) && label == NULL))
281 		return;
282 
283 	free(fLabel);
284 	fLabel = label ? strdup(label) : NULL;
285 
286 	InvalidateLayout();
287 	Invalidate();
288 }
289 
290 
291 const char *
292 BControl::Label() const
293 {
294 	return fLabel;
295 }
296 
297 
298 void
299 BControl::SetValue(int32 value)
300 {
301 	if (value == fValue)
302 		return;
303 
304 	fValue = value;
305 	Invalidate();
306 }
307 
308 
309 void
310 BControl::SetValueNoUpdate(int32 value)
311 {
312 	fValue = value;
313 }
314 
315 
316 int32
317 BControl::Value() const
318 {
319 	return fValue;
320 }
321 
322 
323 void
324 BControl::SetEnabled(bool enabled)
325 {
326 	if (fEnabled == enabled)
327 		return;
328 
329 	fEnabled = enabled;
330 
331 	if (fEnabled)
332 		BView::SetFlags(Flags() | B_NAVIGABLE);
333 	else
334 		BView::SetFlags(Flags() & ~B_NAVIGABLE);
335 
336 	if (Window()) {
337 		Invalidate(Bounds());
338 		Flush();
339 	}
340 }
341 
342 
343 bool
344 BControl::IsEnabled() const
345 {
346 	return fEnabled;
347 }
348 
349 
350 void
351 BControl::GetPreferredSize(float *_width, float *_height)
352 {
353 	BView::GetPreferredSize(_width, _height);
354 }
355 
356 
357 void
358 BControl::ResizeToPreferred()
359 {
360 	BView::ResizeToPreferred();
361 }
362 
363 
364 status_t
365 BControl::Invoke(BMessage *message)
366 {
367 	bool notify = false;
368 	uint32 kind = InvokeKind(&notify);
369 
370 	if (!message && !notify)
371 		message = Message();
372 
373 	BMessage clone(kind);
374 
375 	if (!message) {
376 		if (!IsWatched())
377 			return B_BAD_VALUE;
378 	} else
379 		clone = *message;
380 
381 	clone.AddInt64("when", (int64)system_time());
382 	clone.AddPointer("source", this);
383 	clone.AddInt32("be:value", fValue);
384 	clone.AddMessenger("be:sender", BMessenger(this));
385 
386 	// ToDo: is this correct? If message == NULL (even if IsWatched()), we always return B_BAD_VALUE
387 	status_t err;
388 	if (message)
389 		err = BInvoker::Invoke(&clone);
390 	else
391 		err = B_BAD_VALUE;
392 
393 	// TODO: asynchronous messaging
394 	SendNotices(kind, &clone);
395 
396 	return err;
397 }
398 
399 
400 BHandler *
401 BControl::ResolveSpecifier(BMessage *message, int32 index,
402 	BMessage *specifier, int32 what, const char *property)
403 {
404 	BPropertyInfo propInfo(sPropertyList);
405 
406 	if (propInfo.FindMatch(message, 0, specifier, what, property) >= B_OK)
407 		return this;
408 
409 	return BView::ResolveSpecifier(message, index, specifier, what,
410 		property);
411 }
412 
413 
414 status_t
415 BControl::GetSupportedSuites(BMessage *message)
416 {
417 	message->AddString("suites", "suite/vnd.Be-control");
418 
419 	BPropertyInfo propInfo(sPropertyList);
420 	message->AddFlat("messages", &propInfo);
421 
422 	return BView::GetSupportedSuites(message);
423 }
424 
425 
426 void
427 BControl::AllAttached()
428 {
429 	BView::AllAttached();
430 }
431 
432 
433 void
434 BControl::AllDetached()
435 {
436 	BView::AllDetached();
437 }
438 
439 
440 status_t
441 BControl::Perform(perform_code d, void *arg)
442 {
443 	return BView::Perform(d, arg);
444 }
445 
446 
447 bool
448 BControl::IsFocusChanging() const
449 {
450 	return fFocusChanging;
451 }
452 
453 
454 bool
455 BControl::IsTracking() const
456 {
457 	return fTracking;
458 }
459 
460 
461 void
462 BControl::SetTracking(bool state)
463 {
464 	fTracking = state;
465 }
466 
467 
468 void BControl::_ReservedControl1() {}
469 void BControl::_ReservedControl2() {}
470 void BControl::_ReservedControl3() {}
471 void BControl::_ReservedControl4() {}
472 
473 
474 BControl &
475 BControl::operator=(const BControl &)
476 {
477 	return *this;
478 }
479 
480 
481 void
482 BControl::InitData(BMessage *data)
483 {
484 	fLabel = NULL;
485 	SetLabel(B_EMPTY_STRING);
486 	fValue = B_CONTROL_OFF;
487 	fEnabled = true;
488 	fFocusChanging = false;
489 	fTracking = false;
490 	fWantsNav = true;
491 
492 	if (data && data->HasString("_fname"))
493 		SetFont(be_plain_font, B_FONT_FAMILY_AND_STYLE);
494 }
495 
496