xref: /haiku/src/kits/interface/Control.cpp (revision 0b2dbe7d46ee888392907c60131b7f7652314175)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2005, Haiku
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:		Control.cpp
23 //	Author:			Marc Flerackers (mflerackers@androme.be)
24 //	Description:	BControl is the base class for user-event handling objects.
25 //------------------------------------------------------------------------------
26 
27 #include <Control.h>
28 #include <PropertyInfo.h>
29 #include <Window.h>
30 #include <Errors.h>
31 #include <Debug.h>
32 
33 #include <string.h>
34 #include <stdlib.h>
35 
36 
37 static property_info sPropertyList[] = {
38 	{
39 		"Enabled",
40 		{ B_GET_PROPERTY, B_SET_PROPERTY },
41 		{ B_DIRECT_SPECIFIER },
42 		NULL, 0,
43 		{ B_BOOL_TYPE }
44 	},
45 	{
46 		"Label",
47 		{ B_GET_PROPERTY, B_SET_PROPERTY },
48 		{ B_DIRECT_SPECIFIER },
49 		NULL, 0,
50 		{ B_STRING_TYPE }
51 	},
52 	{
53 		"Value",
54 		{ B_GET_PROPERTY, B_SET_PROPERTY },
55 		{ B_DIRECT_SPECIFIER },
56 		NULL, 0,
57 		{ B_INT32_TYPE }
58 	},
59 	{}
60 };
61 
62 
63 BControl::BControl(BRect frame, const char *name, const char *label,
64 	BMessage *message, uint32 resizingMode, uint32 flags)
65 	: BView(frame, name, resizingMode, flags)
66 {
67 	InitData(NULL);
68 
69 	SetLabel(label);
70 	SetMessage(message);
71 }
72 
73 
74 BControl::~BControl()
75 {
76 	free(fLabel);
77 	SetMessage(NULL);
78 }
79 
80 
81 BControl::BControl(BMessage *archive)
82 	: BView(archive)
83 {
84 	InitData(archive);
85 
86 	BMessage message;
87 	if (archive->FindMessage("_msg", &message) == B_OK)
88 		SetMessage(new BMessage(message));
89 
90 	const char *label;
91 	if (archive->FindString("_label", &label) != B_OK)
92 		SetLabel(label);
93 
94 	int32 value;
95 	if (archive->FindInt32("_val", &value) != B_OK)
96 		SetValue(value);
97 
98 	bool toggle;
99 	if (archive->FindBool("_disable", &toggle) != B_OK)
100 		SetEnabled(!toggle);
101 
102 	if (archive->FindBool("be:wants_nav", &toggle) != B_OK)
103 		fWantsNav = toggle;
104 }
105 
106 
107 BArchivable *
108 BControl::Instantiate(BMessage *archive)
109 {
110 	if (validate_instantiation(archive, "BControl"))
111 		return new BControl(archive);
112 
113 	return NULL;
114 }
115 
116 
117 status_t
118 BControl::Archive(BMessage *archive, bool deep) const
119 {
120 	status_t status = BView::Archive(archive, deep);
121 
122 	if (status == B_OK && Message())
123 		status = archive->AddMessage("_msg", Message ());
124 
125 	if (status == B_OK && fLabel)
126 		status = archive->AddString("_label", fLabel);
127 
128 	if (status == B_OK && fValue != B_CONTROL_OFF)
129 		status = archive->AddInt32("_val", fValue);
130 
131 	if (status == B_OK && !fEnabled)
132 		status = archive->AddBool("_disable", true);
133 
134 	return status;
135 }
136 
137 
138 void
139 BControl::WindowActivated(bool active)
140 {
141 	BView::WindowActivated(active);
142 
143 	if (IsFocus())
144 		Invalidate();
145 }
146 
147 
148 void
149 BControl::AttachedToWindow()
150 {
151 	if (Parent()) {
152 		// inherit the color from parent
153 		rgb_color color = Parent()->ViewColor();
154 
155 		SetViewColor(color);
156 		SetLowColor(color);
157 	}
158 
159 	if (!Messenger().IsValid())
160 		SetTarget(Window());
161 
162 	BView::AttachedToWindow();
163 }
164 
165 
166 void
167 BControl::MessageReceived(BMessage *message)
168 {
169 	if (message->what == B_GET_PROPERTY || message->what == B_SET_PROPERTY) {
170 		BMessage reply(B_REPLY);
171 		bool handled = false;
172 
173 		BMessage specifier;
174 		int32 index;
175 		int32 form;
176 		const char *property;
177 		if (message->GetCurrentSpecifier(&index, &specifier, &form, &property) == B_OK) {
178 			if (strcmp(property, "Label") == 0) {
179 				if (message->what == B_GET_PROPERTY) {
180 					reply.AddString("result", fLabel);
181 					handled = true;
182 				} else {
183 					// B_GET_PROPERTY
184 					const char *label;
185 					if (message->FindString("data", &label) == B_OK) {
186 						SetLabel(label);
187 						reply.AddInt32("error", B_OK);
188 						handled = true;
189 					}
190 				}
191 			} else if (strcmp(property, "Value") == 0) {
192 				if (message->what == B_GET_PROPERTY) {
193 					reply.AddInt32("result", fValue);
194 					handled = true;
195 				} else {
196 					// B_GET_PROPERTY
197 					int32 value;
198 					if (message->FindInt32("data", &value) == B_OK) {
199 						SetValue(value);
200 						reply.AddInt32("error", B_OK);
201 						handled = true;
202 					}
203 				}
204 			} else if (strcmp(property, "Enabled") == 0) {
205 				if (message->what == B_GET_PROPERTY) {
206 					reply.AddBool("result", fEnabled);
207 					handled = true;
208 				} else {
209 					// B_GET_PROPERTY
210 					bool enabled;
211 					if (message->FindBool("data", &enabled) == B_OK) {
212 						SetEnabled(enabled);
213 						reply.AddInt32("error", B_OK);
214 						handled = true;
215 					}
216 				}
217 			}
218 		}
219 
220 		if (handled) {
221 			message->SendReply(&reply);
222 			return;
223 		}
224 	}
225 
226 	BView::MessageReceived(message);
227 }
228 
229 
230 void
231 BControl::MakeFocus(bool focused)
232 {
233 	if (focused == IsFocus())
234 		return;
235 
236 	BView::MakeFocus(focused);
237 
238  	if (Window()) {
239 		fFocusChanging = true;
240 		Invalidate(Bounds());
241 		Flush();
242 		fFocusChanging = false;
243 	}
244 }
245 
246 
247 void
248 BControl::KeyDown(const char *bytes, int32 numBytes)
249 {
250 	if (*bytes == B_ENTER || *bytes == B_SPACE) {
251 		if (!fEnabled)
252 			return;
253 
254 		SetValue(Value() ? B_CONTROL_OFF : B_CONTROL_ON);
255 		Invoke();
256 	} else
257 		BView::KeyDown(bytes, numBytes);
258 }
259 
260 
261 void
262 BControl::MouseDown(BPoint point)
263 {
264 	BView::MouseDown(point);
265 }
266 
267 
268 void
269 BControl::MouseUp(BPoint point)
270 {
271 	BView::MouseUp(point);
272 }
273 
274 
275 void
276 BControl::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
277 {
278 	BView::MouseMoved(point, transit, message);
279 }
280 
281 
282 void
283 BControl::DetachedFromWindow()
284 {
285 	BView::DetachedFromWindow();
286 }
287 
288 
289 void
290 BControl::SetLabel(const char *string)
291 {
292 	if (fLabel && string && strcmp(fLabel, string) == 0)
293 		return;
294 
295 	free(fLabel);
296 	fLabel = strdup(string ? string : B_EMPTY_STRING);
297 
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 	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
469 BControl::SetValueNoUpdate(int32 value)
470 {
471 	fValue = value;
472 }
473 
474 
475 void BControl::_ReservedControl1() {}
476 void BControl::_ReservedControl2() {}
477 void BControl::_ReservedControl3() {}
478 void BControl::_ReservedControl4() {}
479 
480 
481 BControl &
482 BControl::operator=(const BControl &)
483 {
484 	return *this;
485 }
486 
487 
488 void
489 BControl::InitData(BMessage *data)
490 {
491 	fLabel = NULL;
492 	SetLabel(B_EMPTY_STRING);
493 	fValue = B_CONTROL_OFF;
494 	fEnabled = true;
495 	fFocusChanging = false;
496 	fTracking = false;
497 	fWantsNav = true;
498 
499 	if (data && data->HasString("_fname"))
500 		SetFont(be_plain_font, B_FONT_FAMILY_AND_STYLE);
501 }
502 
503