xref: /haiku/src/kits/interface/Control.cpp (revision 3cb015b1ee509d69c643506e8ff573808c86dcfc)
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 	fValue = value;
302 	Invalidate();
303 }
304 
305 
306 void
307 BControl::SetValueNoUpdate(int32 value)
308 {
309 	fValue = value;
310 }
311 
312 
313 int32
314 BControl::Value() const
315 {
316 	return fValue;
317 }
318 
319 
320 void
321 BControl::SetEnabled(bool enabled)
322 {
323 	if (fEnabled == enabled)
324 		return;
325 
326 	fEnabled = enabled;
327 
328 	if (fEnabled)
329 		BView::SetFlags(Flags() | B_NAVIGABLE);
330 	else
331 		BView::SetFlags(Flags() & ~B_NAVIGABLE);
332 
333 	if (Window()) {
334 		Invalidate(Bounds());
335 		Flush();
336 	}
337 }
338 
339 
340 bool
341 BControl::IsEnabled() const
342 {
343 	return fEnabled;
344 }
345 
346 
347 void
348 BControl::GetPreferredSize(float *_width, float *_height)
349 {
350 	BView::GetPreferredSize(_width, _height);
351 }
352 
353 
354 void
355 BControl::ResizeToPreferred()
356 {
357 	BView::ResizeToPreferred();
358 }
359 
360 
361 status_t
362 BControl::Invoke(BMessage *message)
363 {
364 	bool notify = false;
365 	uint32 kind = InvokeKind(&notify);
366 
367 	if (!message && !notify)
368 		message = Message();
369 
370 	BMessage clone(kind);
371 
372 	if (!message) {
373 		if (!IsWatched())
374 			return B_BAD_VALUE;
375 	} else
376 		clone = *message;
377 
378 	clone.AddInt64("when", (int64)system_time());
379 	clone.AddPointer("source", this);
380 	clone.AddInt32("be:value", fValue);
381 	clone.AddMessenger("be:sender", BMessenger(this));
382 
383 	// ToDo: is this correct? If message == NULL (even if IsWatched()), we always return B_BAD_VALUE
384 	status_t err;
385 	if (message)
386 		err = BInvoker::Invoke(&clone);
387 	else
388 		err = B_BAD_VALUE;
389 
390 	// TODO: asynchronous messaging
391 	SendNotices(kind, &clone);
392 
393 	return err;
394 }
395 
396 
397 BHandler *
398 BControl::ResolveSpecifier(BMessage *message, int32 index,
399 	BMessage *specifier, int32 what, const char *property)
400 {
401 	BPropertyInfo propInfo(sPropertyList);
402 
403 	if (propInfo.FindMatch(message, 0, specifier, what, property) >= B_OK)
404 		return this;
405 
406 	return BView::ResolveSpecifier(message, index, specifier, what,
407 		property);
408 }
409 
410 
411 status_t
412 BControl::GetSupportedSuites(BMessage *message)
413 {
414 	message->AddString("suites", "suite/vnd.Be-control");
415 
416 	BPropertyInfo propInfo(sPropertyList);
417 	message->AddFlat("messages", &propInfo);
418 
419 	return BView::GetSupportedSuites(message);
420 }
421 
422 
423 void
424 BControl::AllAttached()
425 {
426 	BView::AllAttached();
427 }
428 
429 
430 void
431 BControl::AllDetached()
432 {
433 	BView::AllDetached();
434 }
435 
436 
437 status_t
438 BControl::Perform(perform_code d, void *arg)
439 {
440 	return BView::Perform(d, arg);
441 }
442 
443 
444 bool
445 BControl::IsFocusChanging() const
446 {
447 	return fFocusChanging;
448 }
449 
450 
451 bool
452 BControl::IsTracking() const
453 {
454 	return fTracking;
455 }
456 
457 
458 void
459 BControl::SetTracking(bool state)
460 {
461 	fTracking = state;
462 }
463 
464 
465 void BControl::_ReservedControl1() {}
466 void BControl::_ReservedControl2() {}
467 void BControl::_ReservedControl3() {}
468 void BControl::_ReservedControl4() {}
469 
470 
471 BControl &
472 BControl::operator=(const BControl &)
473 {
474 	return *this;
475 }
476 
477 
478 void
479 BControl::InitData(BMessage *data)
480 {
481 	fLabel = NULL;
482 	SetLabel(B_EMPTY_STRING);
483 	fValue = B_CONTROL_OFF;
484 	fEnabled = true;
485 	fFocusChanging = false;
486 	fTracking = false;
487 	fWantsNav = true;
488 
489 	if (data && data->HasString("_fname"))
490 		SetFont(be_plain_font, B_FONT_FAMILY_AND_STYLE);
491 }
492 
493