23ae77aa56
* The Decorator are temporarily using ui_color() - this needs to be changed to use the DesktopSettings (when the decorator stuff gets refactored); right now, the colors are fixed. * Added B_WINDOW_TEXT_COLOR, B_WINDOW_INACTIVE_TAB_COLOR, and B_WINDOW_INACTIVE_TEXT_COLOR to the UI colors, B_WINDOW_TAB_COLOR is no longer deprecated. Note, however, that not every decorator may use these colors. * Removed unused and wrong (ie. hard-coded paths) stuff from ServerConfig.h. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17236 a95241bf-73f2-0310-859d-f6bbb57e9c96
1070 lines
30 KiB
C++
1070 lines
30 KiB
C++
/*
|
|
* Copyright 2001-2006, Haiku.
|
|
* Distributed under the terms of the MIT License.
|
|
*
|
|
* Authors:
|
|
* DarkWyrm <bpmagic@columbus.rr.com>
|
|
* Stephan Aßmus <superstippi@gmx.de>
|
|
*/
|
|
|
|
/** Default and fallback decorator for the app_server - the yellow tabs */
|
|
|
|
|
|
#include "DefaultDecorator.h"
|
|
|
|
#include "DesktopSettings.h"
|
|
#include "DrawingEngine.h"
|
|
#include "DrawState.h"
|
|
#include "FontManager.h"
|
|
#include "PatternHandler.h"
|
|
#include "RGBColor.h"
|
|
|
|
#include <Rect.h>
|
|
#include <View.h>
|
|
|
|
#include <WindowPrivate.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
//#define DEBUG_DECORATOR
|
|
#ifdef DEBUG_DECORATOR
|
|
# include <stdio.h>
|
|
# define STRACE(x) printf x
|
|
#else
|
|
# define STRACE(x) ;
|
|
#endif
|
|
|
|
|
|
static inline uint8
|
|
blend_color_value(uint8 a, uint8 b, float position)
|
|
{
|
|
int16 delta = (int16)b - a;
|
|
int32 value = a + (int32)(position * delta);
|
|
if (value > 255)
|
|
return 255;
|
|
if (value < 0)
|
|
return 0;
|
|
|
|
return (uint8)value;
|
|
}
|
|
|
|
|
|
/*!
|
|
\brief Function mostly for calculating gradient colors
|
|
\param col Start color
|
|
\param col2 End color
|
|
\param position A floating point number such that 0.0 <= position <= 1.0. 0.0 results in the
|
|
start color and 1.0 results in the end color.
|
|
\return The blended color. If an invalid position was given, {0,0,0,0} is returned.
|
|
*/
|
|
static rgb_color
|
|
make_blend_color(rgb_color colorA, rgb_color colorB, float position)
|
|
{
|
|
if (position < 0)
|
|
return colorA;
|
|
if (position > 1)
|
|
return colorB;
|
|
|
|
rgb_color blendColor;
|
|
blendColor.red = blend_color_value(colorA.red, colorB.red, position);
|
|
blendColor.green = blend_color_value(colorA.green, colorB.green, position);
|
|
blendColor.blue = blend_color_value(colorA.blue, colorB.blue, position);
|
|
blendColor.alpha = blend_color_value(colorA.alpha, colorB.alpha, position);
|
|
|
|
return blendColor;
|
|
}
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
// TODO: get rid of DesktopSettings here, and introduce private accessor
|
|
// methods to the Decorator base class
|
|
|
|
DefaultDecorator::DefaultDecorator(DesktopSettings& settings, BRect rect,
|
|
window_look look, uint32 flags)
|
|
: Decorator(settings, rect, look, flags),
|
|
fLastClicked(0)
|
|
{
|
|
DefaultDecorator::SetLook(settings, look);
|
|
|
|
fFrameColors = new RGBColor[6];
|
|
fFrameColors[0].SetColor(152, 152, 152);
|
|
fFrameColors[1].SetColor(255, 255, 255);
|
|
fFrameColors[2].SetColor(216, 216, 216);
|
|
fFrameColors[3].SetColor(136, 136, 136);
|
|
fFrameColors[4].SetColor(152, 152, 152);
|
|
fFrameColors[5].SetColor(96, 96, 96);
|
|
|
|
// Set appropriate colors based on the current focus value. In this case, each decorator
|
|
// defaults to not having the focus.
|
|
_SetFocus();
|
|
|
|
// Do initial decorator setup
|
|
_DoLayout();
|
|
|
|
// ToDo: if the decorator was created with a frame too small, it should resize itself!
|
|
|
|
STRACE(("DefaultDecorator:\n"));
|
|
STRACE(("\tFrame (%.1f,%.1f,%.1f,%.1f)\n",
|
|
rect.left, rect.top, rect.right, rect.bottom));
|
|
}
|
|
|
|
|
|
DefaultDecorator::~DefaultDecorator()
|
|
{
|
|
STRACE(("DefaultDecorator: ~DefaultDecorator()\n"));
|
|
delete [] fFrameColors;
|
|
}
|
|
|
|
|
|
void
|
|
DefaultDecorator::SetTitle(const char* string, BRegion* updateRegion)
|
|
{
|
|
BRect rect = TabRect();
|
|
|
|
Decorator::SetTitle(string);
|
|
|
|
if (updateRegion == NULL)
|
|
return;
|
|
|
|
BRect updatedRect = TabRect();
|
|
if (rect.left > updatedRect.left)
|
|
rect.left = updatedRect.left;
|
|
if (rect.right < updatedRect.right)
|
|
rect.right = updatedRect.right;
|
|
|
|
rect.bottom++;
|
|
// the border will look differently when the title is adjacent
|
|
|
|
updateRegion->Include(rect);
|
|
}
|
|
|
|
|
|
void
|
|
DefaultDecorator::SetLook(DesktopSettings& settings,
|
|
window_look look, BRegion* updateRegion)
|
|
{
|
|
// TODO: we could be much smarter about the update region
|
|
|
|
// get previous extent
|
|
if (updateRegion != NULL) {
|
|
BRegion extent;
|
|
GetFootprint(&extent);
|
|
updateRegion->Include(&extent);
|
|
}
|
|
|
|
ServerFont font;
|
|
if (look == B_FLOATING_WINDOW_LOOK || look == kLeftTitledWindowLook) {
|
|
settings.GetDefaultPlainFont(font);
|
|
if (look == kLeftTitledWindowLook)
|
|
font.SetRotation(90.0f);
|
|
} else
|
|
settings.GetDefaultBoldFont(font);
|
|
|
|
font.SetFlags(B_FORCE_ANTIALIASING);
|
|
font.SetSpacing(B_STRING_SPACING);
|
|
SetFont(&font);
|
|
|
|
Decorator::SetLook(settings, look, updateRegion);
|
|
_DoLayout();
|
|
|
|
if (updateRegion != NULL) {
|
|
BRegion extent;
|
|
GetFootprint(&extent);
|
|
updateRegion->Include(&extent);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DefaultDecorator::SetFlags(uint32 flags, BRegion* updateRegion)
|
|
{
|
|
// TODO: we could be much smarter about the update region
|
|
|
|
// get previous extent
|
|
if (updateRegion != NULL) {
|
|
BRegion extent;
|
|
GetFootprint(&extent);
|
|
updateRegion->Include(&extent);
|
|
}
|
|
|
|
Decorator::SetFlags(flags, updateRegion);
|
|
_DoLayout();
|
|
|
|
if (updateRegion != NULL) {
|
|
BRegion extent;
|
|
GetFootprint(&extent);
|
|
updateRegion->Include(&extent);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DefaultDecorator::MoveBy(BPoint pt)
|
|
{
|
|
STRACE(("DefaultDecorator: Move By (%.1f, %.1f)\n",pt.x,pt.y));
|
|
// Move all internal rectangles the appropriate amount
|
|
_frame.OffsetBy(pt);
|
|
_closerect.OffsetBy(pt);
|
|
_tabrect.OffsetBy(pt);
|
|
_resizerect.OffsetBy(pt);
|
|
_zoomrect.OffsetBy(pt);
|
|
_borderrect.OffsetBy(pt);
|
|
|
|
fLeftBorder.OffsetBy(pt);
|
|
fRightBorder.OffsetBy(pt);
|
|
fTopBorder.OffsetBy(pt);
|
|
fBottomBorder.OffsetBy(pt);
|
|
}
|
|
|
|
|
|
void
|
|
DefaultDecorator::ResizeBy(BPoint pt, BRegion* dirty)
|
|
{
|
|
STRACE(("DefaultDecorator: Resize By (%.1f, %.1f)\n", pt.x, pt.y));
|
|
// Move all internal rectangles the appropriate amount
|
|
_frame.right += pt.x;
|
|
_frame.bottom += pt.y;
|
|
|
|
// handle invalidation of resize rect
|
|
if (dirty && !(fFlags & B_NOT_RESIZABLE)) {
|
|
BRect realResizeRect;
|
|
switch (fLook) {
|
|
case B_DOCUMENT_WINDOW_LOOK:
|
|
realResizeRect = _resizerect;
|
|
// resize rect at old location
|
|
dirty->Include(realResizeRect);
|
|
realResizeRect.OffsetBy(pt);
|
|
// resize rect at new location
|
|
dirty->Include(realResizeRect);
|
|
break;
|
|
case B_TITLED_WINDOW_LOOK:
|
|
case B_FLOATING_WINDOW_LOOK:
|
|
case B_MODAL_WINDOW_LOOK:
|
|
case kLeftTitledWindowLook:
|
|
realResizeRect.Set(fRightBorder.right - 22, fBottomBorder.top,
|
|
fRightBorder.right - 22, fBottomBorder.bottom - 1);
|
|
// resize rect at old location
|
|
dirty->Include(realResizeRect);
|
|
realResizeRect.OffsetBy(pt);
|
|
// resize rect at new location
|
|
dirty->Include(realResizeRect);
|
|
|
|
realResizeRect.Set(fRightBorder.left, fBottomBorder.bottom - 22,
|
|
fRightBorder.right - 1, fBottomBorder.bottom - 22);
|
|
// resize rect at old location
|
|
dirty->Include(realResizeRect);
|
|
realResizeRect.OffsetBy(pt);
|
|
// resize rect at new location
|
|
dirty->Include(realResizeRect);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
_resizerect.OffsetBy(pt);
|
|
|
|
_borderrect.right += pt.x;
|
|
_borderrect.bottom += pt.y;
|
|
|
|
fLeftBorder.bottom += pt.y;
|
|
fTopBorder.right += pt.x;
|
|
|
|
fRightBorder.OffsetBy(pt.x, 0.0);
|
|
fRightBorder.bottom += pt.y;
|
|
|
|
fBottomBorder.OffsetBy(0.0, pt.y);
|
|
fBottomBorder.right += pt.x;
|
|
|
|
if (dirty) {
|
|
if (pt.x > 0.0) {
|
|
BRect t(fRightBorder.left - pt.x, fTopBorder.top,
|
|
fRightBorder.right, fTopBorder.bottom);
|
|
dirty->Include(t);
|
|
t.Set(fRightBorder.left - pt.x, fBottomBorder.top,
|
|
fRightBorder.right, fBottomBorder.bottom);
|
|
dirty->Include(t);
|
|
dirty->Include(fRightBorder);
|
|
} else if (pt.x < 0.0) {
|
|
dirty->Include(BRect(fRightBorder.left, fTopBorder.top,
|
|
fRightBorder.right, fBottomBorder.bottom));
|
|
}
|
|
if (pt.y > 0.0) {
|
|
BRect t(fLeftBorder.left, fLeftBorder.bottom - pt.y,
|
|
fLeftBorder.right, fLeftBorder.bottom);
|
|
dirty->Include(t);
|
|
t.Set(fRightBorder.left, fRightBorder.bottom - pt.y,
|
|
fRightBorder.right, fRightBorder.bottom);
|
|
dirty->Include(t);
|
|
dirty->Include(fBottomBorder);
|
|
} else if (pt.y < 0.0) {
|
|
dirty->Include(fBottomBorder);
|
|
}
|
|
}
|
|
|
|
// resize tab and layout tab items
|
|
if (_tabrect.IsValid()) {
|
|
float tabSize;
|
|
if (fLook != kLeftTitledWindowLook)
|
|
tabSize = fRightBorder.right - fLeftBorder.left;
|
|
else
|
|
tabSize = fBottomBorder.bottom - fTopBorder.top;
|
|
|
|
if (tabSize < fMinTabSize)
|
|
tabSize = fMinTabSize;
|
|
if (tabSize > fMaxTabSize)
|
|
tabSize = fMaxTabSize;
|
|
|
|
if (fLook != kLeftTitledWindowLook && tabSize != _tabrect.Width()) {
|
|
// NOTE: the tab rect becoming smaller is handled
|
|
// by the Desktop anyways, so it is sufficient
|
|
// to include it into the dirty region in it's
|
|
// final state only once at the end
|
|
_tabrect.right = _tabrect.left + tabSize;
|
|
_LayoutTabItems(_tabrect);
|
|
|
|
if (dirty)
|
|
dirty->Include(_tabrect);
|
|
} else if (fLook == kLeftTitledWindowLook && tabSize != _tabrect.Height()) {
|
|
_tabrect.bottom = _tabrect.top + tabSize;
|
|
_LayoutTabItems(_tabrect);
|
|
|
|
if (dirty)
|
|
dirty->Include(_tabrect);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draw
|
|
void
|
|
DefaultDecorator::Draw(BRect update)
|
|
{
|
|
STRACE(("DefaultDecorator: Draw(%.1f,%.1f,%.1f,%.1f)\n",
|
|
update.left, update.top, update.right, update.bottom));
|
|
|
|
// We need to draw a few things: the tab, the resize thumb, the borders,
|
|
// and the buttons
|
|
|
|
_DrawFrame(update);
|
|
_DrawTab(update);
|
|
}
|
|
|
|
// Draw
|
|
void
|
|
DefaultDecorator::Draw()
|
|
{
|
|
// Easy way to draw everything - no worries about drawing only certain
|
|
// things
|
|
|
|
_DrawFrame(BRect(fTopBorder.LeftTop(), fBottomBorder.RightBottom()));
|
|
_DrawTab(_tabrect);
|
|
}
|
|
|
|
// GetSizeLimits
|
|
void
|
|
DefaultDecorator::GetSizeLimits(int32* minWidth, int32* minHeight,
|
|
int32* maxWidth, int32* maxHeight) const
|
|
{
|
|
if (_tabrect.IsValid())
|
|
*minWidth = (int32)roundf(max_c(*minWidth, fMinTabSize - 2 * fBorderWidth));
|
|
if (_resizerect.IsValid())
|
|
*minHeight = (int32)roundf(max_c(*minHeight, _resizerect.Height() - fBorderWidth));
|
|
}
|
|
|
|
// GetFootprint
|
|
void
|
|
DefaultDecorator::GetFootprint(BRegion *region)
|
|
{
|
|
STRACE(("DefaultDecorator: Get Footprint\n"));
|
|
// This function calculates the decorator's footprint in coordinates
|
|
// relative to the layer. This is most often used to set a WindowLayer
|
|
// object's visible region.
|
|
if (!region)
|
|
return;
|
|
|
|
region->MakeEmpty();
|
|
|
|
if (fLook == B_NO_BORDER_WINDOW_LOOK)
|
|
return;
|
|
|
|
region->Include(fLeftBorder);
|
|
region->Include(fRightBorder);
|
|
region->Include(fTopBorder);
|
|
region->Include(fBottomBorder);
|
|
|
|
if (fLook == B_BORDERED_WINDOW_LOOK)
|
|
return;
|
|
|
|
region->Include(_tabrect);
|
|
|
|
if (fLook == B_DOCUMENT_WINDOW_LOOK) {
|
|
// include the rectangular resize knob on the bottom right
|
|
region->Include(BRect(_frame.right - 13.0f, _frame.bottom - 13.0f,
|
|
_frame.right, _frame.bottom));
|
|
}
|
|
}
|
|
|
|
|
|
click_type
|
|
DefaultDecorator::Clicked(BPoint pt, int32 buttons, int32 modifiers)
|
|
{
|
|
#ifdef DEBUG_DECORATOR
|
|
printf("DefaultDecorator: Clicked\n");
|
|
printf("\tPoint: (%.1f,%.1f)\n", pt.x,pt.y);
|
|
printf("\tButtons: %ld, Modifiers: 0x%lx\n", buttons, modifiers);
|
|
#endif // DEBUG_DECORATOR
|
|
|
|
// TODO: have a real double-click mechanism, ie. take user settings into account
|
|
bigtime_t now = system_time();
|
|
if (buttons != 0) {
|
|
fWasDoubleClick = now - fLastClicked < 200000;
|
|
fLastClicked = now;
|
|
}
|
|
|
|
// In checking for hit test stuff, we start with the smallest rectangles the user might
|
|
// be clicking on and gradually work our way out into larger rectangles.
|
|
if (!(fFlags & B_NOT_CLOSABLE) && _closerect.Contains(pt))
|
|
return DEC_CLOSE;
|
|
|
|
if (!(fFlags & B_NOT_ZOOMABLE) && _zoomrect.Contains(pt))
|
|
return DEC_ZOOM;
|
|
|
|
if (fLook == B_DOCUMENT_WINDOW_LOOK && _resizerect.Contains(pt))
|
|
return DEC_RESIZE;
|
|
|
|
bool clicked = false;
|
|
|
|
// Clicking in the tab?
|
|
if (_tabrect.Contains(pt)) {
|
|
// tab sliding in any case if either shift key is held down
|
|
if (modifiers & B_SHIFT_KEY)
|
|
return DEC_SLIDETAB;
|
|
|
|
clicked = true;
|
|
} else if (fLeftBorder.Contains(pt) || fRightBorder.Contains(pt)
|
|
|| fTopBorder.Contains(pt) || fBottomBorder.Contains(pt)) {
|
|
// Clicked on border
|
|
|
|
// check resize area
|
|
if (!(fFlags & B_NOT_RESIZABLE)
|
|
&& (fLook == B_TITLED_WINDOW_LOOK
|
|
|| fLook == B_FLOATING_WINDOW_LOOK
|
|
|| fLook == B_MODAL_WINDOW_LOOK
|
|
|| fLook == kLeftTitledWindowLook)) {
|
|
BRect temp(BPoint(fBottomBorder.right - 18, fBottomBorder.bottom - 18),
|
|
fBottomBorder.RightBottom());
|
|
if (temp.Contains(pt))
|
|
return DEC_RESIZE;
|
|
}
|
|
|
|
clicked = true;
|
|
}
|
|
|
|
if (clicked) {
|
|
// NOTE: On R5, windows are not moved to back if clicked inside the resize area
|
|
// with the second mouse button. So we check this after the check above
|
|
if (buttons == B_SECONDARY_MOUSE_BUTTON)
|
|
return DEC_MOVETOBACK;
|
|
|
|
if (fWasDoubleClick)
|
|
return DEC_MINIMIZE;
|
|
|
|
return DEC_DRAG;
|
|
}
|
|
|
|
// Guess user didn't click anything
|
|
return DEC_NONE;
|
|
}
|
|
|
|
|
|
void
|
|
DefaultDecorator::_DoLayout()
|
|
{
|
|
STRACE(("DefaultDecorator: Do Layout\n"));
|
|
// Here we determine the size of every rectangle that we use
|
|
// internally when we are given the size of the client rectangle.
|
|
|
|
bool hasTab = false;
|
|
|
|
switch (Look()) {
|
|
case B_MODAL_WINDOW_LOOK:
|
|
fBorderWidth = 5;
|
|
break;
|
|
|
|
case B_TITLED_WINDOW_LOOK:
|
|
case B_DOCUMENT_WINDOW_LOOK:
|
|
hasTab = true;
|
|
fBorderWidth = 5;
|
|
break;
|
|
case B_FLOATING_WINDOW_LOOK:
|
|
case kLeftTitledWindowLook:
|
|
hasTab = true;
|
|
fBorderWidth = 3;
|
|
break;
|
|
|
|
case B_BORDERED_WINDOW_LOOK:
|
|
fBorderWidth = 1;
|
|
break;
|
|
|
|
default:
|
|
fBorderWidth = 0;
|
|
}
|
|
|
|
// calculate our tab rect
|
|
if (hasTab) {
|
|
// tab is initially on the left
|
|
fTabOffset = 0;
|
|
// distance from one item of the tab bar to another.
|
|
// In this case the text and close/zoom rects
|
|
fTextOffset = (fLook == B_FLOATING_WINDOW_LOOK || fLook == kLeftTitledWindowLook)
|
|
? 10 : 18;
|
|
|
|
font_height fontHeight;
|
|
fDrawState.Font().GetHeight(fontHeight);
|
|
|
|
if (fLook != kLeftTitledWindowLook) {
|
|
_tabrect.Set(_frame.left - fBorderWidth,
|
|
_frame.top - fBorderWidth - ceilf(fontHeight.ascent + fontHeight.descent + 7.0),
|
|
((_frame.right - _frame.left) < 35.0 ?
|
|
_frame.left + 35.0 : _frame.right) + fBorderWidth,
|
|
_frame.top - fBorderWidth);
|
|
} else {
|
|
_tabrect.Set(_frame.left - fBorderWidth - ceilf(fontHeight.ascent + fontHeight.descent + 5.0),
|
|
_frame.top - fBorderWidth, _frame.left - fBorderWidth,
|
|
_frame.bottom + fBorderWidth);
|
|
}
|
|
|
|
// format tab rect for a floating window - make the rect smaller
|
|
if (fLook == B_FLOATING_WINDOW_LOOK) {
|
|
_tabrect.InsetBy(0, 2);
|
|
_tabrect.OffsetBy(0, 2);
|
|
}
|
|
|
|
float offset;
|
|
float size;
|
|
_GetButtonSizeAndOffset(_tabrect, &offset, &size);
|
|
|
|
// fMinTabSize contains just the room for the buttons
|
|
fMinTabSize = 4.0 + fTextOffset;
|
|
if ((fFlags & B_NOT_CLOSABLE) == 0)
|
|
fMinTabSize += offset + size;
|
|
if ((fFlags & B_NOT_ZOOMABLE) == 0)
|
|
fMinTabSize += offset + size;
|
|
|
|
// fMaxTabSize contains fMinWidth + the width required for the title
|
|
fMaxTabSize = _driver ? ceilf(_driver->StringWidth(Title(), strlen(Title()),
|
|
&fDrawState)) : 0.0;
|
|
if (fMaxTabSize > 0.0)
|
|
fMaxTabSize += fTextOffset;
|
|
fMaxTabSize += fMinTabSize;
|
|
|
|
float tabSize = fLook != kLeftTitledWindowLook ? _frame.Width() : _frame.Height();
|
|
if (tabSize < fMinTabSize)
|
|
tabSize = fMinTabSize;
|
|
if (tabSize > fMaxTabSize)
|
|
tabSize = fMaxTabSize;
|
|
|
|
// layout buttons and truncate text
|
|
if (fLook != kLeftTitledWindowLook)
|
|
_tabrect.right = _tabrect.left + tabSize;
|
|
else
|
|
_tabrect.bottom = _tabrect.top + tabSize;
|
|
|
|
_LayoutTabItems(_tabrect);
|
|
} else {
|
|
// no tab
|
|
fMinTabSize = 0.0;
|
|
fMaxTabSize = 0.0;
|
|
_tabrect.Set(0.0, 0.0, -1.0, -1.0);
|
|
_closerect.Set(0.0, 0.0, -1.0, -1.0);
|
|
_zoomrect.Set(0.0, 0.0, -1.0, -1.0);
|
|
}
|
|
|
|
// calculate left/top/right/bottom borders
|
|
if (fBorderWidth > 0) {
|
|
// NOTE: no overlapping, the left and right border rects
|
|
// don't include the corners!
|
|
fLeftBorder.Set(_frame.left - fBorderWidth, _frame.top,
|
|
_frame.left - 1, _frame.bottom);
|
|
|
|
fRightBorder.Set(_frame.right + 1, _frame.top ,
|
|
_frame.right + fBorderWidth, _frame.bottom);
|
|
|
|
fTopBorder.Set(_frame.left - fBorderWidth, _frame.top - fBorderWidth,
|
|
_frame.right + fBorderWidth, _frame.top - 1);
|
|
|
|
fBottomBorder.Set(_frame.left - fBorderWidth, _frame.bottom + 1,
|
|
_frame.right + fBorderWidth, _frame.bottom + fBorderWidth);
|
|
} else {
|
|
// no border
|
|
fLeftBorder.Set(0.0, 0.0, -1.0, -1.0);
|
|
fRightBorder.Set(0.0, 0.0, -1.0, -1.0);
|
|
fTopBorder.Set(0.0, 0.0, -1.0, -1.0);
|
|
fBottomBorder.Set(0.0, 0.0, -1.0, -1.0);
|
|
}
|
|
|
|
// calculate resize rect
|
|
_resizerect.Set(fBottomBorder.right - 18.0, fBottomBorder.bottom - 18.0,
|
|
fBottomBorder.right, fBottomBorder.bottom);
|
|
}
|
|
|
|
// _DrawFrame
|
|
void
|
|
DefaultDecorator::_DrawFrame(BRect invalid)
|
|
{
|
|
STRACE(("_DrawFrame(%f,%f,%f,%f)\n", invalid.left, invalid.top,
|
|
invalid.right, invalid.bottom));
|
|
|
|
// NOTE: the DrawingEngine needs to be locked for the entire
|
|
// time for the clipping to stay valid for this decorator
|
|
|
|
if (fLook == B_NO_BORDER_WINDOW_LOOK)
|
|
return;
|
|
|
|
if (fBorderWidth <= 0)
|
|
return;
|
|
|
|
// Draw the border frame
|
|
BRect r = BRect(fTopBorder.LeftTop(), fBottomBorder.RightBottom());
|
|
switch (fLook) {
|
|
case B_TITLED_WINDOW_LOOK:
|
|
case B_DOCUMENT_WINDOW_LOOK:
|
|
case B_MODAL_WINDOW_LOOK:
|
|
{
|
|
// top
|
|
if (invalid.Intersects(fTopBorder)) {
|
|
for (int8 i = 0; i < 5; i++) {
|
|
_driver->StrokeLine(BPoint(r.left + i, r.top + i),
|
|
BPoint(r.right - i, r.top + i),
|
|
fFrameColors[i]);
|
|
}
|
|
if (_tabrect.IsValid()) {
|
|
// grey along the bottom of the tab (overwrites "white" from frame)
|
|
_driver->StrokeLine(BPoint(_tabrect.left + 2, _tabrect.bottom + 1),
|
|
BPoint(_tabrect.right - 2, _tabrect.bottom + 1),
|
|
fFrameColors[2]);
|
|
}
|
|
}
|
|
// left
|
|
if (invalid.Intersects(fLeftBorder.InsetByCopy(0, -fBorderWidth))) {
|
|
for (int8 i = 0; i < 5; i++) {
|
|
_driver->StrokeLine(BPoint(r.left + i, r.top + i),
|
|
BPoint(r.left + i, r.bottom - i),
|
|
fFrameColors[i]);
|
|
}
|
|
}
|
|
// bottom
|
|
if (invalid.Intersects(fBottomBorder)) {
|
|
for (int8 i = 0; i < 5; i++) {
|
|
_driver->StrokeLine(BPoint(r.left + i, r.bottom - i),
|
|
BPoint(r.right - i, r.bottom - i),
|
|
fFrameColors[(4 - i) == 4 ? 5 : (4 - i)]);
|
|
}
|
|
}
|
|
// right
|
|
if (invalid.Intersects(fRightBorder.InsetByCopy(0, -fBorderWidth))) {
|
|
for (int8 i = 0; i < 5; i++) {
|
|
_driver->StrokeLine(BPoint(r.right - i, r.top + i),
|
|
BPoint(r.right - i, r.bottom - i),
|
|
fFrameColors[(4 - i) == 4 ? 5 : (4 - i)]);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case B_FLOATING_WINDOW_LOOK:
|
|
case kLeftTitledWindowLook:
|
|
{
|
|
// top
|
|
if (invalid.Intersects(fTopBorder)) {
|
|
for (int8 i = 0; i < 3; i++) {
|
|
_driver->StrokeLine(BPoint(r.left + i, r.top + i),
|
|
BPoint(r.right - i, r.top + i),
|
|
fFrameColors[i * 2]);
|
|
}
|
|
if (_tabrect.IsValid() && fLook != kLeftTitledWindowLook) {
|
|
// grey along the bottom of the tab (overwrites "white" from frame)
|
|
_driver->StrokeLine(BPoint(_tabrect.left + 2, _tabrect.bottom + 1),
|
|
BPoint(_tabrect.right - 2, _tabrect.bottom + 1),
|
|
fFrameColors[2]);
|
|
}
|
|
}
|
|
// left
|
|
if (invalid.Intersects(fLeftBorder.InsetByCopy(0, -fBorderWidth))) {
|
|
for (int8 i = 0; i < 3; i++) {
|
|
_driver->StrokeLine(BPoint(r.left + i, r.top + i),
|
|
BPoint(r.left + i, r.bottom - i),
|
|
fFrameColors[i * 2]);
|
|
}
|
|
if (fLook == kLeftTitledWindowLook && _tabrect.IsValid()) {
|
|
// grey along the right side of the tab (overwrites "white" from frame)
|
|
_driver->StrokeLine(BPoint(_tabrect.right + 1, _tabrect.top + 2),
|
|
BPoint(_tabrect.right + 1, _tabrect.bottom - 2),
|
|
fFrameColors[2]);
|
|
}
|
|
}
|
|
// bottom
|
|
if (invalid.Intersects(fBottomBorder)) {
|
|
for (int8 i = 0; i < 3; i++) {
|
|
_driver->StrokeLine(BPoint(r.left + i, r.bottom - i),
|
|
BPoint(r.right - i, r.bottom - i),
|
|
fFrameColors[(2 - i) == 2 ? 5 : (2 - i) * 2]);
|
|
}
|
|
}
|
|
// right
|
|
if (invalid.Intersects(fRightBorder.InsetByCopy(0, -fBorderWidth))) {
|
|
for (int8 i = 0; i < 3; i++) {
|
|
_driver->StrokeLine(BPoint(r.right - i, r.top + i),
|
|
BPoint(r.right - i, r.bottom - i),
|
|
fFrameColors[(2 - i) == 2 ? 5 : (2 - i) * 2]);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case B_BORDERED_WINDOW_LOOK:
|
|
_driver->StrokeRect(r, fFrameColors[5]);
|
|
break;
|
|
|
|
default:
|
|
// don't draw a border frame
|
|
break;
|
|
}
|
|
|
|
// Draw the resize thumb if we're supposed to
|
|
if (!(fFlags & B_NOT_RESIZABLE)) {
|
|
r = _resizerect;
|
|
|
|
switch (fLook) {
|
|
case B_DOCUMENT_WINDOW_LOOK:
|
|
{
|
|
if (!invalid.Intersects(r))
|
|
break;
|
|
|
|
float x = r.right - 3;
|
|
float y = r.bottom - 3;
|
|
|
|
_driver->FillRect(BRect(x - 13, y - 13, x, y), fFrameColors[2]);
|
|
_driver->StrokeLine(BPoint(x - 15, y - 15), BPoint(x - 15, y - 2),
|
|
fFrameColors[0]);
|
|
_driver->StrokeLine(BPoint(x - 14, y - 14), BPoint(x - 14, y - 1),
|
|
fFrameColors[1]);
|
|
_driver->StrokeLine(BPoint(x - 15, y - 15), BPoint(x - 2, y - 15),
|
|
fFrameColors[0]);
|
|
_driver->StrokeLine(BPoint(x - 14, y - 14), BPoint(x - 1, y - 14),
|
|
fFrameColors[1]);
|
|
|
|
if (!IsFocus())
|
|
break;
|
|
|
|
for (int8 i = 1; i <= 4; i++) {
|
|
for (int8 j = 1; j <= i; j++) {
|
|
BPoint pt1(x - (3 * j) + 1, y - (3 * (5 - i)) + 1);
|
|
BPoint pt2(x - (3 * j) + 2, y - (3 * (5 - i)) + 2);
|
|
_driver->StrokePoint(pt1, fFrameColors[0]);
|
|
_driver->StrokePoint(pt2, fFrameColors[1]);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case B_TITLED_WINDOW_LOOK:
|
|
case B_FLOATING_WINDOW_LOOK:
|
|
case B_MODAL_WINDOW_LOOK:
|
|
case kLeftTitledWindowLook:
|
|
{
|
|
if (!invalid.Intersects(BRect(fRightBorder.right - 22,
|
|
fBottomBorder.bottom - 22, fRightBorder.right - 1,
|
|
fBottomBorder.bottom - 1)))
|
|
break;
|
|
|
|
_driver->StrokeLine(BPoint(fRightBorder.left, fBottomBorder.bottom - 22),
|
|
BPoint(fRightBorder.right - 1, fBottomBorder.bottom - 22),
|
|
fFrameColors[0]);
|
|
_driver->StrokeLine(BPoint(fRightBorder.right - 22, fBottomBorder.top),
|
|
BPoint(fRightBorder.right - 22, fBottomBorder.bottom - 1),
|
|
fFrameColors[0]);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// don't draw resize corner
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// _DrawTab
|
|
void
|
|
DefaultDecorator::_DrawTab(BRect invalid)
|
|
{
|
|
STRACE(("_DrawTab(%.1f,%.1f,%.1f,%.1f)\n",
|
|
invalid.left, invalid.top, invalid.right, invalid.bottom));
|
|
// If a window has a tab, this will draw it and any buttons which are
|
|
// in it.
|
|
if (!_tabrect.IsValid() || !invalid.Intersects(_tabrect))
|
|
return;
|
|
|
|
// TODO: cache these
|
|
RGBColor tabColorLight = RGBColor(tint_color(fTabColor.GetColor32(),
|
|
(B_LIGHTEN_2_TINT + B_LIGHTEN_MAX_TINT) / 2));
|
|
RGBColor tabColorShadow = RGBColor(tint_color(fTabColor.GetColor32(),
|
|
B_DARKEN_2_TINT));
|
|
|
|
// outer frame
|
|
_driver->StrokeLine(_tabrect.LeftTop(), _tabrect.LeftBottom(), fFrameColors[0]);
|
|
_driver->StrokeLine(_tabrect.LeftTop(), _tabrect.RightTop(), fFrameColors[0]);
|
|
if (fLook != kLeftTitledWindowLook)
|
|
_driver->StrokeLine(_tabrect.RightTop(),_tabrect.RightBottom(), fFrameColors[5]);
|
|
else
|
|
_driver->StrokeLine(_tabrect.LeftBottom(),_tabrect.RightBottom(), fFrameColors[5]);
|
|
|
|
// bevel
|
|
_driver->StrokeLine(BPoint(_tabrect.left + 1, _tabrect.top + 1),
|
|
BPoint(_tabrect.left + 1, _tabrect.bottom - (fLook == kLeftTitledWindowLook ? 1 : 0)),
|
|
tabColorLight);
|
|
_driver->StrokeLine(BPoint(_tabrect.left + 1, _tabrect.top + 1),
|
|
BPoint(_tabrect.right - (fLook == kLeftTitledWindowLook ? 0 : 1), _tabrect.top + 1),
|
|
tabColorLight);
|
|
|
|
if (fLook != kLeftTitledWindowLook) {
|
|
_driver->StrokeLine(BPoint(_tabrect.right - 1, _tabrect.top + 2),
|
|
BPoint(_tabrect.right - 1, _tabrect.bottom), tabColorShadow);
|
|
} else {
|
|
_driver->StrokeLine(BPoint(_tabrect.left + 2, _tabrect.bottom - 1),
|
|
BPoint(_tabrect.right, _tabrect.bottom - 1), tabColorShadow);
|
|
}
|
|
|
|
// fill
|
|
if (fLook != kLeftTitledWindowLook) {
|
|
_driver->FillRect(BRect(_tabrect.left + 2, _tabrect.top + 2,
|
|
_tabrect.right - 2, _tabrect.bottom), fTabColor);
|
|
} else {
|
|
_driver->FillRect(BRect(_tabrect.left + 2, _tabrect.top + 2,
|
|
_tabrect.right, _tabrect.bottom - 2), fTabColor);
|
|
}
|
|
|
|
_DrawTitle(_tabrect);
|
|
|
|
// Draw the buttons if we're supposed to
|
|
if (!(fFlags & B_NOT_CLOSABLE) && invalid.Intersects(_closerect))
|
|
_DrawClose(_closerect);
|
|
if (!(fFlags & B_NOT_ZOOMABLE) && invalid.Intersects(_zoomrect))
|
|
_DrawZoom(_zoomrect);
|
|
}
|
|
|
|
// _DrawClose
|
|
void
|
|
DefaultDecorator::_DrawClose(BRect r)
|
|
{
|
|
STRACE(("_DrawClose(%f,%f,%f,%f)\n", r.left, r.top, r.right, r.bottom));
|
|
// Just like DrawZoom, but for a close button
|
|
_DrawBlendedRect(r, GetClose());
|
|
}
|
|
|
|
// _DrawTitle
|
|
void
|
|
DefaultDecorator::_DrawTitle(BRect r)
|
|
{
|
|
STRACE(("_DrawTitle(%f,%f,%f,%f)\n", r.left, r.top, r.right, r.bottom));
|
|
|
|
fDrawState.SetHighColor(fTextColor);
|
|
fDrawState.SetLowColor(fTabColor);
|
|
|
|
// figure out position of text
|
|
font_height fontHeight;
|
|
fDrawState.Font().GetHeight(fontHeight);
|
|
|
|
BPoint titlePos;
|
|
if (fLook != kLeftTitledWindowLook) {
|
|
titlePos.x = _closerect.IsValid() ? _closerect.right + fTextOffset
|
|
: _tabrect.left + fTextOffset;
|
|
titlePos.y = floorf(((_tabrect.top + 2.0) + _tabrect.bottom + fontHeight.ascent
|
|
+ fontHeight.descent) / 2.0 - fontHeight.descent + 0.5);
|
|
} else {
|
|
titlePos.x = floorf(((_tabrect.left + 2.0) + _tabrect.right + fontHeight.ascent
|
|
+ fontHeight.descent) / 2.0 - fontHeight.descent + 0.5);
|
|
titlePos.y = _zoomrect.IsValid() ? _zoomrect.top - fTextOffset
|
|
: _tabrect.bottom - fTextOffset;
|
|
}
|
|
|
|
_driver->DrawString(fTruncatedTitle.String(), fTruncatedTitleLength, titlePos, &fDrawState);
|
|
}
|
|
|
|
// _DrawZoom
|
|
void
|
|
DefaultDecorator::_DrawZoom(BRect r)
|
|
{
|
|
STRACE(("_DrawZoom(%f,%f,%f,%f)\n", r.left, r.top, r.right, r.bottom));
|
|
// If this has been implemented, then the decorator has a Zoom button
|
|
// which should be drawn based on the state of the member zoomstate
|
|
|
|
BRect zr(r);
|
|
zr.left += 3.0;
|
|
zr.top += 3.0;
|
|
_DrawBlendedRect(zr, GetZoom());
|
|
|
|
zr = r;
|
|
zr.right -= 5.0;
|
|
zr.bottom -= 5.0;
|
|
_DrawBlendedRect(zr, GetZoom());
|
|
}
|
|
|
|
// _SetFocus
|
|
void
|
|
DefaultDecorator::_SetFocus()
|
|
{
|
|
// SetFocus() performs necessary duties for color swapping and
|
|
// other things when a window is deactivated or activated.
|
|
|
|
if (IsFocus() || ((fLook == B_FLOATING_WINDOW_LOOK || fLook == kLeftTitledWindowLook)
|
|
&& (fFlags & B_AVOID_FOCUS) != 0)) {
|
|
fTabColor = UIColor(B_WINDOW_TAB_COLOR);
|
|
fTextColor = UIColor(B_WINDOW_TEXT_COLOR);
|
|
fButtonHighColor.SetColor(tint_color(fTabColor.GetColor32(), B_LIGHTEN_2_TINT));
|
|
fButtonLowColor.SetColor(tint_color(fTabColor.GetColor32(), B_DARKEN_1_TINT));
|
|
|
|
// fFrameColors[0].SetColor(152, 152, 152);
|
|
// fFrameColors[1].SetColor(255, 255, 255);
|
|
fFrameColors[2].SetColor(216, 216, 216);
|
|
fFrameColors[3].SetColor(136, 136, 136);
|
|
// fFrameColors[4].SetColor(152, 152, 152);
|
|
// fFrameColors[5].SetColor(96, 96, 96);
|
|
} else {
|
|
fTabColor = UIColor(B_WINDOW_INACTIVE_TAB_COLOR);
|
|
fTextColor = UIColor(B_WINDOW_INACTIVE_TEXT_COLOR);
|
|
fButtonHighColor.SetColor(tint_color(fTabColor.GetColor32(), B_LIGHTEN_2_TINT));
|
|
fButtonLowColor.SetColor(tint_color(fTabColor.GetColor32(), B_DARKEN_1_TINT));
|
|
|
|
// fFrameColors[0].SetColor(152, 152, 152);
|
|
// fFrameColors[1].SetColor(255, 255, 255);
|
|
fFrameColors[2].SetColor(232, 232, 232);
|
|
fFrameColors[3].SetColor(148, 148, 148);
|
|
// fFrameColors[4].SetColor(152, 152, 152);
|
|
// fFrameColors[5].SetColor(96, 96, 96);
|
|
}
|
|
}
|
|
|
|
// _SetColors
|
|
void
|
|
DefaultDecorator::_SetColors()
|
|
{
|
|
_SetFocus();
|
|
}
|
|
|
|
|
|
/*!
|
|
\brief Draws a framed rectangle with a gradient.
|
|
\param down The rectangle should be drawn recessed or not
|
|
*/
|
|
void
|
|
DefaultDecorator::_DrawBlendedRect(BRect r, bool down)
|
|
{
|
|
// Actually just draws a blended square
|
|
int32 w = r.IntegerWidth();
|
|
int32 h = r.IntegerHeight();
|
|
|
|
RGBColor temprgbcol;
|
|
rgb_color halfColor, startColor, endColor;
|
|
float rstep, gstep, bstep;
|
|
|
|
int steps = w < h ? w : h;
|
|
|
|
if (down) {
|
|
startColor = fButtonLowColor.GetColor32();
|
|
endColor = fButtonHighColor.GetColor32();
|
|
} else {
|
|
startColor = fButtonHighColor.GetColor32();
|
|
endColor = fButtonLowColor.GetColor32();
|
|
}
|
|
|
|
halfColor = make_blend_color(startColor, endColor, 0.5);
|
|
|
|
rstep = float(startColor.red - halfColor.red) / steps;
|
|
gstep = float(startColor.green - halfColor.green) / steps;
|
|
bstep = float(startColor.blue - halfColor.blue) / steps;
|
|
|
|
for (int32 i = 0; i <= steps; i++) {
|
|
temprgbcol.SetColor(uint8(startColor.red - (i * rstep)),
|
|
uint8(startColor.green - (i * gstep)),
|
|
uint8(startColor.blue - (i * bstep)));
|
|
|
|
_driver->StrokeLine(BPoint(r.left, r.top + i),
|
|
BPoint(r.left + i, r.top), temprgbcol);
|
|
|
|
temprgbcol.SetColor(uint8(halfColor.red - (i * rstep)),
|
|
uint8(halfColor.green - (i * gstep)),
|
|
uint8(halfColor.blue - (i * bstep)));
|
|
|
|
_driver->StrokeLine(BPoint(r.left + steps, r.top + i),
|
|
BPoint(r.left + i, r.top + steps), temprgbcol);
|
|
}
|
|
_driver->StrokeRect(r, fFrameColors[3]);
|
|
}
|
|
|
|
// _GetButtonSizeAndOffset
|
|
void
|
|
DefaultDecorator::_GetButtonSizeAndOffset(const BRect& tabRect, float* _offset,
|
|
float* _size) const
|
|
{
|
|
*_offset = fLook == B_FLOATING_WINDOW_LOOK || fLook == kLeftTitledWindowLook ? 4.0 : 5.0;
|
|
|
|
// "+ 2" so that the rects are centered within the solid area
|
|
// (without the 2 pixels for the top border)
|
|
if (fLook != kLeftTitledWindowLook)
|
|
*_size = tabRect.Height() - 2.0 * *_offset + 2.0f;
|
|
else
|
|
*_size = tabRect.Width() - 2.0 * *_offset + 2.0f;
|
|
}
|
|
|
|
// _LayoutTabItems
|
|
void
|
|
DefaultDecorator::_LayoutTabItems(const BRect& tabRect)
|
|
{
|
|
float offset;
|
|
float size;
|
|
_GetButtonSizeAndOffset(tabRect, &offset, &size);
|
|
|
|
// calulate close rect based on the tab rectangle
|
|
if (fLook != kLeftTitledWindowLook) {
|
|
_closerect.Set(tabRect.left + offset, tabRect.top + offset,
|
|
tabRect.left + offset + size, tabRect.top + offset + size);
|
|
|
|
_zoomrect.Set(tabRect.right - offset - size, tabRect.top + offset,
|
|
tabRect.right - offset, tabRect.top + offset + size);
|
|
|
|
// hidden buttons have no width
|
|
if ((Flags() & B_NOT_CLOSABLE) != 0)
|
|
_closerect.right = _closerect.left - offset;
|
|
if ((Flags() & B_NOT_ZOOMABLE) != 0)
|
|
_zoomrect.left = _zoomrect.right + offset;
|
|
} else {
|
|
_closerect.Set(tabRect.left + offset, tabRect.top + offset,
|
|
tabRect.left + offset + size, tabRect.top + offset + size);
|
|
|
|
_zoomrect.Set(tabRect.left + offset, tabRect.bottom - offset - size,
|
|
tabRect.left + size + offset, tabRect.bottom - offset);
|
|
|
|
// hidden buttons have no height
|
|
if ((Flags() & B_NOT_CLOSABLE) != 0)
|
|
_closerect.bottom = _closerect.top - offset;
|
|
if ((Flags() & B_NOT_ZOOMABLE) != 0)
|
|
_zoomrect.top = _zoomrect.bottom + offset;
|
|
}
|
|
|
|
// calculate room for title
|
|
// ToDo: the +2 is there because the title often appeared
|
|
// truncated for no apparent reason - OTOH the title does
|
|
// also not appear perfectly in the middle
|
|
if (fLook != kLeftTitledWindowLook)
|
|
size = (_zoomrect.left - _closerect.right) - fTextOffset * 2 + 2;
|
|
else
|
|
size = (_zoomrect.top - _closerect.bottom) - fTextOffset * 2 + 2;
|
|
|
|
fTruncatedTitle = Title();
|
|
fDrawState.Font().TruncateString(&fTruncatedTitle, B_TRUNCATE_END, size);
|
|
fTruncatedTitleLength = fTruncatedTitle.Length();
|
|
}
|