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 fValue = value; 302 Invalidate(); 303 } 304 305 306 void 307 BControl::SetValueNoUpdate(int32 value) 308 { 309 fValue = value; 310 } 311 312 313 int32 314 BControl::Value() const 315 { 316 return fValue; 317 } 318 319 320 void 321 BControl::SetEnabled(bool enabled) 322 { 323 if (fEnabled == enabled) 324 return; 325 326 fEnabled = enabled; 327 328 if (fEnabled) 329 BView::SetFlags(Flags() | B_NAVIGABLE); 330 else 331 BView::SetFlags(Flags() & ~B_NAVIGABLE); 332 333 if (Window()) { 334 Invalidate(Bounds()); 335 Flush(); 336 } 337 } 338 339 340 bool 341 BControl::IsEnabled() const 342 { 343 return fEnabled; 344 } 345 346 347 void 348 BControl::GetPreferredSize(float *_width, float *_height) 349 { 350 BView::GetPreferredSize(_width, _height); 351 } 352 353 354 void 355 BControl::ResizeToPreferred() 356 { 357 BView::ResizeToPreferred(); 358 } 359 360 361 status_t 362 BControl::Invoke(BMessage *message) 363 { 364 bool notify = false; 365 uint32 kind = InvokeKind(¬ify); 366 367 if (!message && !notify) 368 message = Message(); 369 370 BMessage clone(kind); 371 372 if (!message) { 373 if (!IsWatched()) 374 return B_BAD_VALUE; 375 } else 376 clone = *message; 377 378 clone.AddInt64("when", (int64)system_time()); 379 clone.AddPointer("source", this); 380 clone.AddInt32("be:value", fValue); 381 clone.AddMessenger("be:sender", BMessenger(this)); 382 383 // ToDo: is this correct? If message == NULL (even if IsWatched()), we always return B_BAD_VALUE 384 status_t err; 385 if (message) 386 err = BInvoker::Invoke(&clone); 387 else 388 err = B_BAD_VALUE; 389 390 // TODO: asynchronous messaging 391 SendNotices(kind, &clone); 392 393 return err; 394 } 395 396 397 BHandler * 398 BControl::ResolveSpecifier(BMessage *message, int32 index, 399 BMessage *specifier, int32 what, const char *property) 400 { 401 BPropertyInfo propInfo(sPropertyList); 402 403 if (propInfo.FindMatch(message, 0, specifier, what, property) >= B_OK) 404 return this; 405 406 return BView::ResolveSpecifier(message, index, specifier, what, 407 property); 408 } 409 410 411 status_t 412 BControl::GetSupportedSuites(BMessage *message) 413 { 414 message->AddString("suites", "suite/vnd.Be-control"); 415 416 BPropertyInfo propInfo(sPropertyList); 417 message->AddFlat("messages", &propInfo); 418 419 return BView::GetSupportedSuites(message); 420 } 421 422 423 void 424 BControl::AllAttached() 425 { 426 BView::AllAttached(); 427 } 428 429 430 void 431 BControl::AllDetached() 432 { 433 BView::AllDetached(); 434 } 435 436 437 status_t 438 BControl::Perform(perform_code d, void *arg) 439 { 440 return BView::Perform(d, arg); 441 } 442 443 444 bool 445 BControl::IsFocusChanging() const 446 { 447 return fFocusChanging; 448 } 449 450 451 bool 452 BControl::IsTracking() const 453 { 454 return fTracking; 455 } 456 457 458 void 459 BControl::SetTracking(bool state) 460 { 461 fTracking = state; 462 } 463 464 465 void BControl::_ReservedControl1() {} 466 void BControl::_ReservedControl2() {} 467 void BControl::_ReservedControl3() {} 468 void BControl::_ReservedControl4() {} 469 470 471 BControl & 472 BControl::operator=(const BControl &) 473 { 474 return *this; 475 } 476 477 478 void 479 BControl::InitData(BMessage *data) 480 { 481 fLabel = NULL; 482 SetLabel(B_EMPTY_STRING); 483 fValue = B_CONTROL_OFF; 484 fEnabled = true; 485 fFocusChanging = false; 486 fTracking = false; 487 fWantsNav = true; 488 489 if (data && data->HasString("_fname")) 490 SetFont(be_plain_font, B_FONT_FAMILY_AND_STYLE); 491 } 492 493