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() 58 { 59 free(fLabel); 60 SetMessage(NULL); 61 } 62 63 64 BControl::BControl(BMessage *archive) 65 : BView(archive) 66 { 67 InitData(archive); 68 69 BMessage message; 70 if (archive->FindMessage("_msg", &message) == B_OK) 71 SetMessage(new BMessage(message)); 72 73 const char *label; 74 if (archive->FindString("_label", &label) != B_OK) 75 SetLabel(label); 76 77 int32 value; 78 if (archive->FindInt32("_val", &value) != B_OK) 79 SetValue(value); 80 81 bool toggle; 82 if (archive->FindBool("_disable", &toggle) != B_OK) 83 SetEnabled(!toggle); 84 85 if (archive->FindBool("be:wants_nav", &toggle) != B_OK) 86 fWantsNav = toggle; 87 } 88 89 90 BArchivable * 91 BControl::Instantiate(BMessage *archive) 92 { 93 if (validate_instantiation(archive, "BControl")) 94 return new BControl(archive); 95 96 return NULL; 97 } 98 99 100 status_t 101 BControl::Archive(BMessage *archive, bool deep) const 102 { 103 status_t status = BView::Archive(archive, deep); 104 105 if (status == B_OK && Message()) 106 status = archive->AddMessage("_msg", Message ()); 107 108 if (status == B_OK && fLabel) 109 status = archive->AddString("_label", fLabel); 110 111 if (status == B_OK && fValue != B_CONTROL_OFF) 112 status = archive->AddInt32("_val", fValue); 113 114 if (status == B_OK && !fEnabled) 115 status = archive->AddBool("_disable", true); 116 117 return status; 118 } 119 120 121 void 122 BControl::WindowActivated(bool active) 123 { 124 BView::WindowActivated(active); 125 126 if (IsFocus()) 127 Invalidate(); 128 } 129 130 131 void 132 BControl::AttachedToWindow() 133 { 134 if (Parent()) { 135 // inherit the color from parent 136 rgb_color color = Parent()->ViewColor(); 137 138 SetViewColor(color); 139 SetLowColor(color); 140 } 141 142 if (!Messenger().IsValid()) 143 SetTarget(Window()); 144 145 BView::AttachedToWindow(); 146 } 147 148 149 void 150 BControl::MessageReceived(BMessage *message) 151 { 152 if (message->what == B_GET_PROPERTY || message->what == B_SET_PROPERTY) { 153 BMessage reply(B_REPLY); 154 bool handled = false; 155 156 BMessage specifier; 157 int32 index; 158 int32 form; 159 const char *property; 160 if (message->GetCurrentSpecifier(&index, &specifier, &form, &property) == B_OK) { 161 if (strcmp(property, "Label") == 0) { 162 if (message->what == B_GET_PROPERTY) { 163 reply.AddString("result", fLabel); 164 handled = true; 165 } else { 166 // B_GET_PROPERTY 167 const char *label; 168 if (message->FindString("data", &label) == B_OK) { 169 SetLabel(label); 170 reply.AddInt32("error", B_OK); 171 handled = true; 172 } 173 } 174 } else if (strcmp(property, "Value") == 0) { 175 if (message->what == B_GET_PROPERTY) { 176 reply.AddInt32("result", fValue); 177 handled = true; 178 } else { 179 // B_GET_PROPERTY 180 int32 value; 181 if (message->FindInt32("data", &value) == B_OK) { 182 SetValue(value); 183 reply.AddInt32("error", B_OK); 184 handled = true; 185 } 186 } 187 } else if (strcmp(property, "Enabled") == 0) { 188 if (message->what == B_GET_PROPERTY) { 189 reply.AddBool("result", fEnabled); 190 handled = true; 191 } else { 192 // B_GET_PROPERTY 193 bool enabled; 194 if (message->FindBool("data", &enabled) == B_OK) { 195 SetEnabled(enabled); 196 reply.AddInt32("error", B_OK); 197 handled = true; 198 } 199 } 200 } 201 } 202 203 if (handled) { 204 message->SendReply(&reply); 205 return; 206 } 207 } 208 209 BView::MessageReceived(message); 210 } 211 212 213 void 214 BControl::MakeFocus(bool focused) 215 { 216 if (focused == IsFocus()) 217 return; 218 219 BView::MakeFocus(focused); 220 221 if (Window()) { 222 fFocusChanging = true; 223 Invalidate(Bounds()); 224 Flush(); 225 fFocusChanging = false; 226 } 227 } 228 229 230 void 231 BControl::KeyDown(const char *bytes, int32 numBytes) 232 { 233 if (*bytes == B_ENTER || *bytes == B_SPACE) { 234 if (!fEnabled) 235 return; 236 237 SetValue(Value() ? B_CONTROL_OFF : B_CONTROL_ON); 238 Invoke(); 239 } else 240 BView::KeyDown(bytes, numBytes); 241 } 242 243 244 void 245 BControl::MouseDown(BPoint point) 246 { 247 BView::MouseDown(point); 248 } 249 250 251 void 252 BControl::MouseUp(BPoint point) 253 { 254 BView::MouseUp(point); 255 } 256 257 258 void 259 BControl::MouseMoved(BPoint point, uint32 transit, const BMessage *message) 260 { 261 BView::MouseMoved(point, transit, message); 262 } 263 264 265 void 266 BControl::DetachedFromWindow() 267 { 268 BView::DetachedFromWindow(); 269 } 270 271 272 void 273 BControl::SetLabel(const char *label) 274 { 275 if (label != NULL && !label[0]) 276 label = NULL; 277 278 // Has the label been changed? 279 if ((fLabel && label && !strcmp(fLabel, label)) 280 || ((fLabel == NULL || !fLabel[0]) && label == NULL)) 281 return; 282 283 free(fLabel); 284 fLabel = label ? strdup(label) : NULL; 285 286 InvalidateLayout(); 287 Invalidate(); 288 } 289 290 291 const char * 292 BControl::Label() const 293 { 294 return fLabel; 295 } 296 297 298 void 299 BControl::SetValue(int32 value) 300 { 301 if (value == fValue) 302 return; 303 304 fValue = value; 305 Invalidate(); 306 } 307 308 309 void 310 BControl::SetValueNoUpdate(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(¬ify); 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 BControl::_ReservedControl1() {} 469 void BControl::_ReservedControl2() {} 470 void BControl::_ReservedControl3() {} 471 void BControl::_ReservedControl4() {} 472 473 474 BControl & 475 BControl::operator=(const BControl &) 476 { 477 return *this; 478 } 479 480 481 void 482 BControl::InitData(BMessage *data) 483 { 484 fLabel = NULL; 485 SetLabel(B_EMPTY_STRING); 486 fValue = B_CONTROL_OFF; 487 fEnabled = true; 488 fFocusChanging = false; 489 fTracking = false; 490 fWantsNav = true; 491 492 if (data && data->HasString("_fname")) 493 SetFont(be_plain_font, B_FONT_FAMILY_AND_STYLE); 494 } 495 496