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: Menu.cpp 23 // Author: Marc Flerackers (mflerackers@androme.be) 24 // Description: BMenu display a menu of selectable items. 25 //------------------------------------------------------------------------------ 26 27 // Standard Includes ----------------------------------------------------------- 28 29 // System Includes ------------------------------------------------------------- 30 #include "Menu.h" 31 #include "MenuItem.h" 32 #include "Window.h" 33 #include <PropertyInfo.h> 34 #include <Errors.h> 35 #include <File.h> 36 #include <FindDirectory.h> 37 #include <Path.h> 38 39 // Project Includes ------------------------------------------------------------ 40 41 // Local Includes -------------------------------------------------------------- 42 43 // Local Defines --------------------------------------------------------------- 44 45 // Globals --------------------------------------------------------------------- 46 47 static property_info prop_list[] = 48 { 49 { "Enabled", { B_GET_PROPERTY, 0 }, 50 { B_DIRECT_SPECIFIER, 0 }, "Returns true if menu or menu item is enabled; false " 51 "otherwise." }, 52 { "Enabled", { B_SET_PROPERTY, 0 }, 53 { B_DIRECT_SPECIFIER, 0 }, "Enables or disables menu or menu item." }, 54 { "Label", { B_GET_PROPERTY, 0 }, 55 { B_DIRECT_SPECIFIER, 0 }, "Returns the string label of the menu or menu item." }, 56 { "Label", { B_SET_PROPERTY, 0 }, 57 { B_DIRECT_SPECIFIER, 0 }, "Sets the string label of the menu or menu item." }, 58 { "Mark", { B_GET_PROPERTY, 0 }, 59 { B_DIRECT_SPECIFIER, 0 }, "Returns true if the menu item or the menu's superitem " 60 "is marked; false otherwise." }, 61 { "Mark", { B_SET_PROPERTY, 0 }, 62 { B_DIRECT_SPECIFIER, 0 }, "Marks or unmarks the menu item or the menu's superitem." }, 63 { "Menu", { B_CREATE_PROPERTY, 0 }, 64 { B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 }, 65 "Adds a new menu item at the specified index with the text label found in \"data\" " 66 "and the int32 command found in \"what\" (used as the what field in the CMessage " 67 "sent by the item)." }, 68 { "Menu", { B_DELETE_PROPERTY, 0 }, 69 { B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 }, 70 "Removes the selected menu or menus." }, 71 { "Menu", { B_GET_PROPERTY, B_SET_PROPERTY, 0 }, 72 { B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 }, 73 "Directs scripting message to the specified menu, first popping the current " 74 "specifier off the stack." }, 75 { "MenuItem", { B_COUNT_PROPERTIES, 0 }, 76 { B_DIRECT_SPECIFIER, 0 }, "Counts the number of menu items in the specified menu." }, 77 { "MenuItem", { B_CREATE_PROPERTY, 0 }, 78 { B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 }, 79 "Adds a new menu item at the specified index with the text label found in \"data\" " 80 "and the int32 command found in \"what\" (used as the what field in the CMessage " 81 "sent by the item)." }, 82 { "MenuItem", { B_DELETE_PROPERTY, 0 }, 83 { B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 }, 84 "Removes the specified menu item from its parent menu." }, 85 { "MenuItem", { B_EXECUTE_PROPERTY, 0 }, 86 { B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 }, 87 "Invokes the specified menu item." }, 88 { "MenuItem", { B_GET_PROPERTY, B_SET_PROPERTY, 0 }, 89 { B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 }, 90 "Directs scripting message to the specified menu, first popping the current " 91 "specifier off the stack." }, 92 0 93 }; 94 95 //------------------------------------------------------------------------------ 96 class BMenuWindow : public BWindow 97 { 98 public: 99 BMenuWindow(BRect frame, BMenu *menu) : 100 BWindow(frame, "Menu", B_NO_BORDER_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, 101 B_NOT_ZOOMABLE) 102 { 103 fMenu = menu; 104 AddChild(fMenu); 105 ResizeTo(fMenu->Bounds().Width() + 1, fMenu->Bounds().Height() + 1); 106 fMenu->MakeFocus(true); 107 } 108 109 virtual ~BMenuWindow() {} 110 111 virtual void WindowActivated(bool active) 112 { 113 if (!active) 114 { 115 RemoveChild(fMenu); 116 117 if (Lock()) 118 Quit(); 119 } 120 } 121 122 private: 123 BMenu *fMenu; 124 }; 125 126 //------------------------------------------------------------------------------ 127 BMenu::BMenu(const char *name, menu_layout layout) 128 : BView(BRect(), name, B_FOLLOW_LEFT | B_FOLLOW_TOP, 129 B_WILL_DRAW | B_NAVIGABLE), 130 fChosenItem(NULL), 131 fPad(14.0f, 2.0f, 20.0f, 0.0f), 132 fSelected(NULL), 133 fCachedMenuWindow(NULL), 134 fSuper(NULL), 135 fSuperitem(NULL), 136 fAscent(-1.0f), 137 fDescent(-1.0f), 138 fFontHeight(-1.0f), 139 fState(0), 140 fLayout(layout), 141 fExtraRect(NULL), 142 fMaxContentWidth(0.0f), 143 fInitMatrixSize(NULL), 144 fExtraMenuData(NULL), 145 fTrigger(0), 146 fResizeToFit(true), 147 fUseCachedMenuLayout(true), 148 fEnabled(true), 149 fDynamicName(false), 150 fRadioMode(false), 151 fTrackNewBounds(false), 152 fStickyMode(false), 153 fIgnoreHidden(true), 154 fTriggerEnabled(true), 155 fRedrawAfterSticky(true), 156 fAttachAborted(false) 157 { 158 SetViewColor(ui_color(B_MENU_BACKGROUND_COLOR)); 159 SetFontSize(10); 160 } 161 //------------------------------------------------------------------------------ 162 BMenu::BMenu(const char *name, float width, float height) 163 : BView(BRect(0.0f, width, 0.0f, height), name, 164 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE), 165 fChosenItem(NULL), 166 fSelected(NULL), 167 fCachedMenuWindow(NULL), 168 fSuper(NULL), 169 fSuperitem(NULL), 170 fAscent(-1.0f), 171 fDescent(-1.0f), 172 fFontHeight(-1.0f), 173 fState(0), 174 fLayout(B_ITEMS_IN_MATRIX), 175 fExtraRect(NULL), 176 fMaxContentWidth(0.0f), 177 fInitMatrixSize(NULL), 178 fExtraMenuData(NULL), 179 fTrigger(0), 180 fResizeToFit(true), 181 fUseCachedMenuLayout(true), 182 fEnabled(true), 183 fDynamicName(false), 184 fRadioMode(false), 185 fTrackNewBounds(false), 186 fStickyMode(false), 187 fIgnoreHidden(true), 188 fTriggerEnabled(true), 189 fRedrawAfterSticky(true), 190 fAttachAborted(false) 191 { 192 SetViewColor(ui_color(B_MENU_BACKGROUND_COLOR)); 193 SetFontSize(10); 194 } 195 //------------------------------------------------------------------------------ 196 BMenu::~BMenu() 197 { 198 for (int i = 0; i < CountItems(); i++) 199 delete ItemAt(i); 200 } 201 //------------------------------------------------------------------------------ 202 BMenu::BMenu(BMessage *archive) 203 : BView(archive) 204 { 205 SetViewColor(ui_color(B_MENU_BACKGROUND_COLOR)); 206 } 207 //------------------------------------------------------------------------------ 208 BArchivable *BMenu::Instantiate(BMessage *data) 209 { 210 if (validate_instantiation(data, "BMenu")) 211 return new BMenu(data); 212 else 213 return NULL; 214 } 215 //------------------------------------------------------------------------------ 216 status_t BMenu::Archive(BMessage *data, bool deep) const 217 { 218 status_t err = BView::Archive(data, deep); 219 220 if (err != B_OK) 221 return err; 222 223 if (Layout() != B_ITEMS_IN_ROW) 224 { 225 err = data->AddInt32("_layout", Layout()); 226 227 if (err != B_OK) 228 return err; 229 } 230 231 err = data->AddBool("_rsize_to_fit", fResizeToFit); 232 233 if (err != B_OK) 234 return err; 235 236 err = data->AddBool("_disable", !IsEnabled()); 237 238 if (err != B_OK) 239 return err; 240 241 err = data->AddBool("_radio", IsRadioMode()); 242 243 if (err != B_OK) 244 return err; 245 246 err = data->AddBool("_trig_disabled", AreTriggersEnabled()); 247 248 if (err != B_OK) 249 return err; 250 251 err = data->AddBool("_dyn_label", fDynamicName); 252 253 if (err != B_OK) 254 return err; 255 256 err = data->AddFloat("_maxwidth", fDynamicName); 257 258 if (err != B_OK) 259 return err; 260 261 if (deep) 262 { 263 // TODO store items and rects 264 } 265 266 return err; 267 } 268 //------------------------------------------------------------------------------ 269 void BMenu::AttachedToWindow() 270 { 271 BView::AttachedToWindow(); 272 273 LayoutItems(0); 274 } 275 //------------------------------------------------------------------------------ 276 void BMenu::DetachedFromWindow() 277 { 278 } 279 //------------------------------------------------------------------------------ 280 bool BMenu::AddItem(BMenuItem *item) 281 { 282 return AddItem(item, CountItems()); 283 } 284 //------------------------------------------------------------------------------ 285 bool BMenu::AddItem(BMenuItem *item, int32 index) 286 { 287 item->fSuper = this; 288 289 bool err = fItems.AddItem(item, index); 290 291 if (!err) 292 return err; 293 294 // Make sure we update the layout in case we are already attached. 295 if (Window() && fResizeToFit) 296 LayoutItems(index); 297 298 // Find the root menu window, so we can install this item. 299 BMenu *root = this; 300 while (root->Supermenu()) 301 root = root->Supermenu(); 302 303 if (root->Window()) 304 Install(root->Window()); 305 306 return err; 307 } 308 //------------------------------------------------------------------------------ 309 bool BMenu::AddItem(BMenuItem *item, BRect frame) 310 { 311 item->fBounds = frame; 312 313 return AddItem(item, CountItems()); 314 } 315 //------------------------------------------------------------------------------ 316 bool BMenu::AddItem(BMenu *submenu) 317 { 318 BMenuItem *item = new BMenuItem(submenu); 319 submenu->fSuper = this; 320 321 return AddItem(item); 322 } 323 //------------------------------------------------------------------------------ 324 bool BMenu::AddItem(BMenu *submenu, int32 index) 325 { 326 BMenuItem *item = new BMenuItem(submenu); 327 submenu->fSuper = this; 328 329 return AddItem(item, index); 330 } 331 //------------------------------------------------------------------------------ 332 bool BMenu::AddItem(BMenu *submenu, BRect frame) 333 { 334 BMenuItem *item = new BMenuItem(submenu); 335 submenu->fSuper = this; 336 item->fBounds = frame; 337 338 return AddItem(item); 339 } 340 //------------------------------------------------------------------------------ 341 bool BMenu::AddList(BList *list, int32 index) 342 { 343 return false; 344 } 345 //------------------------------------------------------------------------------ 346 bool BMenu::AddSeparatorItem() 347 { 348 BMenuItem *item = new BSeparatorItem(); 349 item->fSuper = this; 350 351 return fItems.AddItem(item); 352 } 353 //------------------------------------------------------------------------------ 354 bool BMenu::RemoveItem(BMenuItem *item) 355 { 356 return fItems.RemoveItem(item); 357 } 358 //------------------------------------------------------------------------------ 359 BMenuItem *BMenu::RemoveItem(int32 index) 360 { 361 return (BMenuItem*)fItems.RemoveItem ( index ); 362 } 363 //------------------------------------------------------------------------------ 364 bool BMenu::RemoveItems(int32 index, int32 count, bool del) 365 { 366 return false; 367 } 368 //------------------------------------------------------------------------------ 369 bool BMenu::RemoveItem(BMenu *submenu) 370 { 371 for (int i =0; i < fItems.CountItems(); i++) 372 if (((BMenuItem*)fItems.ItemAt(i))->Submenu() == submenu) 373 return (BMenuItem*)fItems.RemoveItem(fItems.ItemAt(i)); 374 375 return false; 376 } 377 //------------------------------------------------------------------------------ 378 int32 BMenu::CountItems() const 379 { 380 return fItems.CountItems(); 381 } 382 //------------------------------------------------------------------------------ 383 BMenuItem *BMenu::ItemAt(int32 index) const 384 { 385 return (BMenuItem*)fItems.ItemAt(index); 386 } 387 //------------------------------------------------------------------------------ 388 BMenu *BMenu::SubmenuAt(int32 index) const 389 { 390 return ((BMenuItem*)fItems.ItemAt(index))->Submenu(); 391 } 392 //------------------------------------------------------------------------------ 393 int32 BMenu::IndexOf(BMenuItem *item) const 394 { 395 return fItems.IndexOf(item); 396 } 397 //------------------------------------------------------------------------------ 398 int32 BMenu::IndexOf(BMenu *submenu) const 399 { 400 for (int32 i =0; i < fItems.CountItems(); i++) 401 if (((BMenuItem*)fItems.ItemAt(i))->Submenu() == submenu) 402 return i; 403 404 return -1; 405 } 406 //------------------------------------------------------------------------------ 407 BMenuItem *BMenu::FindItem(const char *label) const 408 { 409 BMenuItem *item; 410 411 for (int32 i =0; i < CountItems(); i++) 412 { 413 item = ItemAt(i); 414 415 if (item->Label() && strcmp(item->Label(), label) == 0) 416 return (item); 417 418 if (item->Submenu()) 419 { 420 item = item->Submenu()->FindItem(label); 421 if (item) 422 return item; 423 } 424 } 425 426 return NULL; 427 } 428 //------------------------------------------------------------------------------ 429 BMenuItem *BMenu::FindItem(uint32 command) const 430 { 431 return NULL; 432 } 433 //------------------------------------------------------------------------------ 434 status_t BMenu::SetTargetForItems(BHandler *handler) 435 { 436 for (int32 i = 0; i < fItems.CountItems(); i++) 437 if (((BMenuItem*)fItems.ItemAt(i))->SetTarget(handler) != B_OK) 438 return B_ERROR; 439 440 return B_OK; 441 } 442 //------------------------------------------------------------------------------ 443 status_t BMenu::SetTargetForItems(BMessenger messenger) 444 { 445 for (int32 i = 0; i < fItems.CountItems (); i++) 446 if (((BMenuItem*)fItems.ItemAt(i))->SetTarget(messenger) != B_OK) 447 return B_ERROR; 448 449 return B_OK; 450 } 451 //------------------------------------------------------------------------------ 452 void BMenu::SetEnabled(bool enabled) 453 { 454 fEnabled = enabled; 455 456 for (int32 i = 0; i < CountItems(); i++) 457 ItemAt(i)->SetEnabled(enabled); 458 } 459 //------------------------------------------------------------------------------ 460 void BMenu::SetRadioMode(bool flag) 461 { 462 fRadioMode = flag; 463 } 464 //------------------------------------------------------------------------------ 465 void BMenu::SetTriggersEnabled(bool flag) 466 { 467 fTriggerEnabled = flag; 468 } 469 //------------------------------------------------------------------------------ 470 void BMenu::SetMaxContentWidth(float width) 471 { 472 fMaxContentWidth = width; 473 } 474 //------------------------------------------------------------------------------ 475 void BMenu::SetLabelFromMarked(bool flag) 476 { 477 } 478 //------------------------------------------------------------------------------ 479 bool BMenu::IsLabelFromMarked() 480 { 481 return false; 482 } 483 //------------------------------------------------------------------------------ 484 bool BMenu::IsEnabled() const 485 { 486 return fEnabled; 487 } 488 //------------------------------------------------------------------------------ 489 bool BMenu::IsRadioMode() const 490 { 491 return fRadioMode; 492 } 493 //------------------------------------------------------------------------------ 494 bool BMenu::AreTriggersEnabled() const 495 { 496 return fTriggerEnabled; 497 } 498 //------------------------------------------------------------------------------ 499 bool BMenu::IsRedrawAfterSticky() const 500 { 501 return fRedrawAfterSticky; 502 } 503 //------------------------------------------------------------------------------ 504 float BMenu::MaxContentWidth() const 505 { 506 return fMaxContentWidth; 507 } 508 //------------------------------------------------------------------------------ 509 BMenuItem *BMenu::FindMarked() 510 { 511 for (int i =0; i < fItems.CountItems(); i++) 512 if (((BMenuItem*)fItems.ItemAt(i))->IsMarked()) 513 return (BMenuItem*)fItems.ItemAt(i); 514 515 return NULL; 516 } 517 //------------------------------------------------------------------------------ 518 BMenu *BMenu::Supermenu() const 519 { 520 return fSuper; 521 } 522 //------------------------------------------------------------------------------ 523 BMenuItem *BMenu::Superitem() const 524 { 525 return fSuperitem; 526 } 527 //------------------------------------------------------------------------------ 528 void BMenu::MessageReceived(BMessage *msg) 529 { 530 BView::MessageReceived(msg); 531 } 532 //------------------------------------------------------------------------------ 533 void BMenu::KeyDown(const char *bytes, int32 numBytes) 534 { 535 switch (bytes[0]) 536 { 537 case B_UP_ARROW: 538 { 539 if (fSelected) 540 { 541 fSelected->fSelected = false; 542 543 if ( fSelected == fItems.FirstItem()) 544 fSelected = (BMenuItem*)fItems.LastItem(); 545 else 546 fSelected = ItemAt(IndexOf(fSelected) - 1); 547 } 548 else 549 fSelected = (BMenuItem*)fItems.LastItem(); 550 551 fSelected->fSelected = true; 552 553 break; 554 } 555 case B_DOWN_ARROW: 556 { 557 if (fSelected) 558 { 559 fSelected->fSelected = false; 560 561 if (fSelected == fItems.LastItem()) 562 fSelected = (BMenuItem*)fItems.FirstItem(); 563 else 564 fSelected = ItemAt(IndexOf(fSelected) + 1); 565 } 566 else 567 fSelected = (BMenuItem*)fItems.FirstItem(); 568 569 fSelected->fSelected = true; 570 571 break; 572 } 573 case B_HOME: 574 { 575 if (fSelected) 576 fSelected->fSelected = false; 577 578 fSelected = (BMenuItem*)fItems.FirstItem(); 579 fSelected->fSelected = true; 580 581 break; 582 } 583 case B_END: 584 { 585 if (fSelected) 586 fSelected->fSelected = false; 587 588 fSelected = (BMenuItem*)fItems.LastItem(); 589 fSelected->fSelected = true; 590 591 break; 592 } 593 case B_ENTER: 594 case B_SPACE: 595 { 596 if (fSelected) 597 InvokeItem(fSelected); 598 599 break; 600 } 601 default: 602 BView::KeyDown(bytes, numBytes); 603 } 604 } 605 //------------------------------------------------------------------------------ 606 void BMenu::Draw(BRect updateRect) 607 { 608 BRect bounds(Bounds()); 609 610 SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_4_TINT)); 611 StrokeRect(bounds); 612 SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_2_TINT)); 613 StrokeLine(BPoint(bounds.left + 2, bounds.bottom - 1), 614 BPoint(bounds.right - 1, bounds.bottom - 1)); 615 StrokeLine(BPoint(bounds.right - 1, bounds.top + 1)); 616 SetHighColor(tint_color ( ui_color ( B_MENU_BACKGROUND_COLOR ), B_LIGHTEN_2_TINT)); 617 StrokeLine(BPoint(bounds.right - 2, bounds.top + 1), 618 BPoint(bounds.left + 1, bounds.top + 1)); 619 StrokeLine(BPoint(bounds.left + 1, bounds.bottom - 2)); 620 621 DrawItems(updateRect); 622 } 623 //------------------------------------------------------------------------------ 624 void BMenu::GetPreferredSize(float *width, float *height) 625 { 626 } 627 //------------------------------------------------------------------------------ 628 void BMenu::ResizeToPreferred() 629 { 630 } 631 //------------------------------------------------------------------------------ 632 void BMenu::FrameMoved(BPoint new_position) 633 { 634 } 635 //------------------------------------------------------------------------------ 636 void BMenu::FrameResized(float new_width, float new_height) 637 { 638 } 639 //------------------------------------------------------------------------------ 640 void BMenu::InvalidateLayout() 641 { 642 CacheFontInfo(); 643 LayoutItems(0); 644 } 645 //------------------------------------------------------------------------------ 646 BHandler *BMenu::ResolveSpecifier(BMessage *msg, int32 index, 647 BMessage *specifier, int32 form, 648 const char *property) 649 { 650 BPropertyInfo propInfo(prop_list); 651 BHandler *target = NULL; 652 653 switch (propInfo.FindMatch(msg, 0, specifier, form, property)) 654 { 655 case B_ERROR: 656 break; 657 658 case 0: 659 case 1: 660 case 2: 661 case 3: 662 case 4: 663 case 5: 664 case 6: 665 case 7: 666 target = this; 667 break; 668 case 8: 669 // TODO: redirect to menu 670 target = this; 671 break; 672 case 9: 673 case 10: 674 case 11: 675 case 12: 676 target = this; 677 break; 678 case 13: 679 // TODO: redirect to menuitem 680 target = this; 681 break; 682 } 683 684 if (!target) 685 target = BView::ResolveSpecifier(msg, index, specifier, form, 686 property); 687 688 return target; 689 } 690 //------------------------------------------------------------------------------ 691 status_t BMenu::GetSupportedSuites(BMessage *data) 692 { 693 status_t err; 694 695 if (data == NULL) 696 return B_BAD_VALUE; 697 698 err = data->AddString("suites", "suite/vnd.Be-menu"); 699 700 if (err != B_OK) 701 return err; 702 703 BPropertyInfo prop_info(prop_list); 704 err = data->AddFlat("messages", &prop_info); 705 706 if (err != B_OK) 707 return err; 708 709 return BView::GetSupportedSuites(data); 710 } 711 //------------------------------------------------------------------------------ 712 status_t BMenu::Perform(perform_code d, void *arg) 713 { 714 return B_ERROR; 715 } 716 //------------------------------------------------------------------------------ 717 void BMenu::MakeFocus(bool focused) 718 { 719 if (focused) 720 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); 721 722 BView::MakeFocus(focused); 723 } 724 //------------------------------------------------------------------------------ 725 void BMenu::AllAttached() 726 { 727 } 728 //------------------------------------------------------------------------------ 729 void BMenu::AllDetached() 730 { 731 } 732 //------------------------------------------------------------------------------ 733 BMenu::BMenu(BRect frame, const char *name, uint32 resizingMode, uint32 flags, 734 menu_layout layout, bool resizeToFit) 735 : BView(frame, name, resizingMode, flags), 736 fChosenItem(NULL), 737 fSelected(NULL), 738 fCachedMenuWindow(NULL), 739 fSuper(NULL), 740 fSuperitem(NULL), 741 fAscent(-1.0f), 742 fDescent(-1.0f), 743 fFontHeight(-1.0f), 744 fState(0), 745 fLayout(layout), 746 fExtraRect(NULL), 747 fMaxContentWidth(0.0f), 748 fInitMatrixSize(NULL), 749 fExtraMenuData(NULL), 750 fTrigger(0), 751 fResizeToFit(resizeToFit), 752 fUseCachedMenuLayout(true), 753 fEnabled(true), 754 fDynamicName(false), 755 fRadioMode(false), 756 fTrackNewBounds(false), 757 fStickyMode(false), 758 fIgnoreHidden(true), 759 fTriggerEnabled(true), 760 fRedrawAfterSticky(true), 761 fAttachAborted(false) 762 { 763 SetViewColor(ui_color(B_MENU_BACKGROUND_COLOR)); 764 SetFontSize(10); 765 } 766 //------------------------------------------------------------------------------ 767 BPoint BMenu::ScreenLocation() 768 { 769 BMenu *superMenu = Supermenu(); 770 771 if (superMenu == NULL) 772 return BPoint(); 773 774 BMenuItem *superItem = Superitem(); 775 776 if (superItem == NULL) 777 return BPoint(); 778 779 BPoint point; 780 781 if (superMenu->Layout() == B_ITEMS_IN_COLUMN) 782 point = superItem->Frame().RightTop(); 783 else 784 point = superItem->Frame().LeftBottom() + BPoint(0.0f, 1.0f); 785 786 superMenu->ConvertToScreen(&point); 787 788 return point; 789 } 790 //------------------------------------------------------------------------------ 791 void BMenu::SetItemMargins(float left, float top, float right, float bottom) 792 { 793 fPad.Set(left, top, right, bottom); 794 } 795 //------------------------------------------------------------------------------ 796 void BMenu::GetItemMargins(float *left, float *top, float *right, 797 float *bottom) const 798 { 799 *left = fPad.left; 800 *top = fPad.top; 801 *right = fPad.right; 802 *bottom = fPad.bottom; 803 } 804 //------------------------------------------------------------------------------ 805 menu_layout BMenu::Layout() const 806 { 807 return fLayout; 808 } 809 //------------------------------------------------------------------------------ 810 void BMenu::Show() 811 { 812 Show(false); 813 } 814 //------------------------------------------------------------------------------ 815 void BMenu::Show(bool selectFirst) 816 { 817 _show(selectFirst); 818 } 819 //------------------------------------------------------------------------------ 820 void BMenu::Hide() 821 { 822 _hide(); 823 } 824 //------------------------------------------------------------------------------ 825 BMenuItem *BMenu::Track(bool openAnyway, BRect *clickToOpenRect) 826 { 827 return NULL; 828 } 829 //------------------------------------------------------------------------------ 830 bool BMenu::AddDynamicItem(add_state s) 831 { 832 return false; 833 } 834 //------------------------------------------------------------------------------ 835 void BMenu::DrawBackground(BRect update) 836 { 837 } 838 //------------------------------------------------------------------------------ 839 void BMenu::SetTrackingHook(menu_tracking_hook func, void *state) 840 { 841 } 842 //------------------------------------------------------------------------------ 843 void BMenu::_ReservedMenu3() {} 844 void BMenu::_ReservedMenu4() {} 845 void BMenu::_ReservedMenu5() {} 846 void BMenu::_ReservedMenu6() {} 847 //------------------------------------------------------------------------------ 848 BMenu &BMenu::operator=(const BMenu &) 849 { 850 return *this; 851 } 852 //------------------------------------------------------------------------------ 853 void BMenu::InitData(BMessage *data) 854 { 855 } 856 //------------------------------------------------------------------------------ 857 bool BMenu::_show(bool selectFirstItem) 858 { 859 BPoint point = ScreenLocation(); 860 861 BWindow *window = new BMenuWindow(BRect(point.x, point.y, 862 point.x + 20, point.y + 200), this); 863 864 window->Show(); 865 866 return true; 867 } 868 //------------------------------------------------------------------------------ 869 void BMenu::_hide() 870 { 871 BWindow *window = Window(); 872 873 if (window) 874 { 875 window->RemoveChild(this); 876 877 window->Lock(); 878 window->Quit(); 879 } 880 } 881 //------------------------------------------------------------------------------ 882 BMenuItem *BMenu::_track(int *action, long start) 883 { 884 return NULL; 885 } 886 //------------------------------------------------------------------------------ 887 bool BMenu::_AddItem(BMenuItem *item, int32 index) 888 { 889 return false; 890 } 891 //------------------------------------------------------------------------------ 892 bool BMenu::RemoveItems(int32 index, int32 count, BMenuItem *item, bool del) 893 { 894 return false; 895 } 896 //------------------------------------------------------------------------------ 897 void BMenu::LayoutItems(int32 index) 898 { 899 CalcTriggers(); 900 901 float width, height; 902 903 ComputeLayout(index, true, true, &width, &height); 904 905 ResizeTo(width, height); 906 } 907 //------------------------------------------------------------------------------ 908 void BMenu::ComputeLayout(int32 index, bool bestFit, bool moveItems, 909 float* width, float* height) 910 { 911 BRect frame; 912 float iWidth, iHeight; 913 BMenuItem *item; 914 915 if (fLayout == B_ITEMS_IN_COLUMN) 916 { 917 frame = BRect(0.0f, 0.0f, 0.0f, 2.0f); 918 919 for (int i = 0; i < fItems.CountItems(); i++) 920 { 921 item = (BMenuItem*)fItems.ItemAt(i); 922 923 item->GetContentSize(&iWidth, &iHeight); 924 925 if (item->fModifiers && item->fShortcutChar) 926 iWidth += 25.0f; 927 928 item->fBounds.left = 2.0f; 929 item->fBounds.top = frame.bottom; 930 item->fBounds.bottom = item->fBounds.top + iHeight + fPad.top + fPad.bottom; 931 932 frame.right = max_c(frame.right, iWidth + fPad.left + fPad.right); 933 frame.bottom = item->fBounds.bottom + 1.0f; 934 } 935 936 for (int i = 0; i < fItems.CountItems(); i++) 937 ItemAt(i)->fBounds.right = frame.right; 938 939 frame.right = (float)ceil(frame.right) + 2.0f; 940 frame.bottom += 1.0f; 941 } 942 else if (fLayout == B_ITEMS_IN_ROW) 943 { 944 font_height fh; 945 GetFontHeight(&fh); 946 frame = BRect(0.0f, 0.0f, 0.0f, 947 (float)ceil(fh.ascent) + (float)ceil(fh.descent) + fPad.top + fPad.bottom); 948 949 for (int i = 0; i < fItems.CountItems(); i++) 950 { 951 item = (BMenuItem*)fItems.ItemAt(i); 952 953 item->GetContentSize(&iWidth, &iHeight); 954 955 item->fBounds.left = frame.right; 956 item->fBounds.top = 0.0f; 957 item->fBounds.right = item->fBounds.left + iWidth + fPad.left + fPad.right; 958 959 frame.right = item->fBounds.right + 1.0f; 960 frame.bottom = max_c(frame.bottom, iHeight + fPad.top + fPad.bottom); 961 } 962 963 for (int i = 0; i < fItems.CountItems(); i++) 964 ItemAt(i)->fBounds.bottom = frame.bottom; 965 966 frame.right = (float)ceil(frame.right) + 8.0f; 967 } 968 969 if ((ResizingMode() & B_FOLLOW_LEFT_RIGHT) == B_FOLLOW_LEFT_RIGHT) 970 { 971 if (Parent()) 972 *width = Parent()->Frame().Width() + 1.0f; 973 else 974 *width = Window()->Frame().Width() + 1.0f; 975 976 *height = frame.Height(); 977 } 978 else 979 { 980 *width = frame.Width(); 981 *height = frame.Height(); 982 } 983 } 984 //------------------------------------------------------------------------------ 985 BRect BMenu::Bump(BRect current, BPoint extent, int32 index) const 986 { 987 return BRect(); 988 } 989 //------------------------------------------------------------------------------ 990 BPoint BMenu::ItemLocInRect(BRect frame) const 991 { 992 return BPoint(); 993 } 994 //------------------------------------------------------------------------------ 995 BRect BMenu::CalcFrame(BPoint where, bool *scrollOn) 996 { 997 return BRect(); 998 } 999 //------------------------------------------------------------------------------ 1000 bool BMenu::ScrollMenu(BRect bounds, BPoint loc, bool *fast) 1001 { 1002 return false; 1003 } 1004 //------------------------------------------------------------------------------ 1005 void BMenu::ScrollIntoView(BMenuItem *item) 1006 { 1007 } 1008 //------------------------------------------------------------------------------ 1009 void BMenu::DrawItems(BRect updateRect) 1010 { 1011 for (int i =0; i < fItems.CountItems(); i++) 1012 { 1013 if (ItemAt(i)->Frame().Intersects(updateRect)) 1014 ItemAt(i)->Draw(); 1015 } 1016 } 1017 //------------------------------------------------------------------------------ 1018 int BMenu::State(BMenuItem **item) const 1019 { 1020 return 0; 1021 } 1022 //------------------------------------------------------------------------------ 1023 void BMenu::InvokeItem(BMenuItem *item, bool now) 1024 { 1025 if (item->Submenu()) 1026 item->Submenu()->Show(); 1027 else if (IsRadioMode()) 1028 item->SetMarked(true); 1029 1030 item->Invoke(); 1031 } 1032 //------------------------------------------------------------------------------ 1033 bool BMenu::OverSuper(BPoint loc) 1034 { 1035 // TODO: we assume that loc is in screen coords 1036 if (!Supermenu()) 1037 return false; 1038 1039 return Supermenu()->Window()->Frame().Contains(loc); 1040 } 1041 //------------------------------------------------------------------------------ 1042 bool BMenu::OverSubmenu(BMenuItem *item, BPoint loc) 1043 { 1044 // TODO: we assume that loc is in screen coords 1045 if (!item->Submenu()) 1046 return false; 1047 1048 return item->Submenu()->Window()->Frame().Contains(loc); 1049 } 1050 //------------------------------------------------------------------------------ 1051 BMenuWindow *BMenu::MenuWindow() 1052 { 1053 return fCachedMenuWindow; 1054 } 1055 //------------------------------------------------------------------------------ 1056 void BMenu::DeleteMenuWindow() 1057 { 1058 delete fCachedMenuWindow; 1059 fCachedMenuWindow = NULL; 1060 } 1061 //------------------------------------------------------------------------------ 1062 BMenuItem *BMenu::HitTestItems(BPoint where, BPoint slop) const 1063 { 1064 for (int i =0; i < CountItems(); i++) 1065 if (ItemAt(i)->fBounds.Contains(where)) 1066 return ItemAt(i); 1067 1068 return NULL; 1069 } 1070 //------------------------------------------------------------------------------ 1071 BRect BMenu::Superbounds() const 1072 { 1073 return BRect(); 1074 } 1075 //------------------------------------------------------------------------------ 1076 void BMenu::CacheFontInfo() 1077 { 1078 font_height fh; 1079 GetFontHeight(&fh); 1080 fAscent = fh.ascent; 1081 fDescent = fh.descent; 1082 fFontHeight = (float)ceil(fh.ascent + fh.descent + 0.5f); 1083 } 1084 //------------------------------------------------------------------------------ 1085 void BMenu::ItemMarked(BMenuItem *item) 1086 { 1087 if (IsRadioMode()) 1088 { 1089 for (int32 i = 0; i < CountItems(); i++) 1090 if (ItemAt(i) != item) 1091 ItemAt(i)->SetMarked(false); 1092 } 1093 1094 if (IsLabelFromMarked() && Superitem()) 1095 Superitem()->SetLabel(item->Label()); 1096 } 1097 //------------------------------------------------------------------------------ 1098 void BMenu::Install(BWindow *target) 1099 { 1100 for (int i =0; i < CountItems(); i++) 1101 ItemAt(i)->Install(target); 1102 } 1103 //------------------------------------------------------------------------------ 1104 void BMenu::Uninstall() 1105 { 1106 } 1107 //------------------------------------------------------------------------------ 1108 void BMenu::SelectItem(BMenuItem *m, uint32 showSubmenu,bool selectFirstItem) 1109 { 1110 } 1111 //------------------------------------------------------------------------------ 1112 BMenuItem *BMenu::CurrentSelection() const 1113 { 1114 return fSelected; 1115 } 1116 //------------------------------------------------------------------------------ 1117 bool BMenu::SelectNextItem(BMenuItem *item, bool forward) 1118 { 1119 return false; 1120 } 1121 //------------------------------------------------------------------------------ 1122 BMenuItem *BMenu::NextItem(BMenuItem *item, bool forward) const 1123 { 1124 return NULL; 1125 } 1126 //------------------------------------------------------------------------------ 1127 bool BMenu::IsItemVisible(BMenuItem *item) const 1128 { 1129 return false; 1130 } 1131 //------------------------------------------------------------------------------ 1132 void BMenu::SetIgnoreHidden(bool on) 1133 { 1134 fIgnoreHidden = on; 1135 } 1136 //------------------------------------------------------------------------------ 1137 void BMenu::SetStickyMode(bool on) 1138 { 1139 fStickyMode = on; 1140 } 1141 //------------------------------------------------------------------------------ 1142 bool BMenu::IsStickyMode() const 1143 { 1144 return fStickyMode; 1145 } 1146 //------------------------------------------------------------------------------ 1147 void BMenu::CalcTriggers() 1148 { 1149 } 1150 //------------------------------------------------------------------------------ 1151 const char *BMenu::ChooseTrigger(const char *title, BList *chars) 1152 { 1153 return NULL; 1154 } 1155 //------------------------------------------------------------------------------ 1156 void BMenu::UpdateWindowViewSize(bool upWind) 1157 { 1158 } 1159 //------------------------------------------------------------------------------ 1160 bool BMenu::IsStickyPrefOn() 1161 { 1162 return false; 1163 } 1164 //------------------------------------------------------------------------------ 1165 void BMenu::RedrawAfterSticky(BRect bounds) 1166 { 1167 } 1168 //------------------------------------------------------------------------------ 1169 bool BMenu::OkToProceed(BMenuItem *) 1170 { 1171 return false; 1172 } 1173 //------------------------------------------------------------------------------ 1174 status_t BMenu::ParseMsg(BMessage *msg, int32 *sindex, BMessage *spec, 1175 int32 *form, const char **prop, BMenu **tmenu, 1176 BMenuItem **titem, int32 *user_data, 1177 BMessage *reply) const 1178 { 1179 return B_ERROR; 1180 } 1181 //------------------------------------------------------------------------------ 1182 status_t BMenu::DoMenuMsg(BMenuItem **next, BMenu *tar, BMessage *m, 1183 BMessage *r, BMessage *spec, int32 f) const 1184 { 1185 return B_ERROR; 1186 } 1187 //------------------------------------------------------------------------------ 1188 status_t BMenu::DoMenuItemMsg(BMenuItem **next, BMenu *tar, BMessage *m, 1189 BMessage *r, BMessage *spec, int32 f) const 1190 { 1191 return B_ERROR; 1192 } 1193 //------------------------------------------------------------------------------ 1194 status_t BMenu::DoEnabledMsg(BMenuItem *ti, BMenu *tm, BMessage *m, 1195 BMessage *r) const 1196 { 1197 return B_ERROR; 1198 } 1199 //------------------------------------------------------------------------------ 1200 status_t BMenu::DoLabelMsg(BMenuItem *ti, BMenu *tm, BMessage *m, 1201 BMessage *r) const 1202 { 1203 return B_ERROR; 1204 } 1205 //------------------------------------------------------------------------------ 1206 status_t BMenu::DoMarkMsg(BMenuItem *ti, BMenu *tm, BMessage *m, 1207 BMessage *r) const 1208 { 1209 return B_ERROR; 1210 } 1211 //------------------------------------------------------------------------------ 1212 status_t BMenu::DoDeleteMsg(BMenuItem *ti, BMenu *tm, BMessage *m, 1213 BMessage *r) const 1214 { 1215 return B_ERROR; 1216 } 1217 //------------------------------------------------------------------------------ 1218 status_t BMenu::DoCreateMsg(BMenuItem *ti, BMenu *tm, BMessage *m, 1219 BMessage *r, bool menu) const 1220 { 1221 return B_ERROR; 1222 } 1223 //------------------------------------------------------------------------------ 1224 1225 1226 1227 // Temporary mouse hooks 1228 //------------------------------------------------------------------------------ 1229 void BMenu::MouseDown(BPoint point) 1230 { 1231 BMenuItem *item = HitTestItems(point); 1232 1233 if (item) 1234 InvokeItem(item); 1235 1236 Hide(); 1237 } 1238 //------------------------------------------------------------------------------ 1239 void BMenu::MouseMoved(BPoint point, uint32 transit, const BMessage *message) 1240 { 1241 BMenuItem *item = HitTestItems(point); 1242 1243 if (fSelected) 1244 { 1245 if (fSelected == item) 1246 return; 1247 1248 fSelected->fSelected = false; 1249 //if (fSelected->Submenu()) 1250 // fSelected->Submenu()->Hide(); 1251 Invalidate(fSelected->Frame()); 1252 } 1253 1254 fSelected = item; 1255 1256 if (fSelected) 1257 { 1258 fSelected->fSelected = true; 1259 //if (fSelected->Submenu()) 1260 // fSelected->Submenu()->Show(); 1261 Invalidate(fSelected->Frame()); 1262 } 1263 } 1264 //------------------------------------------------------------------------------ 1265 void BMenu::MouseUp(BPoint point) 1266 { 1267 1268 } 1269 //------------------------------------------------------------------------------ 1270 status_t set_menu_info(menu_info *info) 1271 { 1272 BPath path; 1273 1274 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 1275 return B_OK; 1276 1277 path.Append("menu_settings"); 1278 1279 BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); 1280 1281 if (file.InitCheck() != B_OK) 1282 return B_OK; 1283 1284 file.Write(info, sizeof(menu_info)); 1285 1286 return B_OK; 1287 } 1288 //------------------------------------------------------------------------------ 1289 status_t get_menu_info(menu_info *info) 1290 { 1291 info->font_size = 8; 1292 memcpy(info->f_family, "Arial", 6); 1293 memcpy(info->f_style, "Regular", 8); 1294 info->background_color = ui_color(B_MENU_BACKGROUND_COLOR); 1295 info->separator = 0; 1296 info->click_to_open = true; 1297 info->triggers_always_shown = false; 1298 1299 BPath path; 1300 1301 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 1302 return B_OK; 1303 1304 path.Append("menu_settings"); 1305 1306 BFile file(path.Path(), B_READ_ONLY); 1307 1308 if (file.InitCheck() != B_OK) 1309 return B_OK; 1310 1311 file.Read(info, sizeof(menu_info)); 1312 1313 return B_OK; 1314 } 1315 //------------------------------------------------------------------------------ 1316