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