1/* 2 * Copyright 2009-2010, Haiku. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7/*! Decorator looking like Windows 95 */ 8 9 10#include "WinDecorator.h" 11 12#include <new> 13#include <stdio.h> 14 15#include <Point.h> 16#include <View.h> 17 18#include "DesktopSettings.h" 19#include "DrawingEngine.h" 20#include "PatternHandler.h" 21#include "RGBColor.h" 22 23 24//#define DEBUG_DECORATOR 25#ifdef DEBUG_DECORATOR 26# define STRACE(x) printf x 27#else 28# define STRACE(x) ; 29#endif 30 31 32WinDecorAddOn::WinDecorAddOn(image_id id, const char* name) 33 : 34 DecorAddOn(id, name) 35{ 36 37} 38 39 40Decorator* 41WinDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect, 42 window_look look, uint32 flags) 43{ 44 return new (std::nothrow)WinDecorator(settings, rect, look, flags); 45} 46 47 48WinDecorator::WinDecorator(DesktopSettings& settings, BRect rect, 49 window_look look, uint32 flags) 50 : 51 Decorator(settings, rect, look, flags) 52{ 53 _UpdateFont(settings); 54 55 // common colors to both focus and non focus state 56 frame_highcol = (rgb_color){ 255, 255, 255, 255 }; 57 frame_midcol = (rgb_color){ 216, 216, 216, 255 }; 58 frame_lowcol = (rgb_color){ 110, 110, 110, 255 }; 59 frame_lowercol = (rgb_color){ 0, 0, 0, 255 }; 60 61 // state based colors 62 fFocusTabColor = settings.UIColor(B_WINDOW_TAB_COLOR); 63 fFocusTextColor = settings.UIColor(B_WINDOW_TEXT_COLOR); 64 fNonFocusTabColor = settings.UIColor(B_WINDOW_INACTIVE_TAB_COLOR); 65 fNonFocusTextColor = settings.UIColor(B_WINDOW_INACTIVE_TEXT_COLOR); 66 67 // Set appropriate colors based on the current focus value. In this case, 68 // each decorator defaults to not having the focus. 69 _SetFocus(); 70 71 // Do initial decorator setup 72 _DoLayout(); 73 74 textoffset=5; 75 76 STRACE(("WinDecorator()\n")); 77} 78 79 80WinDecorator::~WinDecorator() 81{ 82 STRACE(("~WinDecorator()\n")); 83} 84 85 86// TODO : Add GetSettings 87 88 89void 90WinDecorator::Draw(BRect update) 91{ 92 STRACE(("WinDecorator::Draw(): ")); update.PrintToStream(); 93 94 fDrawingEngine->SetDrawState(&fDrawState); 95 96 _DrawFrame(update); 97 _DrawTab(update); 98} 99 100 101void 102WinDecorator::Draw() 103{ 104 STRACE(("WinDecorator::Draw()\n")); 105 fDrawingEngine->SetDrawState(&fDrawState); 106 107 _DrawFrame(fBorderRect); 108 _DrawTab(fTabRect); 109} 110 111 112// TODO : add GetSizeLimits 113 114 115Decorator::Region 116WinDecorator::RegionAt(BPoint where) const 117{ 118 // Let the base class version identify hits of the buttons and the tab. 119 Region region = Decorator::RegionAt(where); 120 if (region != REGION_NONE) 121 return region; 122 123 // check the resize corner 124 if (fLook == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(where)) 125 return REGION_RIGHT_BOTTOM_CORNER; 126 127 // hit-test the borders 128 if (!(fFlags & B_NOT_RESIZABLE) 129 && (fLook == B_TITLED_WINDOW_LOOK 130 || fLook == B_FLOATING_WINDOW_LOOK 131 || fLook == B_MODAL_WINDOW_LOOK) 132 && fBorderRect.Contains(where) && !fFrame.Contains(where)) { 133 return REGION_BOTTOM_BORDER; 134 // TODO: Determine the actual border! 135 } 136 137 return REGION_NONE; 138} 139 140 141void 142WinDecorator::_DoLayout() 143{ 144 STRACE(("WinDecorator()::_DoLayout()\n")); 145 146 bool hasTab = false; 147 148 fBorderRect=fFrame; 149 fTabRect=fFrame; 150 151 switch (Look()) { 152 case B_MODAL_WINDOW_LOOK: 153 fBorderRect.InsetBy(-4, -4); 154 break; 155 156 case B_TITLED_WINDOW_LOOK: 157 case B_DOCUMENT_WINDOW_LOOK: 158 hasTab = true; 159 fBorderRect.InsetBy(-4, -4); 160 break; 161 case B_FLOATING_WINDOW_LOOK: 162 hasTab = true; 163 break; 164 165 case B_BORDERED_WINDOW_LOOK: 166 fBorderRect.InsetBy(-1, -1); 167 break; 168 169 default: 170 break; 171 } 172 173 if (hasTab) { 174 fBorderRect.top -= 19; 175 176 fTabRect.top -= 19; 177 fTabRect.bottom=fTabRect.top+19; 178 179 fZoomRect=fTabRect; 180 fZoomRect.top+=3; 181 fZoomRect.right-=3; 182 fZoomRect.bottom-=3; 183 fZoomRect.left=fZoomRect.right-15; 184 185 fCloseRect=fZoomRect; 186 fZoomRect.OffsetBy(0-fZoomRect.Width()-3,0); 187 188 fMinimizeRect=fZoomRect; 189 fMinimizeRect.OffsetBy(0-fZoomRect.Width()-1,0); 190 } else { 191 fTabRect.Set(0.0, 0.0, -1.0, -1.0); 192 fCloseRect.Set(0.0, 0.0, -1.0, -1.0); 193 fZoomRect.Set(0.0, 0.0, -1.0, -1.0); 194 fMinimizeRect.Set(0.0, 0.0, -1.0, -1.0); 195 } 196} 197 198 199void 200WinDecorator::_DrawFrame(BRect rect) 201{ 202 if (fLook == B_NO_BORDER_WINDOW_LOOK) 203 return; 204 205 if (fBorderRect == fFrame) 206 return; 207 208 BRect r = fBorderRect; 209 210 fDrawingEngine->SetHighColor(frame_lowercol); 211 fDrawingEngine->StrokeRect(r); 212 213 if (fLook == B_BORDERED_WINDOW_LOOK) 214 return; 215 216 BPoint pt; 217 218 pt=r.RightTop(); 219 pt.x--; 220 fDrawingEngine->StrokeLine(r.LeftTop(),pt,frame_midcol); 221 pt=r.LeftBottom(); 222 pt.y--; 223 fDrawingEngine->StrokeLine(r.LeftTop(),pt,frame_midcol); 224 225 fDrawingEngine->StrokeLine(r.RightTop(),r.RightBottom(),frame_lowercol); 226 fDrawingEngine->StrokeLine(r.LeftBottom(),r.RightBottom(),frame_lowercol); 227 228 r.InsetBy(1,1); 229 pt=r.RightTop(); 230 pt.x--; 231 fDrawingEngine->StrokeLine(r.LeftTop(),pt,frame_highcol); 232 pt=r.LeftBottom(); 233 pt.y--; 234 fDrawingEngine->StrokeLine(r.LeftTop(),pt,frame_highcol); 235 236 fDrawingEngine->StrokeLine(r.RightTop(),r.RightBottom(),frame_lowcol); 237 fDrawingEngine->StrokeLine(r.LeftBottom(),r.RightBottom(),frame_lowcol); 238 239 r.InsetBy(1,1); 240 fDrawingEngine->StrokeRect(r,frame_midcol); 241 r.InsetBy(1,1); 242 fDrawingEngine->StrokeRect(r,frame_midcol); 243} 244 245 246void 247WinDecorator::_DrawTab(BRect invalid) 248{ 249 // If a window has a tab, this will draw it and any buttons which are 250 // in it. 251 if (!fTabRect.IsValid() || !invalid.Intersects(fTabRect) || fLook==B_NO_BORDER_WINDOW_LOOK) 252 return; 253 254 fDrawingEngine->FillRect(fTabRect,tab_highcol); 255 256 _DrawTitle(fTabRect); 257 258 // Draw the buttons if we're supposed to 259 // TODO : we should still draw the buttons if they are disabled, but grey them out 260 if (!(fFlags & B_NOT_CLOSABLE) && invalid.Intersects(fCloseRect)) 261 _DrawClose(fCloseRect); 262 if (!(fFlags & B_NOT_ZOOMABLE) && invalid.Intersects(fZoomRect)) 263 _DrawZoom(fZoomRect); 264} 265 266 267void 268WinDecorator::_DrawClose(BRect r) 269{ 270 // Just like DrawZoom, but for a close button 271 _DrawBeveledRect(r,GetClose()); 272 273 // Draw the X 274 275 BRect rect(r); 276 rect.InsetBy(4,4); 277 rect.right--; 278 rect.top--; 279 280 if (GetClose()) 281 rect.OffsetBy(1,1); 282 283 fDrawingEngine->SetHighColor(RGBColor(0,0,0)); 284 fDrawingEngine->StrokeLine(rect.LeftTop(),rect.RightBottom()); 285 fDrawingEngine->StrokeLine(rect.RightTop(),rect.LeftBottom()); 286 rect.OffsetBy(1,0); 287 fDrawingEngine->StrokeLine(rect.LeftTop(),rect.RightBottom()); 288 fDrawingEngine->StrokeLine(rect.RightTop(),rect.LeftBottom()); 289} 290 291 292void 293WinDecorator::_DrawTitle(BRect r) 294{ 295 //fDrawingEngine->SetDrawingMode(B_OP_OVER); 296 fDrawingEngine->SetHighColor(textcol); 297 fDrawingEngine->SetLowColor(IsFocus()?fFocusTabColor:fNonFocusTabColor); 298 299 fTruncatedTitle = Title(); 300 fDrawState.Font().TruncateString(&fTruncatedTitle, B_TRUNCATE_END, 301 ((fZoomRect.IsValid() ? fZoomRect.left : 302 fCloseRect.IsValid() ? fCloseRect.left : fTabRect.right) - 5) 303 - (fTabRect.left + textoffset)); 304 fTruncatedTitleLength = fTruncatedTitle.Length(); 305 fDrawingEngine->SetFont(fDrawState.Font()); 306 307 fDrawingEngine->DrawString(fTruncatedTitle,fTruncatedTitleLength, 308 BPoint(fTabRect.left+textoffset,fCloseRect.bottom-1)); 309 310 //fDrawingEngine->SetDrawingMode(B_OP_COPY); 311} 312 313 314void 315WinDecorator::_DrawZoom(BRect r) 316{ 317 _DrawBeveledRect(r,GetZoom()); 318 319 // Draw the Zoom box 320 321 BRect rect(r); 322 rect.InsetBy(2,2); 323 rect.InsetBy(1,0); 324 rect.bottom--; 325 rect.right--; 326 327 if (GetZoom()) 328 rect.OffsetBy(1,1); 329 330 fDrawingEngine->SetHighColor(RGBColor(0,0,0)); 331 fDrawingEngine->StrokeRect(rect); 332 rect.InsetBy(1,1); 333 fDrawingEngine->StrokeLine(rect.LeftTop(),rect.RightTop()); 334 335} 336 337 338void 339WinDecorator::_DrawMinimize(BRect r) 340{ 341 // Just like DrawZoom, but for a Minimize button 342 _DrawBeveledRect(r,GetMinimize()); 343 344 fDrawingEngine->SetHighColor(textcol); 345 BRect rect(r.left+5,r.bottom-4,r.right-5,r.bottom-3); 346 if(GetMinimize()) 347 rect.OffsetBy(1,1); 348 349 fDrawingEngine->SetHighColor(RGBColor(0,0,0)); 350 fDrawingEngine->StrokeRect(rect); 351} 352 353 354void 355WinDecorator::_SetTitle(const char* string, BRegion* updateRegion) 356{ 357 // TODO: we could be much smarter about the update region 358 359 BRect rect = TabRect(); 360 361 if (updateRegion == NULL) 362 return; 363 364 BRect updatedRect = TabRect(); 365 if (rect.left > updatedRect.left) 366 rect.left = updatedRect.left; 367 if (rect.right < updatedRect.right) 368 rect.right = updatedRect.right; 369 370 updateRegion->Include(rect); 371} 372 373 374void 375WinDecorator::_FontsChanged(DesktopSettings& settings, 376 BRegion* updateRegion) 377{ 378 // get previous extent 379 if (updateRegion != NULL) 380 updateRegion->Include(&GetFootprint()); 381 382 _UpdateFont(settings); 383 _DoLayout(); 384 385 _InvalidateFootprint(); 386 if (updateRegion != NULL) 387 updateRegion->Include(&GetFootprint()); 388} 389 390 391void 392WinDecorator::_SetLook(DesktopSettings& settings, window_look look, 393 BRegion* updateRegion) 394{ 395 // TODO: we could be much smarter about the update region 396 397 // get previous extent 398 if (updateRegion != NULL) 399 updateRegion->Include(&GetFootprint()); 400 401 fLook = look; 402 403 _UpdateFont(settings); 404 _DoLayout(); 405 406 _InvalidateFootprint(); 407 if (updateRegion != NULL) 408 updateRegion->Include(&GetFootprint()); 409} 410 411 412void 413WinDecorator::_SetFlags(uint32 flags, BRegion* updateRegion) 414{ 415 // TODO: we could be much smarter about the update region 416 417 // get previous extent 418 if (updateRegion != NULL) 419 updateRegion->Include(&GetFootprint()); 420 421 _DoLayout(); 422 423 _InvalidateFootprint(); 424 if (updateRegion != NULL) 425 updateRegion->Include(&GetFootprint()); 426} 427 428 429void 430WinDecorator::_SetFocus(void) 431{ 432 // SetFocus() performs necessary duties for color swapping and 433 // other things when a window is deactivated or activated. 434 435 if (IsFocus()) { 436// tab_highcol.SetColor(100,100,255); 437// tab_lowcol.SetColor(40,0,255); 438 tab_highcol=fFocusTabColor; 439 textcol=fFocusTextColor; 440 } else { 441// tab_highcol.SetColor(220,220,220); 442// tab_lowcol.SetColor(128,128,128); 443 tab_highcol=fNonFocusTabColor; 444 textcol=fNonFocusTextColor; 445 } 446} 447 448 449void 450WinDecorator::_MoveBy(BPoint pt) 451{ 452 // Move all internal rectangles the appropriate amount 453 fFrame.OffsetBy(pt); 454 fCloseRect.OffsetBy(pt); 455 fTabRect.OffsetBy(pt); 456 fBorderRect.OffsetBy(pt); 457 fZoomRect.OffsetBy(pt); 458 fMinimizeRect.OffsetBy(pt); 459} 460 461 462void 463WinDecorator::_ResizeBy(BPoint offset, BRegion* dirty) 464{ 465 // Move all internal rectangles the appropriate amount 466 fFrame.right += offset.x; 467 fFrame.bottom += offset.y; 468 469 fTabRect.right += offset.x; 470 fBorderRect.right += offset.x; 471 fBorderRect.bottom += offset.y; 472 // fZoomRect.OffsetBy(offset.x, 0); 473 // fMinimizeRect.OffsetBy(offset.x, 0); 474 if (dirty) { 475 dirty->Include(fTabRect); 476 dirty->Include(fBorderRect); 477 } 478 479 480 // TODO probably some other layouting stuff here 481 _DoLayout(); 482} 483 484 485// TODO : _SetSettings 486 487 488void 489WinDecorator::_GetFootprint(BRegion* region) 490{ 491 // This function calculates the decorator's footprint in coordinates 492 // relative to the view. This is most often used to set a Window 493 // object's visible region. 494 if (!region) 495 return; 496 497 region->MakeEmpty(); 498 499 if (fLook == B_NO_BORDER_WINDOW_LOOK) 500 return; 501 502 region->Set(fBorderRect); 503 region->Include(fTabRect); 504 region->Exclude(fFrame); 505} 506 507 508void 509WinDecorator::_UpdateFont(DesktopSettings& settings) 510{ 511 ServerFont font; 512 if (fLook == B_FLOATING_WINDOW_LOOK) 513 settings.GetDefaultPlainFont(font); 514 else 515 settings.GetDefaultBoldFont(font); 516 517 font.SetFlags(B_FORCE_ANTIALIASING); 518 font.SetSpacing(B_STRING_SPACING); 519 fDrawState.SetFont(font); 520} 521 522 523void 524WinDecorator::_DrawBeveledRect(BRect r, bool down) 525{ 526 RGBColor higher; 527 RGBColor high; 528 RGBColor mid; 529 RGBColor low; 530 RGBColor lower; 531 532 if (down) { 533 lower.SetColor(255,255,255); 534 low.SetColor(216,216,216); 535 mid.SetColor(192,192,192); 536 high.SetColor(128,128,128); 537 higher.SetColor(0,0,0); 538 } else { 539 higher.SetColor(255,255,255); 540 high.SetColor(216,216,216); 541 mid.SetColor(192,192,192); 542 low.SetColor(128,128,128); 543 lower.SetColor(0,0,0); 544 } 545 546 BRect rect(r); 547 BPoint pt; 548 549 // Top highlight 550 fDrawingEngine->SetHighColor(higher); 551 fDrawingEngine->StrokeLine(rect.LeftTop(),rect.RightTop()); 552 553 // Left highlight 554 fDrawingEngine->StrokeLine(rect.LeftTop(),rect.LeftBottom()); 555 556 // Right shading 557 pt=rect.RightTop(); 558 pt.y++; 559 fDrawingEngine->StrokeLine(pt,rect.RightBottom(),lower); 560 561 // Bottom shading 562 pt=rect.LeftBottom(); 563 pt.x++; 564 fDrawingEngine->StrokeLine(pt,rect.RightBottom(),lower); 565 566 rect.InsetBy(1,1); 567 568 // Top inside highlight 569 fDrawingEngine->StrokeLine(rect.LeftTop(),rect.RightTop()); 570 571 // Left inside highlight 572 fDrawingEngine->StrokeLine(rect.LeftTop(),rect.LeftBottom()); 573 574 // Right inside shading 575 pt=rect.RightTop(); 576 pt.y++; 577 fDrawingEngine->StrokeLine(pt,rect.RightBottom(),lower); 578 579 // Bottom inside shading 580 pt=rect.LeftBottom(); 581 pt.x++; 582 fDrawingEngine->StrokeLine(pt,rect.RightBottom(),lower); 583 584 rect.InsetBy(1,1); 585 586 fDrawingEngine->FillRect(rect,mid); 587} 588 589 590// #pragma mark - 591 592 593extern "C" DecorAddOn* 594instantiate_decor_addon(image_id id, const char* name) 595{ 596 return new (std::nothrow)WinDecorAddOn(id, name); 597} 598