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(¬ify); 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