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