1/* 2 * Copyright 2001-2020 Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan A��mus, superstippi@gmx.de 7 * DarkWyrm, bpmagic@columbus.rr.com 8 * John Scipione, jscipione@gmail.com 9 * Ingo Weinhold, ingo_weinhold@gmx.de 10 * Clemens Zeidler, haiku@clemens-zeidler.de 11 * Joseph Groover, looncraz@looncraz.net 12 * Tri-Edge AI 13 * Jacob Secunda, secundja@gmail.com 14 */ 15 16 17/*! Base class for window decorators */ 18 19 20#include "Decorator.h" 21 22#include <stdio.h> 23 24#include <Region.h> 25 26#include "Desktop.h" 27#include "DesktopSettings.h" 28#include "DrawingEngine.h" 29 30 31Decorator::Tab::Tab() 32 : 33 tabRect(), 34 35 zoomRect(), 36 closeRect(), 37 minimizeRect(), 38 39 closePressed(false), 40 zoomPressed(false), 41 minimizePressed(false), 42 43 look(B_TITLED_WINDOW_LOOK), 44 flags(0), 45 isFocused(false), 46 title(""), 47 48 tabOffset(0), 49 tabLocation(0.0f), 50 textOffset(10.0f), 51 52 truncatedTitle(""), 53 truncatedTitleLength(0), 54 55 buttonFocus(false), 56 isHighlighted(false), 57 58 minTabSize(0.0f), 59 maxTabSize(0.0f) 60{ 61 closeBitmaps[0] = closeBitmaps[1] = closeBitmaps[2] = closeBitmaps[3] 62 = minimizeBitmaps[0] = minimizeBitmaps[1] = minimizeBitmaps[2] 63 = minimizeBitmaps[3] = zoomBitmaps[0] = zoomBitmaps[1] = zoomBitmaps[2] 64 = zoomBitmaps[3] = NULL; 65} 66 67 68/*! \brief Constructor 69 70 Does general initialization of internal data members and creates a colorset 71 object. 72 73 \param settings DesktopSettings pointer. 74 \param frame Decorator frame rectangle 75*/ 76Decorator::Decorator(DesktopSettings& settings, BRect frame, 77 Desktop* desktop) 78 : 79 fLocker("Decorator"), 80 81 fDrawingEngine(NULL), 82 fDrawState(), 83 84 fTitleBarRect(), 85 fFrame(frame), 86 fResizeRect(), 87 fBorderRect(), 88 fOutlineBorderRect(), 89 90 fLeftBorder(), 91 fTopBorder(), 92 fBottomBorder(), 93 fRightBorder(), 94 95 fLeftOutlineBorder(), 96 fTopOutlineBorder(), 97 fBottomOutlineBorder(), 98 fRightOutlineBorder(), 99 100 fBorderWidth(-1), 101 fOutlineBorderWidth(-1), 102 103 fTopTab(NULL), 104 105 fDesktop(desktop), 106 fFootprintValid(false) 107{ 108 memset(&fRegionHighlights, HIGHLIGHT_NONE, sizeof(fRegionHighlights)); 109} 110 111 112/*! \brief Destructor 113 114 Frees the color set and the title string 115*/ 116Decorator::~Decorator() 117{ 118} 119 120 121Decorator::Tab* 122Decorator::AddTab(DesktopSettings& settings, const char* title, 123 window_look look, uint32 flags, int32 index, BRegion* updateRegion) 124{ 125 AutoWriteLocker _(fLocker); 126 127 Decorator::Tab* tab = _AllocateNewTab(); 128 if (tab == NULL) 129 return NULL; 130 tab->title = title; 131 tab->look = look; 132 tab->flags = flags; 133 134 bool ok = false; 135 if (index >= 0) { 136 if (fTabList.AddItem(tab, index) == true) 137 ok = true; 138 } else if (fTabList.AddItem(tab) == true) 139 ok = true; 140 141 if (ok == false) { 142 delete tab; 143 return NULL; 144 } 145 146 Decorator::Tab* oldTop = fTopTab; 147 fTopTab = tab; 148 if (_AddTab(settings, index, updateRegion) == false) { 149 fTabList.RemoveItem(tab); 150 delete tab; 151 fTopTab = oldTop; 152 return NULL; 153 } 154 155 _InvalidateFootprint(); 156 return tab; 157} 158 159 160bool 161Decorator::RemoveTab(int32 index, BRegion* updateRegion) 162{ 163 AutoWriteLocker _(fLocker); 164 165 Decorator::Tab* tab = fTabList.RemoveItemAt(index); 166 if (tab == NULL) 167 return false; 168 169 _RemoveTab(index, updateRegion); 170 171 delete tab; 172 _InvalidateFootprint(); 173 return true; 174} 175 176 177bool 178Decorator::MoveTab(int32 from, int32 to, bool isMoving, BRegion* updateRegion) 179{ 180 AutoWriteLocker _(fLocker); 181 182 if (_MoveTab(from, to, isMoving, updateRegion) == false) 183 return false; 184 if (fTabList.MoveItem(from, to) == false) { 185 // move the tab back 186 _MoveTab(from, to, isMoving, updateRegion); 187 return false; 188 } 189 return true; 190} 191 192 193int32 194Decorator::TabAt(const BPoint& where) const 195{ 196 AutoReadLocker _(fLocker); 197 198 for (int32 i = 0; i < fTabList.CountItems(); i++) { 199 Decorator::Tab* tab = fTabList.ItemAt(i); 200 if (tab->tabRect.Contains(where)) 201 return i; 202 } 203 204 return -1; 205} 206 207 208void 209Decorator::SetTopTab(int32 tab) 210{ 211 AutoWriteLocker _(fLocker); 212 fTopTab = fTabList.ItemAt(tab); 213} 214 215 216/*! \brief Assigns a display driver to the decorator 217 \param driver A valid DrawingEngine object 218*/ 219void 220Decorator::SetDrawingEngine(DrawingEngine* engine) 221{ 222 AutoWriteLocker _(fLocker); 223 224 fDrawingEngine = engine; 225 // lots of subclasses will depend on the driver for text support, so call 226 // _DoLayout() after we have it 227 if (fDrawingEngine != NULL) { 228 _DoLayout(); 229 _DoOutlineLayout(); 230 } 231} 232 233 234/*! \brief Sets the decorator's window flags 235 236 While this call will not update the screen, it will affect how future 237 updates work and immediately affects input handling. 238 239 \param flags New value for the flags 240*/ 241void 242Decorator::SetFlags(int32 tab, uint32 flags, BRegion* updateRegion) 243{ 244 AutoWriteLocker _(fLocker); 245 246 // we're nice to our subclasses - we make sure B_NOT_{H|V|}_RESIZABLE 247 // are in sync (it's only a semantical simplification, not a necessity) 248 if ((flags & (B_NOT_H_RESIZABLE | B_NOT_V_RESIZABLE)) 249 == (B_NOT_H_RESIZABLE | B_NOT_V_RESIZABLE)) 250 flags |= B_NOT_RESIZABLE; 251 if (flags & B_NOT_RESIZABLE) 252 flags |= B_NOT_H_RESIZABLE | B_NOT_V_RESIZABLE; 253 254 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 255 if (decoratorTab == NULL) 256 return; 257 _SetFlags(decoratorTab, flags, updateRegion); 258 _InvalidateFootprint(); 259 // the border might have changed (smaller/larger tab) 260} 261 262 263/*! \brief Called whenever the system fonts are changed. 264*/ 265void 266Decorator::FontsChanged(DesktopSettings& settings, BRegion* updateRegion) 267{ 268 AutoWriteLocker _(fLocker); 269 270 _FontsChanged(settings, updateRegion); 271 _InvalidateFootprint(); 272} 273 274 275/*! \brief Called when a system colors change. 276*/ 277void 278Decorator::ColorsChanged(DesktopSettings& settings, BRegion* updateRegion) 279{ 280 AutoWriteLocker _(fLocker); 281 282 UpdateColors(settings); 283 284 if (updateRegion != NULL) 285 updateRegion->Include(&GetFootprint()); 286 287 _InvalidateBitmaps(); 288} 289 290 291/*! \brief Sets the decorator's window look 292 \param look New value for the look 293*/ 294void 295Decorator::SetLook(int32 tab, DesktopSettings& settings, window_look look, 296 BRegion* updateRect) 297{ 298 AutoWriteLocker _(fLocker); 299 300 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 301 if (decoratorTab == NULL) 302 return; 303 304 _SetLook(decoratorTab, settings, look, updateRect); 305 _InvalidateFootprint(); 306 // the border very likely changed 307} 308 309 310/*! \brief Returns the decorator's window look 311 \return the decorator's window look 312*/ 313window_look 314Decorator::Look(int32 tab) const 315{ 316 AutoReadLocker _(fLocker); 317 return TabAt(tab)->look; 318} 319 320 321/*! \brief Returns the decorator's window flags 322 \return the decorator's window flags 323*/ 324uint32 325Decorator::Flags(int32 tab) const 326{ 327 AutoReadLocker _(fLocker); 328 return TabAt(tab)->flags; 329} 330 331 332/*! \brief Returns the decorator's border rectangle 333 \return the decorator's border rectangle 334*/ 335BRect 336Decorator::BorderRect() const 337{ 338 AutoReadLocker _(fLocker); 339 return fBorderRect; 340} 341 342 343BRect 344Decorator::TitleBarRect() const 345{ 346 AutoReadLocker _(fLocker); 347 return fTitleBarRect; 348} 349 350 351/*! \brief Returns the decorator's tab rectangle 352 \return the decorator's tab rectangle 353*/ 354BRect 355Decorator::TabRect(int32 tab) const 356{ 357 AutoReadLocker _(fLocker); 358 359 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 360 if (decoratorTab == NULL) 361 return BRect(); 362 return decoratorTab->tabRect; 363} 364 365 366BRect 367Decorator::TabRect(Decorator::Tab* tab) const 368{ 369 return tab->tabRect; 370} 371 372 373/*! \brief Sets the close button's value. 374 375 Note that this does not update the button's look - it just updates the 376 internal button value 377 378 \param tab The tab index 379 \param pressed Whether the button is down or not 380*/ 381void 382Decorator::SetClose(int32 tab, bool pressed) 383{ 384 AutoWriteLocker _(fLocker); 385 386 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 387 if (decoratorTab == NULL) 388 return; 389 390 if (pressed != decoratorTab->closePressed) { 391 decoratorTab->closePressed = pressed; 392 DrawClose(tab); 393 } 394} 395 396 397/*! \brief Sets the minimize button's value. 398 399 Note that this does not update the button's look - it just updates the 400 internal button value 401 402 \param is_down Whether the button is down or not 403*/ 404void 405Decorator::SetMinimize(int32 tab, bool pressed) 406{ 407 AutoWriteLocker _(fLocker); 408 409 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 410 if (decoratorTab == NULL) 411 return; 412 413 if (pressed != decoratorTab->minimizePressed) { 414 decoratorTab->minimizePressed = pressed; 415 DrawMinimize(tab); 416 } 417} 418 419/*! \brief Sets the zoom button's value. 420 421 Note that this does not update the button's look - it just updates the 422 internal button value 423 424 \param is_down Whether the button is down or not 425*/ 426void 427Decorator::SetZoom(int32 tab, bool pressed) 428{ 429 AutoWriteLocker _(fLocker); 430 431 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 432 if (decoratorTab == NULL) 433 return; 434 435 if (pressed != decoratorTab->zoomPressed) { 436 decoratorTab->zoomPressed = pressed; 437 DrawZoom(tab); 438 } 439} 440 441 442/*! \brief Updates the value of the decorator title 443 \param string New title value 444*/ 445void 446Decorator::SetTitle(int32 tab, const char* string, BRegion* updateRegion) 447{ 448 AutoWriteLocker _(fLocker); 449 450 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 451 if (decoratorTab == NULL) 452 return; 453 454 decoratorTab->title.SetTo(string); 455 _SetTitle(decoratorTab, string, updateRegion); 456 457 _InvalidateFootprint(); 458 // the border very likely changed 459 460 // TODO: redraw? 461} 462 463 464/*! \brief Returns the decorator's title 465 \return the decorator's title 466*/ 467const char* 468Decorator::Title(int32 tab) const 469{ 470 AutoReadLocker _(fLocker); 471 472 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 473 if (decoratorTab == NULL) 474 return ""; 475 476 return decoratorTab->title; 477} 478 479 480const char* 481Decorator::Title(Decorator::Tab* tab) const 482{ 483 AutoReadLocker _(fLocker); 484 return tab->title; 485} 486 487 488float 489Decorator::TabLocation(int32 tab) const 490{ 491 AutoReadLocker _(fLocker); 492 493 Decorator::Tab* decoratorTab = _TabAt(tab); 494 if (decoratorTab == NULL) 495 return 0.0f; 496 497 return (float)decoratorTab->tabOffset; 498} 499 500 501bool 502Decorator::SetTabLocation(int32 tab, float location, bool isShifting, 503 BRegion* updateRegion) 504{ 505 AutoWriteLocker _(fLocker); 506 507 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 508 if (decoratorTab == NULL) 509 return false; 510 if (_SetTabLocation(decoratorTab, location, isShifting, updateRegion)) { 511 _InvalidateFootprint(); 512 return true; 513 } 514 return false; 515} 516 517 518 519/*! \brief Changes the focus value of the decorator 520 521 While this call will not update the screen, it will affect how future 522 updates work. 523 524 \param active True if active, false if not 525*/ 526void 527Decorator::SetFocus(int32 tab, bool active) 528{ 529 AutoWriteLocker _(fLocker); 530 531 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 532 if (decoratorTab == NULL) 533 return; 534 decoratorTab->isFocused = active; 535 _SetFocus(decoratorTab); 536 // TODO: maybe it would be cleaner to handle the redraw here. 537} 538 539 540bool 541Decorator::IsFocus(int32 tab) const 542{ 543 AutoReadLocker _(fLocker); 544 545 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 546 if (decoratorTab == NULL) 547 return false; 548 549 return decoratorTab->isFocused; 550}; 551 552 553bool 554Decorator::IsFocus(Decorator::Tab* tab) const 555{ 556 AutoReadLocker _(fLocker); 557 return tab->isFocused; 558} 559 560 561// #pragma mark - virtual methods 562 563 564/*! \brief Returns a cached footprint if available otherwise recalculate it 565*/ 566const BRegion& 567Decorator::GetFootprint() 568{ 569 AutoReadLocker _(fLocker); 570 571 if (!fFootprintValid) { 572 fFootprint.MakeEmpty(); 573 574 _GetFootprint(&fFootprint); 575 576 if (IsOutlineResizing()) 577 _GetOutlineFootprint(&fFootprint); 578 579 fFootprintValid = true; 580 } 581 582 return fFootprint; 583} 584 585 586/*! \brief Returns our Desktop object pointer 587*/ 588::Desktop* 589Decorator::GetDesktop() 590{ 591 AutoReadLocker _(fLocker); 592 return fDesktop; 593} 594 595 596/*! \brief Performs hit-testing for the decorator. 597 598 The base class provides a basic implementation, recognizing only button and 599 tab hits. Derived classes must override/enhance it to handle borders and 600 corners correctly. 601 602 \param where The point to be tested. 603 \return Either of the following, depending on what was hit: 604 - \c REGION_NONE: None of the decorator regions. 605 - \c REGION_TAB: The window tab (but none of the buttons embedded). 606 - \c REGION_CLOSE_BUTTON: The close button. 607 - \c REGION_ZOOM_BUTTON: The zoom button. 608 - \c REGION_MINIMIZE_BUTTON: The minimize button. 609 - \c REGION_LEFT_BORDER: The left border. 610 - \c REGION_RIGHT_BORDER: The right border. 611 - \c REGION_TOP_BORDER: The top border. 612 - \c REGION_BOTTOM_BORDER: The bottom border. 613 - \c REGION_LEFT_TOP_CORNER: The left-top corner. 614 - \c REGION_LEFT_BOTTOM_CORNER: The left-bottom corner. 615 - \c REGION_RIGHT_TOP_CORNER: The right-top corner. 616 - \c REGION_RIGHT_BOTTOM_CORNER The right-bottom corner. 617*/ 618Decorator::Region 619Decorator::RegionAt(BPoint where, int32& tabIndex) const 620{ 621 AutoReadLocker _(fLocker); 622 623 tabIndex = -1; 624 625 for (int32 i = 0; i < fTabList.CountItems(); i++) { 626 Decorator::Tab* tab = fTabList.ItemAt(i); 627 if (tab->closeRect.Contains(where)) { 628 tabIndex = i; 629 return REGION_CLOSE_BUTTON; 630 } 631 if (tab->zoomRect.Contains(where)) { 632 tabIndex = i; 633 return REGION_ZOOM_BUTTON; 634 } 635 if (tab->tabRect.Contains(where)) { 636 tabIndex = i; 637 return REGION_TAB; 638 } 639 } 640 641 return REGION_NONE; 642} 643 644 645/*! \brief Moves the decorator frame and all default rectangles 646 647 If a subclass implements this method, be sure to call Decorator::MoveBy 648 to ensure that internal members are also updated. All members of the 649 Decorator class are automatically moved in this method 650 651 \param x X Offset 652 \param y y Offset 653*/ 654void 655Decorator::MoveBy(float x, float y) 656{ 657 MoveBy(BPoint(x, y)); 658} 659 660 661/*! \brief Moves the decorator frame and all default rectangles 662 663 If a subclass implements this method, be sure to call Decorator::MoveBy 664 to ensure that internal members are also updated. All members of the 665 Decorator class are automatically moved in this method 666 667 \param offset BPoint containing the offsets 668*/ 669void 670Decorator::MoveBy(BPoint offset) 671{ 672 AutoWriteLocker _(fLocker); 673 674 if (fFootprintValid) 675 fFootprint.OffsetBy(offset.x, offset.y); 676 677 _MoveBy(offset); 678 _MoveOutlineBy(offset); 679} 680 681 682/*! \brief Resizes the decorator frame 683 684 This is a required function for subclasses to implement - the default does 685 nothing. Note that window resize flags should be followed and fFrame should 686 be resized accordingly. It would also be a wise idea to ensure that the 687 window's rectangles are not inverted. 688 689 \param x x offset 690 \param y y offset 691*/ 692void 693Decorator::ResizeBy(float x, float y, BRegion* dirty) 694{ 695 ResizeBy(BPoint(x, y), dirty); 696} 697 698 699void 700Decorator::ResizeBy(BPoint offset, BRegion* dirty) 701{ 702 AutoWriteLocker _(fLocker); 703 704 _ResizeBy(offset, dirty); 705 _ResizeOutlineBy(offset, dirty); 706 707 _InvalidateFootprint(); 708} 709 710 711void 712Decorator::SetOutlinesDelta(BPoint delta, BRegion* dirty) 713{ 714 _SetOutlinesDelta(delta, dirty); 715 _InvalidateFootprint(); 716} 717 718 719void 720Decorator::ExtendDirtyRegion(Region region, BRegion& dirty) 721{ 722 AutoReadLocker _(fLocker); 723 724 switch (region) { 725 case REGION_TAB: 726 dirty.Include(fTitleBarRect); 727 break; 728 729 case REGION_CLOSE_BUTTON: 730 if ((fTopTab->flags & B_NOT_CLOSABLE) == 0) { 731 for (int32 i = 0; i < fTabList.CountItems(); i++) 732 dirty.Include(fTabList.ItemAt(i)->closeRect); 733 } 734 break; 735 736 case REGION_MINIMIZE_BUTTON: 737 if ((fTopTab->flags & B_NOT_MINIMIZABLE) == 0) { 738 for (int32 i = 0; i < fTabList.CountItems(); i++) 739 dirty.Include(fTabList.ItemAt(i)->minimizeRect); 740 } 741 break; 742 743 case REGION_ZOOM_BUTTON: 744 if ((fTopTab->flags & B_NOT_ZOOMABLE) == 0) { 745 for (int32 i = 0; i < fTabList.CountItems(); i++) 746 dirty.Include(fTabList.ItemAt(i)->zoomRect); 747 } 748 break; 749 750 case REGION_LEFT_BORDER: 751 if (fLeftBorder.IsValid()) { 752 // fLeftBorder doesn't include the corners, so we have to add 753 // them manually. 754 BRect rect(fLeftBorder); 755 rect.top = fTopBorder.top; 756 rect.bottom = fBottomBorder.bottom; 757 dirty.Include(rect); 758 } 759 break; 760 761 case REGION_RIGHT_BORDER: 762 if (fRightBorder.IsValid()) { 763 // fRightBorder doesn't include the corners, so we have to add 764 // them manually. 765 BRect rect(fRightBorder); 766 rect.top = fTopBorder.top; 767 rect.bottom = fBottomBorder.bottom; 768 dirty.Include(rect); 769 } 770 break; 771 772 case REGION_TOP_BORDER: 773 dirty.Include(fTopBorder); 774 break; 775 776 case REGION_BOTTOM_BORDER: 777 dirty.Include(fBottomBorder); 778 break; 779 780 case REGION_RIGHT_BOTTOM_CORNER: 781 if ((fTopTab->flags & B_NOT_RESIZABLE) == 0) 782 dirty.Include(fResizeRect); 783 break; 784 785 default: 786 break; 787 } 788} 789 790 791/*! \brief Sets a specific highlight for a decorator region. 792 793 Can be overridden by derived classes, but the base class version must be 794 called, if the highlight shall be applied. 795 796 \param region The decorator region. 797 \param highlight The value identifying the kind of highlight. 798 \param dirty The dirty region to be extended, if the highlight changes. Can 799 be \c NULL. 800 \return \c true, if the highlight could be applied. 801*/ 802bool 803Decorator::SetRegionHighlight(Region region, uint8 highlight, BRegion* dirty, 804 int32 tab) 805{ 806 AutoWriteLocker _(fLocker); 807 808 int32 index = (int32)region - 1; 809 if (index < 0 || index >= REGION_COUNT - 1) 810 return false; 811 812 if (fRegionHighlights[index] == highlight) 813 return true; 814 fRegionHighlights[index] = highlight; 815 816 if (dirty != NULL) 817 ExtendDirtyRegion(region, *dirty); 818 819 return true; 820} 821 822 823bool 824Decorator::SetSettings(const BMessage& settings, BRegion* updateRegion) 825{ 826 AutoWriteLocker _(fLocker); 827 828 if (_SetSettings(settings, updateRegion)) { 829 _InvalidateFootprint(); 830 return true; 831 } 832 return false; 833} 834 835 836bool 837Decorator::GetSettings(BMessage* settings) const 838{ 839 AutoReadLocker _(fLocker); 840 841 if (!fTitleBarRect.IsValid()) 842 return false; 843 844 if (settings->AddRect("tab frame", fTitleBarRect) != B_OK) 845 return false; 846 847 if (settings->AddFloat("border width", fBorderWidth) != B_OK) 848 return false; 849 850 // TODO only add the location of the tab of the window who requested the 851 // settings 852 for (int32 i = 0; i < fTabList.CountItems(); i++) { 853 Decorator::Tab* tab = _TabAt(i); 854 if (settings->AddFloat("tab location", (float)tab->tabOffset) != B_OK) 855 return false; 856 } 857 858 return true; 859} 860 861 862void 863Decorator::GetSizeLimits(int32* minWidth, int32* minHeight, 864 int32* maxWidth, int32* maxHeight) const 865{ 866 AutoReadLocker _(fLocker); 867 868 float minTabSize = 0; 869 if (CountTabs() > 0) 870 minTabSize = _TabAt(0)->minTabSize; 871 872 if (fTitleBarRect.IsValid()) { 873 *minWidth = (int32)roundf(max_c(*minWidth, 874 minTabSize - 2 * fBorderWidth)); 875 } 876 if (fResizeRect.IsValid()) { 877 *minHeight = (int32)roundf(max_c(*minHeight, 878 fResizeRect.Height() - fBorderWidth)); 879 } 880} 881 882 883//! draws the tab, title, and buttons 884void 885Decorator::DrawTab(int32 tabIndex) 886{ 887 AutoReadLocker _(fLocker); 888 889 Decorator::Tab* tab = fTabList.ItemAt(tabIndex); 890 if (tab == NULL) 891 return; 892 893 _DrawTab(tab, tab->tabRect); 894 _DrawZoom(tab, false, tab->zoomRect); 895 _DrawMinimize(tab, false, tab->minimizeRect); 896 _DrawTitle(tab, tab->tabRect); 897 _DrawClose(tab, false, tab->closeRect); 898} 899 900 901//! draws the title 902void 903Decorator::DrawTitle(int32 tab) 904{ 905 AutoReadLocker _(fLocker); 906 907 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 908 if (decoratorTab == NULL) 909 return; 910 _DrawTitle(decoratorTab, decoratorTab->tabRect); 911} 912 913 914//! Draws the close button 915void 916Decorator::DrawClose(int32 tab) 917{ 918 AutoReadLocker _(fLocker); 919 920 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 921 if (decoratorTab == NULL) 922 return; 923 924 _DrawClose(decoratorTab, true, decoratorTab->closeRect); 925} 926 927 928//! draws the minimize button 929void 930Decorator::DrawMinimize(int32 tab) 931{ 932 AutoReadLocker _(fLocker); 933 934 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 935 if (decoratorTab == NULL) 936 return; 937 938 _DrawTab(decoratorTab, decoratorTab->minimizeRect); 939} 940 941 942//! draws the zoom button 943void 944Decorator::DrawZoom(int32 tab) 945{ 946 AutoReadLocker _(fLocker); 947 948 Decorator::Tab* decoratorTab = fTabList.ItemAt(tab); 949 if (decoratorTab == NULL) 950 return; 951 _DrawZoom(decoratorTab, true, decoratorTab->zoomRect); 952} 953 954 955rgb_color 956Decorator::UIColor(color_which which) 957{ 958 AutoReadLocker _(fLocker); 959 DesktopSettings settings(fDesktop); 960 return settings.UIColor(which); 961} 962 963 964float 965Decorator::BorderWidth() 966{ 967 AutoReadLocker _(fLocker); 968 return fBorderWidth; 969} 970 971 972float 973Decorator::TabHeight() 974{ 975 AutoReadLocker _(fLocker); 976 977 if (fTitleBarRect.IsValid()) 978 return fTitleBarRect.Height(); 979 980 return fBorderWidth; 981} 982 983 984// #pragma mark - Protected methods 985 986 987Decorator::Tab* 988Decorator::_AllocateNewTab() 989{ 990 Decorator::Tab* tab = new(std::nothrow) Decorator::Tab; 991 if (tab == NULL) 992 return NULL; 993 994 // Set appropriate colors based on the current focus value. In this case, 995 // each decorator defaults to not having the focus. 996 _SetFocus(tab); 997 return tab; 998} 999 1000 1001void 1002Decorator::_DrawTabs(BRect rect) 1003{ 1004 Decorator::Tab* focusTab = NULL; 1005 for (int32 i = 0; i < fTabList.CountItems(); i++) { 1006 Decorator::Tab* tab = fTabList.ItemAt(i); 1007 if (tab->isFocused) { 1008 focusTab = tab; 1009 continue; 1010 } 1011 _DrawTab(tab, rect); 1012 } 1013 1014 if (focusTab != NULL) 1015 _DrawTab(focusTab, rect); 1016} 1017 1018 1019//! Hook function called when the decorator changes focus 1020void 1021Decorator::_SetFocus(Decorator::Tab* tab) 1022{ 1023} 1024 1025 1026bool 1027Decorator::_SetTabLocation(Decorator::Tab* tab, float location, bool isShifting, 1028 BRegion* /*updateRegion*/) 1029{ 1030 return false; 1031} 1032 1033 1034Decorator::Tab* 1035Decorator::_TabAt(int32 index) const 1036{ 1037 return static_cast<Decorator::Tab*>(fTabList.ItemAt(index)); 1038} 1039 1040 1041void 1042Decorator::_FontsChanged(DesktopSettings& settings, BRegion* updateRegion) 1043{ 1044 // get previous extent 1045 if (updateRegion != NULL) 1046 updateRegion->Include(&GetFootprint()); 1047 1048 _InvalidateBitmaps(); 1049 1050 _UpdateFont(settings); 1051 _DoLayout(); 1052 _DoOutlineLayout(); 1053 1054 _InvalidateFootprint(); 1055 if (updateRegion != NULL) 1056 updateRegion->Include(&GetFootprint()); 1057} 1058 1059 1060void 1061Decorator::_SetLook(Decorator::Tab* tab, DesktopSettings& settings, 1062 window_look look, BRegion* updateRegion) 1063{ 1064 // TODO: we could be much smarter about the update region 1065 1066 // get previous extent 1067 if (updateRegion != NULL) 1068 updateRegion->Include(&GetFootprint()); 1069 1070 tab->look = look; 1071 1072 _UpdateFont(settings); 1073 _DoLayout(); 1074 _DoOutlineLayout(); 1075 1076 _InvalidateFootprint(); 1077 if (updateRegion != NULL) 1078 updateRegion->Include(&GetFootprint()); 1079} 1080 1081 1082void 1083Decorator::_SetFlags(Decorator::Tab* tab, uint32 flags, BRegion* updateRegion) 1084{ 1085 // TODO: we could be much smarter about the update region 1086 1087 // get previous extent 1088 if (updateRegion != NULL) 1089 updateRegion->Include(&GetFootprint()); 1090 1091 tab->flags = flags; 1092 _DoLayout(); 1093 _DoOutlineLayout(); 1094 1095 _InvalidateFootprint(); 1096 if (updateRegion != NULL) 1097 updateRegion->Include(&GetFootprint()); 1098} 1099 1100 1101void 1102Decorator::_MoveBy(BPoint offset) 1103{ 1104 for (int32 i = 0; i < fTabList.CountItems(); i++) { 1105 Decorator::Tab* tab = fTabList.ItemAt(i); 1106 1107 tab->zoomRect.OffsetBy(offset); 1108 tab->closeRect.OffsetBy(offset); 1109 tab->minimizeRect.OffsetBy(offset); 1110 tab->tabRect.OffsetBy(offset); 1111 } 1112 fTitleBarRect.OffsetBy(offset); 1113 fFrame.OffsetBy(offset); 1114 fResizeRect.OffsetBy(offset); 1115 fBorderRect.OffsetBy(offset); 1116} 1117 1118 1119void 1120Decorator::_MoveOutlineBy(BPoint offset) 1121{ 1122 fOutlineBorderRect.OffsetBy(offset); 1123 1124 fLeftOutlineBorder.OffsetBy(offset); 1125 fRightOutlineBorder.OffsetBy(offset); 1126 fTopOutlineBorder.OffsetBy(offset); 1127 fBottomOutlineBorder.OffsetBy(offset); 1128} 1129 1130 1131void 1132Decorator::_ResizeOutlineBy(BPoint offset, BRegion* dirty) 1133{ 1134 fOutlineBorderRect.right += offset.x; 1135 fOutlineBorderRect.bottom += offset.y; 1136 1137 fLeftOutlineBorder.bottom += offset.y; 1138 fTopOutlineBorder.right += offset.x; 1139 1140 fRightOutlineBorder.OffsetBy(offset.x, 0.0); 1141 fRightOutlineBorder.bottom += offset.y; 1142 1143 fBottomOutlineBorder.OffsetBy(0.0, offset.y); 1144 fBottomOutlineBorder.right += offset.x; 1145} 1146 1147 1148void 1149Decorator::_SetOutlinesDelta(BPoint delta, BRegion* dirty) 1150{ 1151 BPoint offset = delta - fOutlinesDelta; 1152 fOutlinesDelta = delta; 1153 1154 dirty->Include(fLeftOutlineBorder); 1155 dirty->Include(fRightOutlineBorder); 1156 dirty->Include(fTopOutlineBorder); 1157 dirty->Include(fBottomOutlineBorder); 1158 1159 fOutlineBorderRect.right += offset.x; 1160 fOutlineBorderRect.bottom += offset.y; 1161 1162 fLeftOutlineBorder.bottom += offset.y; 1163 fTopOutlineBorder.right += offset.x; 1164 1165 fRightOutlineBorder.OffsetBy(offset.x, 0.0); 1166 fRightOutlineBorder.bottom += offset.y; 1167 1168 fBottomOutlineBorder.OffsetBy(0.0, offset.y); 1169 fBottomOutlineBorder.right += offset.x; 1170 1171 dirty->Include(fLeftOutlineBorder); 1172 dirty->Include(fRightOutlineBorder); 1173 dirty->Include(fTopOutlineBorder); 1174 dirty->Include(fBottomOutlineBorder); 1175} 1176 1177 1178bool 1179Decorator::_SetSettings(const BMessage& settings, BRegion* updateRegion) 1180{ 1181 return false; 1182} 1183 1184 1185/*! \brief Returns the "footprint" of the entire window, including decorator 1186 1187 This function is required by all subclasses. 1188 1189 \param region Region to be changed to represent the window's screen 1190 footprint 1191*/ 1192void 1193Decorator::_GetFootprint(BRegion *region) 1194{ 1195} 1196 1197 1198void 1199Decorator::_GetOutlineFootprint(BRegion* region) 1200{ 1201 if (region == NULL) 1202 return; 1203 1204 region->Include(fTopOutlineBorder); 1205 region->Include(fLeftOutlineBorder); 1206 region->Include(fRightOutlineBorder); 1207 region->Include(fBottomOutlineBorder); 1208} 1209 1210 1211void 1212Decorator::_InvalidateFootprint() 1213{ 1214 fFootprintValid = false; 1215} 1216 1217 1218void 1219Decorator::_InvalidateBitmaps() 1220{ 1221 for (int32 i = 0; i < fTabList.CountItems(); i++) { 1222 Decorator::Tab* tab = static_cast<Decorator::Tab*>(_TabAt(i)); 1223 for (int32 index = 0; index < 4; index++) { 1224 tab->closeBitmaps[index] = NULL; 1225 tab->minimizeBitmaps[index] = NULL; 1226 tab->zoomBitmaps[index] = NULL; 1227 } 1228 } 1229} 1230