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