1/* 2 * Copyright 2009-2013 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * DarkWyrm, bpmagic@columbus.rr.com 7 * Adrien Destugues, pulkomandy@gmail.com 8 * John Scipione, jscipione@gmail.com 9 */ 10 11 12/*! Decorator resembling Mac OS 8 and 9 */ 13 14 15#include "MacDecorator.h" 16 17#include <new> 18#include <stdio.h> 19 20#include <GradientLinear.h> 21#include <Point.h> 22#include <View.h> 23 24#include "DesktopSettings.h" 25#include "DrawingEngine.h" 26#include "PatternHandler.h" 27#include "RGBColor.h" 28 29 30//#define DEBUG_DECORATOR 31#ifdef DEBUG_DECORATOR 32# define STRACE(x) printf x 33#else 34# define STRACE(x) ; 35#endif 36 37 38MacDecorAddOn::MacDecorAddOn(image_id id, const char* name) 39 : 40 DecorAddOn(id, name) 41{ 42} 43 44 45Decorator* 46MacDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect, 47 Desktop* desktop) 48{ 49 return new (std::nothrow)MacDecorator(settings, rect, desktop); 50} 51 52 53MacDecorator::MacDecorator(DesktopSettings& settings, BRect frame, 54 Desktop* desktop) 55 : 56 SATDecorator(settings, frame, desktop), 57 fButtonHighColor((rgb_color) { 232, 232, 232, 255 }), 58 fButtonLowColor((rgb_color) { 128, 128, 128, 255 }), 59 fFrameHighColor((rgb_color) { 255, 255, 255, 255 }), 60 fFrameMidColor((rgb_color) { 216, 216, 216, 255 }), 61 fFrameLowColor((rgb_color) { 156, 156, 156, 255 }), 62 fFrameLowerColor((rgb_color) { 0, 0, 0, 255 }), 63 fFocusTextColor(settings.UIColor(B_WINDOW_TEXT_COLOR)), 64 fNonFocusTextColor(settings.UIColor(B_WINDOW_INACTIVE_TEXT_COLOR)) 65{ 66 STRACE(("MacDecorator()\n")); 67 STRACE(("\tFrame (%.1f,%.1f,%.1f,%.1f)\n", 68 frame.left, frame.top, frame.right, frame.bottom)); 69} 70 71 72MacDecorator::~MacDecorator() 73{ 74 STRACE(("~MacDecorator()\n")); 75} 76 77 78// TODO : Add GetSettings 79 80 81void 82MacDecorator::Draw(BRect updateRect) 83{ 84 STRACE(("MacDecorator: Draw(BRect updateRect): ")); 85 updateRect.PrintToStream(); 86 87 // We need to draw a few things: the tab, the borders, 88 // and the buttons 89 fDrawingEngine->SetDrawState(&fDrawState); 90 91 _DrawFrame(updateRect & fBorderRect); 92 _DrawTabs(updateRect & fTitleBarRect); 93} 94 95 96void 97MacDecorator::Draw() 98{ 99 STRACE("MacDecorator::Draw()\n"); 100 fDrawingEngine->SetDrawState(&fDrawState); 101 102 _DrawFrame(fBorderRect); 103 _DrawTabs(fTitleBarRect); 104} 105 106 107// TODO : add GetSizeLimits 108 109 110Decorator::Region 111MacDecorator::RegionAt(BPoint where, int32& tab) const 112{ 113 // Let the base class version identify hits of the buttons and the tab. 114 Region region = Decorator::RegionAt(where, tab); 115 if (region != REGION_NONE) 116 return region; 117 118 // check the resize corner 119 if (fTopTab->look == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(where)) 120 return REGION_RIGHT_BOTTOM_CORNER; 121 122 // hit-test the borders 123 if (!(fTopTab->flags & B_NOT_RESIZABLE) 124 && (fTopTab->look == B_TITLED_WINDOW_LOOK 125 || fTopTab->look == B_FLOATING_WINDOW_LOOK 126 || fTopTab->look == B_MODAL_WINDOW_LOOK) 127 && fBorderRect.Contains(where) && !fFrame.Contains(where)) { 128 return REGION_BOTTOM_BORDER; 129 // TODO: Determine the actual border! 130 } 131 132 return REGION_NONE; 133} 134 135 136bool 137MacDecorator::SetRegionHighlight(Region region, uint8 highlight, 138 BRegion* dirty, int32 tabIndex) 139{ 140 Decorator::Tab* tab 141 = static_cast<Decorator::Tab*>(_TabAt(tabIndex)); 142 if (tab != NULL) { 143 tab->isHighlighted = highlight != 0; 144 // Invalidate the bitmap caches for the close/minimize/zoom button 145 // when the highlight changes. 146 switch (region) { 147 case REGION_CLOSE_BUTTON: 148 if (highlight != RegionHighlight(region)) 149 memset(&tab->closeBitmaps, 0, sizeof(tab->closeBitmaps)); 150 break; 151 152 case REGION_MINIMIZE_BUTTON: 153 if (highlight != RegionHighlight(region)) { 154 memset(&tab->minimizeBitmaps, 0, 155 sizeof(tab->minimizeBitmaps)); 156 } 157 break; 158 159 case REGION_ZOOM_BUTTON: 160 if (highlight != RegionHighlight(region)) 161 memset(&tab->zoomBitmaps, 0, sizeof(tab->zoomBitmaps)); 162 break; 163 164 default: 165 break; 166 } 167 } 168 169 return Decorator::SetRegionHighlight(region, highlight, dirty, tabIndex); 170} 171 172 173void 174MacDecorator::_DoLayout() 175{ 176 STRACE(("MacDecorator: Do Layout\n")); 177 178 // Here we determine the size of every rectangle that we use 179 // internally when we are given the size of the client rectangle. 180 181 const int32 kDefaultBorderWidth = 6; 182 183 bool hasTab = false; 184 185 if (fTopTab) { 186 switch (fTopTab->look) { 187 case B_MODAL_WINDOW_LOOK: 188 fBorderWidth = kDefaultBorderWidth; 189 break; 190 191 case B_TITLED_WINDOW_LOOK: 192 case B_DOCUMENT_WINDOW_LOOK: 193 hasTab = true; 194 fBorderWidth = kDefaultBorderWidth; 195 break; 196 197 case B_FLOATING_WINDOW_LOOK: 198 hasTab = true; 199 fBorderWidth = 3; 200 break; 201 202 case B_BORDERED_WINDOW_LOOK: 203 fBorderWidth = 1; 204 break; 205 206 default: 207 fBorderWidth = 0; 208 } 209 } else 210 fBorderWidth = 0; 211 212 fBorderRect = fFrame.InsetByCopy(-fBorderWidth, -fBorderWidth); 213 214 // calculate our tab rect 215 if (hasTab) { 216 fBorderRect.top += 3; 217 218 font_height fontHeight; 219 fDrawState.Font().GetHeight(fontHeight); 220 221 // TODO the tab is drawn in a fixed height for now 222 fTitleBarRect.Set(fFrame.left - fBorderWidth, 223 fFrame.top - 22, 224 ((fFrame.right - fFrame.left) < 32.0 ? 225 fFrame.left + 32.0 : fFrame.right) + fBorderWidth, 226 fFrame.top - 3); 227 228 for (int32 i = 0; i < fTabList.CountItems(); i++) { 229 Decorator::Tab* tab = fTabList.ItemAt(i); 230 231 tab->tabRect = fTitleBarRect; 232 // TODO actually handle multiple tabs 233 234 tab->zoomRect = fTitleBarRect; 235 tab->zoomRect.left = tab->zoomRect.right - 12; 236 tab->zoomRect.bottom = tab->zoomRect.top + 12; 237 tab->zoomRect.OffsetBy(-4, 4); 238 239 tab->closeRect = tab->zoomRect; 240 tab->minimizeRect = tab->zoomRect; 241 242 tab->closeRect.OffsetTo(fTitleBarRect.left + 4, 243 fTitleBarRect.top + 4); 244 245 tab->zoomRect.OffsetBy(0 - (tab->zoomRect.Width() + 4), 0); 246 if (Title(tab) != NULL && fDrawingEngine != NULL) { 247 tab->truncatedTitle = Title(tab); 248 fDrawingEngine->SetFont(fDrawState.Font()); 249 tab->truncatedTitleLength 250 = (int32)fDrawingEngine->StringWidth(Title(tab), 251 strlen(Title(tab))); 252 253 if (tab->truncatedTitleLength < (tab->zoomRect.left 254 - tab->closeRect.right - 10)) { 255 // start with offset from closerect.right 256 tab->textOffset = int(((tab->zoomRect.left - 5) 257 - (tab->closeRect.right + 5)) / 2); 258 tab->textOffset -= int(tab->truncatedTitleLength / 2); 259 260 // now make it the offset from fTabRect.left 261 tab->textOffset += int(tab->closeRect.right + 5 262 - fTitleBarRect.left); 263 } else 264 tab->textOffset = int(tab->closeRect.right) + 5; 265 } else 266 tab->textOffset = 0; 267 } 268 } else { 269 for (int32 i = 0; i < fTabList.CountItems(); i++) { 270 Decorator::Tab* tab = fTabList.ItemAt(i); 271 272 tab->tabRect.Set(0.0, 0.0, -1.0, -1.0); 273 tab->closeRect.Set(0.0, 0.0, -1.0, -1.0); 274 tab->zoomRect.Set(0.0, 0.0, -1.0, -1.0); 275 tab->minimizeRect.Set(0.0, 0.0, -1.0, -1.0); 276 } 277 } 278} 279 280 281void 282MacDecorator::_DrawFrame(BRect invalid) 283{ 284 if (fTopTab->look == B_NO_BORDER_WINDOW_LOOK) 285 return; 286 287 if (fBorderWidth <= 0) 288 return; 289 290 BRect r = fBorderRect; 291 switch (fTopTab->look) { 292 case B_TITLED_WINDOW_LOOK: 293 case B_DOCUMENT_WINDOW_LOOK: 294 case B_MODAL_WINDOW_LOOK: 295 { 296 if (IsFocus(fTopTab)) { 297 BPoint offset = r.LeftTop(); 298 BPoint pt2 = r.LeftBottom(); 299 300 // Draw the left side of the frame 301 fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); 302 offset.x++; 303 pt2.x++; 304 pt2.y--; 305 306 fDrawingEngine->StrokeLine(offset, pt2, fFrameHighColor); 307 offset.x++; 308 pt2.x++; 309 pt2.y--; 310 311 fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); 312 offset.x++; 313 pt2.x++; 314 fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); 315 offset.x++; 316 pt2.x++; 317 pt2.y--; 318 319 fDrawingEngine->StrokeLine(offset, pt2, fFrameLowColor); 320 offset.x++; 321 offset.y += 2; 322 BPoint topleftpt = offset; 323 pt2.x++; 324 pt2.y--; 325 326 fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); 327 328 offset = r.RightTop(); 329 pt2 = r.RightBottom(); 330 331 // Draw the right side of the frame 332 fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); 333 offset.x--; 334 pt2.x--; 335 336 fDrawingEngine->StrokeLine(offset, pt2, fFrameLowColor); 337 offset.x--; 338 pt2.x--; 339 340 fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); 341 offset.x--; 342 pt2.x--; 343 fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); 344 offset.x--; 345 pt2.x--; 346 347 fDrawingEngine->StrokeLine(offset, pt2, fFrameHighColor); 348 offset.x--; 349 offset.y += 2; 350 BPoint toprightpt = offset; 351 pt2.x--; 352 353 fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); 354 355 // Draw the top side of the frame that is not in the tab 356 if (fTopTab->look == B_MODAL_WINDOW_LOOK) { 357 offset = r.LeftTop(); 358 pt2 = r.RightTop(); 359 360 fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); 361 offset.x++; 362 offset.y++; 363 pt2.x--; 364 pt2.y++; 365 366 fDrawingEngine->StrokeLine(offset, pt2, fFrameHighColor); 367 offset.x++; 368 offset.y++; 369 pt2.x--; 370 pt2.y++; 371 372 fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); 373 offset.x++; 374 offset.y++; 375 pt2.x--; 376 pt2.y++; 377 378 fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); 379 offset.x++; 380 offset.y++; 381 pt2.x--; 382 pt2.y++; 383 384 fDrawingEngine->StrokeLine(offset, pt2, fFrameLowColor); 385 offset.x++; 386 offset.y++; 387 pt2.x--; 388 pt2.y++; 389 390 fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); 391 } else { 392 // Some odd stuff here where the title bar is melded into the 393 // window border so that the sides are drawn into the title 394 // so we draw this bottom up 395 offset = topleftpt; 396 pt2 = toprightpt; 397 398 fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); 399 offset.y--; 400 offset.x++; 401 pt2.y--; 402 403 fDrawingEngine->StrokeLine(offset, pt2, fFrameLowColor); 404 } 405 406 // Draw the bottom side of the frame 407 offset = r.LeftBottom(); 408 pt2 = r.RightBottom(); 409 410 fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); 411 offset.x++; 412 offset.y--; 413 pt2.x--; 414 pt2.y--; 415 416 fDrawingEngine->StrokeLine(offset, pt2, fFrameLowColor); 417 offset.x++; 418 offset.y--; 419 pt2.x--; 420 pt2.y--; 421 422 fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); 423 offset.x++; 424 offset.y--; 425 pt2.x--; 426 pt2.y--; 427 428 fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); 429 offset.x++; 430 offset.y--; 431 pt2.x--; 432 pt2.y--; 433 434 fDrawingEngine->StrokeLine(offset, pt2, fFrameHighColor); 435 offset.x += 2; 436 offset.y--; 437 pt2.x--; 438 pt2.y--; 439 440 fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); 441 offset.y--; 442 pt2.x--; 443 pt2.y--; 444 } else { 445 r.top -= 3; 446 RGBColor inactive(82, 82, 82); 447 448 fDrawingEngine->StrokeLine(r.LeftTop(), r.LeftBottom(), 449 inactive); 450 fDrawingEngine->StrokeLine(r.RightTop(), r.RightBottom(), 451 inactive); 452 fDrawingEngine->StrokeLine(r.LeftBottom(), r.RightBottom(), 453 inactive); 454 455 for (int i = 0; i < 4; i++) { 456 r.InsetBy(1, 1); 457 fDrawingEngine->StrokeLine(r.LeftTop(), r.LeftBottom(), 458 fFrameMidColor); 459 fDrawingEngine->StrokeLine(r.RightTop(), r.RightBottom(), 460 fFrameMidColor); 461 fDrawingEngine->StrokeLine(r.LeftBottom(), r.RightBottom(), 462 fFrameMidColor); 463 fDrawingEngine->StrokeLine(r.LeftTop(), r.RightTop(), 464 fFrameMidColor); 465 } 466 467 r.InsetBy(1, 1); 468 fDrawingEngine->StrokeLine(r.LeftTop(), r.LeftBottom(), 469 inactive); 470 fDrawingEngine->StrokeLine(r.RightTop(), r.RightBottom(), 471 inactive); 472 fDrawingEngine->StrokeLine(r.LeftBottom(), r.RightBottom(), 473 inactive); 474 fDrawingEngine->StrokeLine(r.LeftTop(), r.RightTop(), 475 inactive); 476 } 477 break; 478 } 479 case B_BORDERED_WINDOW_LOOK: 480 fDrawingEngine->StrokeRect(r, fFrameMidColor); 481 break; 482 483 default: 484 // don't draw a border frame 485 break; 486 } 487} 488 489 490void 491MacDecorator::_DrawTab(Decorator::Tab* tab, BRect invalid) 492{ 493 // If a window has a tab, this will draw it and any buttons which are 494 // in it. 495 if (!tab->tabRect.IsValid() || !invalid.Intersects(tab->tabRect)) 496 return; 497 498 BRect rect(tab->tabRect); 499 fDrawingEngine->SetHighColor(RGBColor(fFrameMidColor)); 500 fDrawingEngine->FillRect(rect, fFrameMidColor); 501 502 if (IsFocus(tab)) { 503 fDrawingEngine->StrokeLine(rect.LeftTop(), rect.RightTop(), 504 fFrameLowerColor); 505 fDrawingEngine->StrokeLine(rect.LeftTop(), rect.LeftBottom(), 506 fFrameLowerColor); 507 fDrawingEngine->StrokeLine(rect.RightBottom(), rect.RightTop(), 508 fFrameLowerColor); 509 510 rect.InsetBy(1, 1); 511 rect.bottom++; 512 513 fDrawingEngine->StrokeLine(rect.LeftTop(), rect.RightTop(), 514 fFrameHighColor); 515 fDrawingEngine->StrokeLine(rect.LeftTop(), rect.LeftBottom(), 516 fFrameHighColor); 517 fDrawingEngine->StrokeLine(rect.RightBottom(), rect.RightTop(), 518 fFrameLowColor); 519 520 // Draw the neat little lines on either side of the title if there's 521 // room 522 float left; 523 if ((tab->flags & B_NOT_CLOSABLE) == 0) 524 left = tab->closeRect.right; 525 else 526 left = tab->tabRect.left; 527 528 float right; 529 if ((tab->flags & B_NOT_ZOOMABLE) == 0) 530 right = tab->zoomRect.left; 531 else if ((tab->flags & B_NOT_MINIMIZABLE) == 0) 532 right = tab->minimizeRect.left; 533 else 534 right = tab->tabRect.right; 535 536 if (tab->tabRect.left + tab->textOffset > left + 5) { 537 RGBColor dark(115, 115, 115); 538 539 // Left side 540 541 BPoint offset(left + 5, tab->closeRect.top); 542 BPoint pt2(tab->tabRect.left + tab->textOffset - 5, 543 tab->closeRect.top); 544 545 fDrawState.SetHighColor(RGBColor(fFrameHighColor)); 546 for (int32 i = 0; i < 6; i++) { 547 fDrawingEngine->StrokeLine(offset, pt2, 548 fDrawState.HighColor()); 549 offset.y += 2; 550 pt2.y += 2; 551 } 552 553 offset.Set(left + 6, tab->closeRect.top + 1); 554 pt2.Set(tab->tabRect.left + tab->textOffset - 4, 555 tab->closeRect.top + 1); 556 557 fDrawState.SetHighColor(dark); 558 for (int32 i = 0; i < 6; i++) { 559 fDrawingEngine->StrokeLine(offset, pt2, 560 fDrawState.HighColor()); 561 offset.y += 2; 562 pt2.y += 2; 563 } 564 565 // Right side 566 567 offset.Set(tab->tabRect.left + tab->textOffset 568 + tab->truncatedTitleLength + 3, tab->zoomRect.top); 569 pt2.Set(right - 8, tab->zoomRect.top); 570 571 if (offset.x < pt2.x) { 572 fDrawState.SetHighColor(RGBColor(fFrameHighColor)); 573 for (int32 i = 0; i < 6; i++) { 574 fDrawingEngine->StrokeLine(offset, pt2, 575 fDrawState.HighColor()); 576 offset.y += 2; 577 pt2.y += 2; 578 } 579 580 offset.Set(tab->tabRect.left + tab->textOffset 581 + tab->truncatedTitleLength + 4, tab->zoomRect.top + 1); 582 pt2.Set(right - 7, tab->zoomRect.top + 1); 583 584 fDrawState.SetHighColor(dark); 585 for(int32 i = 0; i < 6; i++) { 586 fDrawingEngine->StrokeLine(offset, pt2, 587 fDrawState.HighColor()); 588 offset.y += 2; 589 pt2.y += 2; 590 } 591 } 592 } 593 594 _DrawButtons(tab, rect); 595 } else { 596 RGBColor inactive(82, 82, 82); 597 // Not focused - Just draw a plain light grey area with the title 598 // in the middle 599 fDrawingEngine->StrokeLine(rect.LeftTop(), rect.RightTop(), 600 inactive); 601 fDrawingEngine->StrokeLine(rect.LeftTop(), rect.LeftBottom(), 602 inactive); 603 fDrawingEngine->StrokeLine(rect.RightBottom(), rect.RightTop(), 604 inactive); 605 } 606 607 _DrawTitle(tab, tab->tabRect); 608} 609 610 611void 612MacDecorator::_DrawButtons(Decorator::Tab* tab, const BRect& invalid) 613{ 614 if ((tab->flags & B_NOT_CLOSABLE) == 0 615 && invalid.Intersects(tab->closeRect)) { 616 _DrawClose(tab, false, tab->closeRect); 617 } 618 if ((tab->flags & B_NOT_MINIMIZABLE) == 0 619 && invalid.Intersects(tab->minimizeRect)) { 620 _DrawMinimize(tab, false, tab->minimizeRect); 621 } 622 if ((tab->flags & B_NOT_ZOOMABLE) == 0 623 && invalid.Intersects(tab->zoomRect)) { 624 _DrawZoom(tab, false, tab->zoomRect); 625 } 626} 627 628 629void 630MacDecorator::_DrawTitle(Decorator::Tab* tab, BRect rect) 631{ 632 fDrawingEngine->SetHighColor(IsFocus(tab) 633 ? fFocusTextColor : fNonFocusTextColor); 634 635 fDrawingEngine->SetLowColor(fFrameMidColor); 636 637 tab->truncatedTitle = Title(tab); 638 fDrawState.Font().TruncateString(&tab->truncatedTitle, B_TRUNCATE_END, 639 (tab->zoomRect.left - 5) - (tab->closeRect.right + 5)); 640 fDrawingEngine->SetFont(fDrawState.Font()); 641 642 fDrawingEngine->DrawString(tab->truncatedTitle, tab->truncatedTitle.Length(), 643 BPoint(fTitleBarRect.left + tab->textOffset, 644 tab->closeRect.bottom - 1)); 645} 646 647 648void 649MacDecorator::_DrawClose(Decorator::Tab* tab, bool direct, BRect r) 650{ 651 _DrawButton(tab, direct, r, tab->closePressed); 652} 653 654 655void 656MacDecorator::_DrawZoom(Decorator::Tab* tab, bool direct, BRect rect) 657{ 658 _DrawButton(tab, direct, rect, tab->zoomPressed); 659 660 rect.top++; 661 rect.left++; 662 rect.bottom = rect.top + 6; 663 rect.right = rect.left + 6; 664 665 fDrawState.SetHighColor(RGBColor(33, 33, 33)); 666 fDrawingEngine->StrokeRect(rect, fDrawState.HighColor()); 667} 668 669 670void 671MacDecorator::_DrawMinimize(Decorator::Tab* tab, bool direct, BRect rect) 672{ 673 _DrawButton(tab, direct, rect, tab->minimizePressed); 674 675 rect.InsetBy(1, 5); 676 677 fDrawState.SetHighColor(RGBColor(33, 33, 33)); 678 fDrawingEngine->StrokeRect(rect, fDrawState.HighColor()); 679} 680 681 682void 683MacDecorator::_SetTitle(Tab* tab, const char* string, BRegion* updateRegion) 684{ 685 // TODO: we could be much smarter about the update region 686 // TODO may this change the other tabs too ? (to make space for a longer 687 // title ?) 688 689 BRect rect = TabRect(tab); 690 691 _DoLayout(); 692 693 if (updateRegion == NULL) 694 return; 695 696 rect = rect | TabRect(tab); 697 698 rect.bottom++; 699 // the border will look differently when the title is adjacent 700 701 updateRegion->Include(rect); 702} 703 704 705// TODO : _SetFocus 706 707 708void 709MacDecorator::_MoveBy(BPoint offset) 710{ 711 // Move all internal rectangles the appropriate amount 712 for (int32 i = 0; i < fTabList.CountItems(); i++) { 713 Decorator::Tab* tab = fTabList.ItemAt(i); 714 tab->zoomRect.OffsetBy(offset); 715 tab->minimizeRect.OffsetBy(offset); 716 tab->closeRect.OffsetBy(offset); 717 tab->tabRect.OffsetBy(offset); 718 } 719 720 fFrame.OffsetBy(offset); 721 fTitleBarRect.OffsetBy(offset); 722 fResizeRect.OffsetBy(offset); 723 fBorderRect.OffsetBy(offset); 724} 725 726 727void 728MacDecorator::_ResizeBy(BPoint offset, BRegion* dirty) 729{ 730 // Move all internal rectangles the appropriate amount 731 fFrame.right += offset.x; 732 fFrame.bottom += offset.y; 733 734 fTitleBarRect.right += offset.x; 735 fBorderRect.right += offset.x; 736 fBorderRect.bottom += offset.y; 737 // fZoomRect.OffsetBy(offset.x, 0); 738 // fMinimizeRect.OffsetBy(offset.x, 0); 739 if (dirty) { 740 dirty->Include(fTitleBarRect); 741 dirty->Include(fBorderRect); 742 } 743 744 // TODO probably some other layouting stuff here 745 _DoLayout(); 746} 747 748 749// TODO : _SetSettings 750 751 752Decorator::Tab* 753MacDecorator::_AllocateNewTab() 754{ 755 Decorator::Tab* tab = new(std::nothrow) Decorator::Tab; 756 if (tab == NULL) 757 return NULL; 758 759 // Set appropriate colors based on the current focus value. In this case, 760 // each decorator defaults to not having the focus. 761 _SetFocus(tab); 762 return tab; 763} 764 765 766bool 767MacDecorator::_AddTab(DesktopSettings& settings, int32 index, 768 BRegion* updateRegion) 769{ 770 _UpdateFont(settings); 771 772 _DoLayout(); 773 if (updateRegion != NULL) 774 updateRegion->Include(fTitleBarRect); 775 return true; 776} 777 778 779bool 780MacDecorator::_RemoveTab(int32 index, BRegion* updateRegion) 781{ 782 BRect oldTitle = fTitleBarRect; 783 _DoLayout(); 784 if (updateRegion != NULL) { 785 updateRegion->Include(oldTitle); 786 updateRegion->Include(fTitleBarRect); 787 } 788 return true; 789} 790 791 792bool 793MacDecorator::_MoveTab(int32 from, int32 to, bool isMoving, 794 BRegion* updateRegion) 795{ 796 return false; 797 798#if 0 799 MacDecorator::Tab* toTab = _TabAt(to); 800 if (toTab == NULL) 801 return false; 802 803 if (from < to) { 804 fOldMovingTab.OffsetBy(toTab->tabRect.Width(), 0); 805 toTab->tabRect.OffsetBy(-fOldMovingTab.Width(), 0); 806 } else { 807 fOldMovingTab.OffsetBy(-toTab->tabRect.Width(), 0); 808 toTab->tabRect.OffsetBy(fOldMovingTab.Width(), 0); 809 } 810 811 toTab->tabOffset = uint32(toTab->tabRect.left - fLeftBorder.left); 812 _LayoutTabItems(toTab, toTab->tabRect); 813 814 _CalculateTabsRegion(); 815 816 if (updateRegion != NULL) 817 updateRegion->Include(fTitleBarRect); 818 return true; 819#endif 820} 821 822 823void 824MacDecorator::_GetFootprint(BRegion* region) 825{ 826 // This function calculates the decorator's footprint in coordinates 827 // relative to the view. This is most often used to set a Window 828 // object's visible region. 829 if (!region) 830 return; 831 832 region->MakeEmpty(); 833 834 if (fTopTab->look == B_NO_BORDER_WINDOW_LOOK) 835 return; 836 837 region->Set(fBorderRect); 838 region->Exclude(fFrame); 839 840 if (fTopTab->look == B_BORDERED_WINDOW_LOOK) 841 return; 842 region->Include(fTitleBarRect); 843} 844 845 846void 847MacDecorator::_UpdateFont(DesktopSettings& settings) 848{ 849 ServerFont font; 850 if (fTopTab && fTopTab->look == B_FLOATING_WINDOW_LOOK) 851 settings.GetDefaultPlainFont(font); 852 else 853 settings.GetDefaultBoldFont(font); 854 855 font.SetFlags(B_FORCE_ANTIALIASING); 856 font.SetSpacing(B_STRING_SPACING); 857 fDrawState.SetFont(font); 858} 859 860 861// #pragma mark - Private methods 862 863 864// Draw a mac-style button 865void 866MacDecorator::_DrawButton(Decorator::Tab* tab, bool direct, BRect r, 867 bool down) 868{ 869 BRect rect(r); 870 871 BPoint offset(r.LeftTop()), pt2(r.RightTop()); 872 873 // Topleft dark grey border 874 pt2.x--; 875 fDrawingEngine->SetHighColor(RGBColor(136, 136, 136)); 876 fDrawingEngine->StrokeLine(offset, pt2); 877 878 pt2 = r.LeftBottom(); 879 pt2.y--; 880 fDrawingEngine->StrokeLine(offset, pt2); 881 882 // Bottomright white border 883 offset = r.RightBottom(); 884 pt2 = r.RightTop(); 885 pt2.y++; 886 fDrawingEngine->SetHighColor(RGBColor(255, 255, 255)); 887 fDrawingEngine->StrokeLine(offset, pt2); 888 889 pt2 = r.LeftBottom(); 890 pt2.x++; 891 fDrawingEngine->StrokeLine(offset, pt2); 892 893 // Black outline 894 rect.InsetBy(1, 1); 895 fDrawingEngine->SetHighColor(RGBColor(33, 33, 33)); 896 fDrawingEngine->StrokeRect(rect); 897 898 // Double-shaded button 899 rect.InsetBy(1, 1); 900 fDrawingEngine->SetHighColor(RGBColor(140, 140, 140)); 901 fDrawingEngine->StrokeLine(rect.RightBottom(), rect.RightTop()); 902 fDrawingEngine->StrokeLine(rect.RightBottom(), rect.LeftBottom()); 903 fDrawingEngine->SetHighColor(RGBColor(206, 206, 206)); 904 fDrawingEngine->StrokeLine(rect.LeftBottom(), rect.LeftTop()); 905 fDrawingEngine->StrokeLine(rect.LeftTop(), rect.RightTop()); 906 fDrawingEngine->SetHighColor(RGBColor(255, 255, 255)); 907 fDrawingEngine->StrokeLine(rect.LeftTop(), rect.LeftTop()); 908 909 rect.InsetBy(1, 1); 910 _DrawBlendedRect(fDrawingEngine, rect, !down); 911} 912 913 914/*! \brief Draws a rectangle with a gradient. 915 \param down The rectangle should be drawn recessed or not 916*/ 917void 918MacDecorator::_DrawBlendedRect(DrawingEngine* engine, BRect rect, 919 bool down/*, bool focus*/) 920{ 921 // figure out which colors to use 922 rgb_color startColor, endColor; 923 if (down) { 924 startColor = fButtonLowColor; 925 endColor = fFrameHighColor; 926 } else { 927 startColor = fButtonHighColor; 928 endColor = fFrameLowerColor; 929 } 930 931 // fill 932 BGradientLinear gradient; 933 gradient.SetStart(rect.LeftTop()); 934 gradient.SetEnd(rect.RightBottom()); 935 gradient.AddColor(startColor, 0); 936 gradient.AddColor(endColor, 255); 937 938 engine->FillRect(rect, gradient); 939} 940 941 942// #pragma mark - DecorAddOn 943 944 945extern "C" DecorAddOn* 946instantiate_decor_addon(image_id id, const char* name) 947{ 948 return new (std::nothrow)MacDecorAddOn(id, name); 949} 950