1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2001-2002, OpenBeOS 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 // Standard Includes ----------------------------------------------------------- 28 #include <string.h> 29 #include <stdlib.h> 30 31 // System Includes ------------------------------------------------------------- 32 #include <Control.h> 33 #include <PropertyInfo.h> 34 #include <Window.h> 35 #include <Errors.h> 36 37 // Project Includes ------------------------------------------------------------ 38 39 // Local Includes -------------------------------------------------------------- 40 41 // Local Defines --------------------------------------------------------------- 42 43 // Globals --------------------------------------------------------------------- 44 static property_info prop_list[] = 45 { 46 { 47 "Enabled", 48 { B_GET_PROPERTY, 0 }, 49 { B_DIRECT_SPECIFIER, 0 }, 50 "Returns whether or not the BControl is currently enabled.", 0, 51 { B_BOOL_TYPE, 0 } 52 }, 53 { 54 "Enabled", 55 { B_SET_PROPERTY, 0 }, 56 { B_DIRECT_SPECIFIER, 0 }, 57 "Enables or disables the BControl.", 0, 58 { B_BOOL_TYPE, 0 } 59 }, 60 { 61 "Label", 62 { B_GET_PROPERTY, 0 }, 63 { B_DIRECT_SPECIFIER, 0 }, 64 "Returns the BControl's label.", 0, 65 { B_STRING_TYPE, 0 } 66 }, 67 { 68 "Label", 69 { B_SET_PROPERTY, 0 }, 70 { B_DIRECT_SPECIFIER, 0 }, 71 "Sets the label of the BControl.", 0, 72 { B_STRING_TYPE, 0 } 73 }, 74 { 75 "Value", 76 { B_GET_PROPERTY, 0 }, 77 { B_DIRECT_SPECIFIER, 0 }, 78 "Returns the BControl's value.", 0, 79 { B_INT32_TYPE, 0 } 80 }, 81 { 82 "Value", 83 { B_SET_PROPERTY, 0 }, 84 { B_DIRECT_SPECIFIER, 0 }, 85 "Sets the value of the BControl.", 0, 86 { B_INT32_TYPE, 0 }, 87 }, 88 { 0 } 89 }; 90 91 //------------------------------------------------------------------------------ 92 BControl::BControl(BRect frame, const char *name, const char *label, 93 BMessage *message, uint32 resizingMode, uint32 flags) 94 : BView(frame, name, resizingMode, flags) 95 { 96 InitData(NULL); 97 98 SetLabel(label); 99 SetMessage(message); 100 } 101 //------------------------------------------------------------------------------ 102 BControl::~BControl() 103 { 104 if (fLabel) 105 free(fLabel); 106 107 SetMessage(NULL); 108 } 109 //------------------------------------------------------------------------------ 110 BControl::BControl(BMessage *archive) 111 : BView(archive) 112 { 113 InitData(archive); 114 115 BMessage message; 116 117 if (archive->FindMessage("_msg", &message) == B_OK) 118 SetMessage(new BMessage(message)); 119 120 const char *label; 121 122 if (archive->FindString("_label", &label) != B_OK) 123 SetLabel(label); 124 125 int32 value; 126 127 if (archive->FindInt32("_val", &value) != B_OK) 128 SetValue(value); 129 130 bool toggle; 131 132 if (archive->FindBool("_disable", &toggle) != B_OK) 133 SetEnabled(!toggle); 134 135 if (archive->FindBool("be:wants_nav", &toggle) != B_OK) 136 fWantsNav = toggle; 137 } 138 //------------------------------------------------------------------------------ 139 BArchivable *BControl::Instantiate(BMessage *archive) 140 { 141 if (validate_instantiation(archive, "BControl")) 142 return new BControl(archive); 143 else 144 return NULL; 145 } 146 //------------------------------------------------------------------------------ 147 status_t BControl::Archive(BMessage *archive, bool deep) const 148 { 149 status_t err = BView::Archive(archive, deep); 150 151 if (err != B_OK) 152 return err; 153 154 if (Message()) 155 err = archive->AddMessage("_msg", Message ()); 156 157 if (err != B_OK) 158 return err; 159 160 if (fLabel) 161 err = archive->AddString("_label", fLabel); 162 163 if (err != B_OK ) 164 return err; 165 166 if (fValue != B_CONTROL_OFF) 167 err = archive->AddInt32("_val", fValue); 168 169 if (err != B_OK) 170 return err; 171 172 if (!fEnabled) 173 err = archive->AddBool("_disable", true); 174 175 return err; 176 } 177 //------------------------------------------------------------------------------ 178 void BControl::WindowActivated(bool active) 179 { 180 BView::WindowActivated(active); 181 182 if (IsFocus()) 183 Draw(Bounds()); 184 } 185 //------------------------------------------------------------------------------ 186 void BControl::AttachedToWindow() 187 { 188 if (Parent()) 189 { 190 rgb_color color = Parent()->ViewColor(); 191 192 SetViewColor(color); 193 SetLowColor(color); 194 } 195 196 if (!Messenger().IsValid()) 197 BInvoker::SetTarget(BMessenger(Window(), NULL)); 198 199 BView::AttachedToWindow(); 200 } 201 //------------------------------------------------------------------------------ 202 void BControl::MessageReceived(BMessage *message) 203 { 204 bool handled = false; 205 BMessage reply(B_REPLY); 206 207 if (message->what == B_GET_PROPERTY || message->what == B_SET_PROPERTY) 208 { 209 BPropertyInfo propInfo(prop_list); 210 BMessage specifier; 211 int32 index; 212 int32 form; 213 const char *property; 214 215 if (message->GetCurrentSpecifier(&index, &specifier, &form, &property) == B_OK) 216 { 217 if (strcmp(property, "Label") == 0) 218 { 219 if (message->what == B_GET_PROPERTY) 220 { 221 reply.AddString("result", fLabel); 222 handled = true; 223 } 224 else 225 { 226 const char *label; 227 228 if (message->FindString("data", &label) == B_OK) 229 { 230 SetLabel(label); 231 reply.AddInt32("error", B_OK); 232 handled = true; 233 } 234 } 235 } 236 else if (strcmp(property, "Value") == 0) 237 { 238 if (message->what == B_GET_PROPERTY) 239 { 240 reply.AddInt32("result", fValue); 241 handled = true; 242 } 243 else 244 { 245 int32 value; 246 247 if (message->FindInt32("data", &value) == B_OK) 248 { 249 SetValue(value); 250 reply.AddInt32("error", B_OK); 251 handled = true; 252 } 253 } 254 } 255 else if (strcmp(property, "Enabled") == 0) 256 { 257 if (message->what == B_GET_PROPERTY) 258 { 259 reply.AddBool("result", fEnabled); 260 handled = true; 261 } 262 else 263 { 264 bool enabled; 265 266 if (message->FindBool("data", &enabled) == B_OK) 267 { 268 SetEnabled(enabled); 269 reply.AddInt32("error", B_OK); 270 handled = true; 271 } 272 } 273 } 274 } 275 } 276 277 if (handled) 278 message->SendReply(&reply); 279 else 280 BView::MessageReceived(message); 281 } 282 //------------------------------------------------------------------------------ 283 void BControl::MakeFocus(bool focused) 284 { 285 if (focused == IsFocus()) 286 return; 287 288 BView::MakeFocus(focused); 289 290 if(Window()) 291 { 292 fFocusChanging = true; 293 Draw(Bounds()); 294 Flush(); 295 fFocusChanging = false; 296 } 297 } 298 //------------------------------------------------------------------------------ 299 void BControl::KeyDown(const char *bytes, int32 numBytes) 300 { 301 if (*bytes == B_ENTER || *bytes == B_SPACE) 302 { 303 if (!fEnabled) 304 return; 305 306 if (Value()) 307 SetValue(B_CONTROL_OFF); 308 else 309 SetValue(B_CONTROL_ON); 310 311 Invoke(); 312 } 313 else 314 BView::KeyDown(bytes, numBytes); 315 } 316 //------------------------------------------------------------------------------ 317 void BControl::MouseDown(BPoint point) 318 { 319 BView::MouseDown(point); 320 } 321 //------------------------------------------------------------------------------ 322 void BControl::MouseUp(BPoint point) 323 { 324 BView::MouseUp(point); 325 } 326 //------------------------------------------------------------------------------ 327 void BControl::MouseMoved(BPoint point, uint32 transit, const BMessage *message) 328 { 329 BView::MouseMoved(point, transit, message); 330 } 331 //------------------------------------------------------------------------------ 332 void BControl::DetachedFromWindow() 333 { 334 BView::DetachedFromWindow(); 335 } 336 //------------------------------------------------------------------------------ 337 void BControl::SetLabel(const char *string) 338 { 339 if (fLabel && string && strcmp(fLabel, string) == 0) 340 return; 341 342 if (fLabel) 343 free(fLabel); 344 345 if (string) 346 fLabel = strdup(string); 347 else 348 fLabel = NULL; 349 350 Invalidate(); 351 } 352 //------------------------------------------------------------------------------ 353 const char *BControl::Label() const 354 { 355 return fLabel; 356 } 357 //------------------------------------------------------------------------------ 358 void BControl::SetValue(int32 value) 359 { 360 if (fValue == value) 361 return; 362 363 fValue = value; 364 365 if (Window()) 366 { 367 Draw(Bounds()); 368 Flush(); 369 } 370 } 371 //------------------------------------------------------------------------------ 372 int32 BControl::Value() const 373 { 374 return fValue; 375 } 376 //------------------------------------------------------------------------------ 377 void BControl::SetEnabled(bool enabled) 378 { 379 if (fEnabled == enabled) 380 return; 381 382 fEnabled = enabled; 383 384 if (fEnabled) 385 BView::SetFlags(Flags() | B_NAVIGABLE); 386 else 387 BView::SetFlags(Flags() & ~B_NAVIGABLE); 388 389 if (Window()) 390 { 391 Draw(Bounds()); 392 Flush(); 393 } 394 } 395 //------------------------------------------------------------------------------ 396 bool BControl::IsEnabled() const 397 { 398 return fEnabled; 399 } 400 //------------------------------------------------------------------------------ 401 void BControl::GetPreferredSize(float *width, float *height) 402 { 403 BView::GetPreferredSize(width, height); 404 } 405 //------------------------------------------------------------------------------ 406 void BControl::ResizeToPreferred() 407 { 408 BView::ResizeToPreferred(); 409 } 410 //------------------------------------------------------------------------------ 411 status_t BControl::Invoke(BMessage *message) 412 { 413 bool notify = false; 414 uint32 kind = InvokeKind(¬ify); 415 416 BMessage clone(kind); 417 status_t err = B_BAD_VALUE; 418 419 if (!message && !notify) 420 message = Message(); 421 422 if (!message) 423 { 424 if (!IsWatched()) 425 return err; 426 } 427 else 428 clone = *message; 429 430 clone.AddInt64("when", (int64)system_time()); 431 clone.AddPointer("source", this); 432 clone.AddInt32("be:value", fValue); 433 clone.AddMessenger("be:sender", BMessenger(this)); 434 435 if (message) 436 err = BInvoker::Invoke(&clone); 437 438 // TODO: assynchronous messaging 439 // SendNotices(kind, &clone); 440 441 return err; 442 } 443 //------------------------------------------------------------------------------ 444 BHandler *BControl::ResolveSpecifier(BMessage *message, int32 index, 445 BMessage *specifier, int32 what, 446 const char *property) 447 { 448 BPropertyInfo propInfo(prop_list); 449 450 if (propInfo.FindMatch(message, 0, specifier, what, property) < B_OK) 451 return BView::ResolveSpecifier(message, index, specifier, what, 452 property); 453 else 454 return this; 455 } 456 //------------------------------------------------------------------------------ 457 status_t BControl::GetSupportedSuites(BMessage *message) 458 { 459 message->AddString("suites", "suite/vnd.Be-control"); 460 461 BPropertyInfo prop_info(prop_list); 462 message->AddFlat("messages", &prop_info); 463 464 return BView::GetSupportedSuites(message); 465 } 466 //------------------------------------------------------------------------------ 467 void BControl::AllAttached() 468 { 469 BView::AllAttached(); 470 } 471 //------------------------------------------------------------------------------ 472 void BControl::AllDetached() 473 { 474 BView::AllDetached(); 475 } 476 //------------------------------------------------------------------------------ 477 status_t BControl::Perform(perform_code d, void *arg) 478 { 479 return BView::Perform(d, arg); 480 } 481 //------------------------------------------------------------------------------ 482 bool BControl::IsFocusChanging() const 483 { 484 return fFocusChanging; 485 } 486 //------------------------------------------------------------------------------ 487 bool BControl::IsTracking() const 488 { 489 return fTracking; 490 } 491 //------------------------------------------------------------------------------ 492 void BControl::SetTracking(bool state) 493 { 494 fTracking = state; 495 } 496 //------------------------------------------------------------------------------ 497 void BControl::SetValueNoUpdate(int32 value) 498 { 499 fValue = value; 500 } 501 502 //------------------------------------------------------------------------------ 503 void BControl::_ReservedControl1() {} 504 void BControl::_ReservedControl2() {} 505 void BControl::_ReservedControl3() {} 506 void BControl::_ReservedControl4() {} 507 //------------------------------------------------------------------------------ 508 BControl &BControl::operator=(const BControl &) 509 { 510 return *this; 511 } 512 //------------------------------------------------------------------------------ 513 void BControl::InitData(BMessage *data) 514 { 515 fLabel = NULL; 516 fValue = B_CONTROL_OFF; 517 fEnabled = true; 518 fFocusChanging = false; 519 fTracking = false; 520 fWantsNav = true; 521 522 if (data && data->HasString("_fname")) 523 SetFont(be_plain_font, B_FONT_FAMILY_AND_STYLE); 524 } 525 //------------------------------------------------------------------------------ 526 527 /* 528 * $Log $ 529 * 530 * $Id $ 531 * 532 */ 533