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