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