//------------------------------------------------------------------------------ // Copyright (c) 2001-2002, OpenBeOS // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // // File Name: DefaultDecorator.cpp // Author: DarkWyrm // Description: Fallback decorator for the app_server // //------------------------------------------------------------------------------ #include #include "DisplayDriver.h" #include #include "LayerData.h" #include "ColorUtils.h" #include "DefaultDecorator.h" #include "PatternHandler.h" #include "RGBColor.h" #include "RectUtils.h" #include #define USE_VIEW_FILL_HACK //#define DEBUG_DECORATOR #ifdef DEBUG_DECORATOR #include #endif DefaultDecorator::DefaultDecorator(BRect rect, int32 wlook, int32 wfeel, int32 wflags) : Decorator(rect,wlook,wfeel,wflags) { taboffset=0; titlepixelwidth=0; framecolors=new RGBColor[5]; framecolors[0].SetColor(255,255,255); framecolors[1].SetColor(216,216,216); framecolors[2].SetColor(152,152,152); framecolors[3].SetColor(136,136,136); framecolors[4].SetColor(96,96,96); _SetFocus(); _DoLayout(); // This flag is used to determine whether or not we're moving the tab slidetab=false; // tab_highcol=_colors->window_tab; // tab_lowcol=_colors->window_tab; #ifdef DEBUG_DECORATOR printf("DefaultDecorator:\n"); printf("\tFrame (%.1f,%.1f,%.1f,%.1f)\n",rect.left,rect.top,rect.right,rect.bottom); #endif } DefaultDecorator::~DefaultDecorator(void) { #ifdef DEBUG_DECORATOR printf("DefaultDecorator: ~DefaultDecorator()\n"); #endif delete [] framecolors; } 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:\n"); if(buttons==0) printf("\t\tNone\n"); else { if(buttons & B_PRIMARY_MOUSE_BUTTON) printf("\t\tPrimary\n"); if(buttons & B_SECONDARY_MOUSE_BUTTON) printf("\t\tSecondary\n"); if(buttons & B_TERTIARY_MOUSE_BUTTON) printf("\t\tTertiary\n"); } printf("\tModifiers:\n"); if(modifiers==0) printf("\t\tNone\n"); else { if(modifiers & B_CAPS_LOCK) printf("\t\tCaps Lock\n"); if(modifiers & B_NUM_LOCK) printf("\t\tNum Lock\n"); if(modifiers & B_SCROLL_LOCK) printf("\t\tScroll Lock\n"); if(modifiers & B_LEFT_COMMAND_KEY) printf("\t\t Left Command\n"); if(modifiers & B_RIGHT_COMMAND_KEY) printf("\t\t Right Command\n"); if(modifiers & B_LEFT_CONTROL_KEY) printf("\t\tLeft Control\n"); if(modifiers & B_RIGHT_CONTROL_KEY) printf("\t\tRight Control\n"); if(modifiers & B_LEFT_OPTION_KEY) printf("\t\tLeft Option\n"); if(modifiers & B_RIGHT_OPTION_KEY) printf("\t\tRight Option\n"); if(modifiers & B_LEFT_SHIFT_KEY) printf("\t\tLeft Shift\n"); if(modifiers & B_RIGHT_SHIFT_KEY) printf("\t\tRight Shift\n"); if(modifiers & B_MENU_KEY) printf("\t\tMenu\n"); } #endif if(_closerect.Contains(pt)) return CLICK_CLOSE; if(_zoomrect.Contains(pt)) return CLICK_ZOOM; if(_resizerect.Contains(pt) && _look==B_DOCUMENT_WINDOW_LOOK) return CLICK_RESIZE; // Clicking in the tab? if(_tabrect.Contains(pt)) { // Here's part of our window management stuff // if(buttons==B_PRIMARY_MOUSE_BUTTON && !GetFocus()) // return CLICK_MOVETOFRONT; if(buttons==B_SECONDARY_MOUSE_BUTTON) return CLICK_MOVETOBACK; return CLICK_DRAG; } // We got this far, so user is clicking on the border? BRect brect(_frame); brect.top+=19; BRect clientrect(brect.InsetByCopy(3,3)); if(brect.Contains(pt) && !clientrect.Contains(pt)) { if(_resizerect.Contains(pt)) return CLICK_RESIZE; return CLICK_DRAG; } // Guess user didn't click anything return CLICK_NONE; } void DefaultDecorator::_DoLayout(void) { //debugger(""); #ifdef DEBUG_DECORATOR printf("DefaultDecorator: Do Layout\n"); #endif // Here we determine the size of every rectangle that we use // internally when we are given the size of the client rectangle. switch(GetLook()) { case B_FLOATING_WINDOW_LOOK: case B_MODAL_WINDOW_LOOK: // We're going to make the frame 5 pixels wide, no matter what. R5's decorator frame // requires the skills of a gaming master to click on the tiny frame if resizing is necessary, // and there *are* apps which do this // borderwidth=3; // break; case B_BORDERED_WINDOW_LOOK: case B_TITLED_WINDOW_LOOK: case B_DOCUMENT_WINDOW_LOOK: borderwidth = 5; break; default: borderwidth = 0; } // Current version simply makes everything fit inside the rect // instead of building around it. This will change. // IT did :-) // distance from one item of the tab bar to another. In this case the text and close/zoom rects textoffset = (_look==B_FLOATING_WINDOW_LOOK) ? 7 : 10; // calculate or tab rect _tabrect.Set( _frame.left - borderwidth, _frame.top - borderwidth - 19.0, ((_frame.right - _frame.left) < 35.0 ? _frame.left + 35.0 : _frame.right) + borderwidth, _frame.top - (borderwidth-1) ); // make it text width sensitive if(strlen(GetTitle())>1) { if(_driver) titlepixelwidth=_driver->StringWidth(GetTitle(),_TitleWidth(), &_layerdata); else titlepixelwidth=10; int32 tabLength = 14 + // _closerect width textoffset + titlepixelwidth + textoffset + 14 + // _zoomrect width 8; // margins int32 tabWidth = (int32)_tabrect.Width(); if ( tabLength < tabWidth ) _tabrect.right = _tabrect.left + tabLength; } else _tabrect.right = _tabrect.left + _tabrect.Width()/2; // calculate left/top/right/bottom borders if ( borderwidth != 0 ){ _borderrect = _frame.InsetByCopy( -borderwidth, -borderwidth ); leftborder.Set( _borderrect.left, _frame.top - borderwidth, _frame.left, _frame.bottom + borderwidth ); rightborder.Set( _frame.right, _frame.top - borderwidth, _borderrect.right, _frame.bottom + borderwidth ); topborder.Set( _borderrect.left, _borderrect.top, _borderrect.right, _frame.top ); bottomborder.Set( _borderrect.left, _frame.bottom, _borderrect.right, _borderrect.bottom ); } else{ // no border ... (?) useful when displaying windows that are just images _borderrect = _frame; leftborder.Set( 0.0, 0.0, -1.0, -1.0 ); rightborder.Set( 0.0, 0.0, -1.0, -1.0 ); topborder.Set( 0.0, 0.0, -1.0, -1.0 ); bottomborder.Set( 0.0, 0.0, -1.0, -1.0 ); } // calculate resize rect _resizerect.Set( _borderrect.right - 19.0, _borderrect.bottom - 19.0, _borderrect.right, _borderrect.bottom); // format tab rect for a floating window - make te rect smaller if ( _look == B_FLOATING_WINDOW_LOOK ){ _tabrect.InsetBy( 0, 2 ); _tabrect.OffsetBy( 0, 2 ); } // calulate close rect based on the tab rectangle _closerect.Set( _tabrect.left + 4.0, _tabrect.top + 4.0, _tabrect.left + 4.0 + 13.0, _tabrect.top + 4.0 + 13.0 ); // calulate zoom rect based on the tab rectangle _zoomrect.Set( _tabrect.right - 4.0 - 13.0, _tabrect.top + 4.0, _tabrect.right - 4.0, _tabrect.top + 4.0 + 13.0 ); // fromat close and zoom rects for a floating window - make rectangles smaller if ( _look == B_FLOATING_WINDOW_LOOK ){ _closerect.InsetBy( 1, 1 ); _zoomrect.InsetBy( 1, 1 ); _closerect.OffsetBy( 0, -2 ); _zoomrect.OffsetBy( 0, -2 ); } // Old version... /* _tabrect=_frame; _resizerect=_frame; _borderrect=_frame; _closerect=_frame; textoffset=(_look==B_FLOATING_WINDOW_LOOK)?5:7; _closerect.left+=(_look==B_FLOATING_WINDOW_LOOK)?2:4; _closerect.top+=(_look==B_FLOATING_WINDOW_LOOK)?6:4; _closerect.right=_closerect.left+10; _closerect.bottom=_closerect.top+10; _borderrect.top+=19; if(borderwidth) { // Set up the border rectangles to handle the window's frame rightborder=leftborder=topborder=bottomborder=_borderrect; // We want the rectangles to intersect because of the beveled intersections, so all // that is necessary is to set the short dimension of each side leftborder.right=leftborder.left+borderwidth; rightborder.left=rightborder.right-borderwidth; topborder.bottom=topborder.top+borderwidth; bottomborder.top=bottomborder.bottom-borderwidth; } _resizerect.top=_resizerect.bottom-18; _resizerect.left=_resizerect.right-18; _tabrect.bottom=_tabrect.top+18; if(strlen(GetTitle())>1) { if(_driver) titlepixelwidth=_driver->StringWidth(GetTitle(),_TitleWidth(), &_layerdata); else titlepixelwidth=10; if(_closerect.right+textoffset+titlepixelwidth+35< _frame.Width()-1) _tabrect.right=_tabrect.left+titlepixelwidth; } else _tabrect.right=_tabrect.left+_tabrect.Width()/2; if(_look==B_FLOATING_WINDOW_LOOK) _tabrect.top+=4; _zoomrect=_tabrect; _zoomrect.top+=(_look==B_FLOATING_WINDOW_LOOK)?2:4; _zoomrect.right-=4; _zoomrect.bottom-=4; _zoomrect.left=_zoomrect.right-10; _zoomrect.bottom=_zoomrect.top+10; */ } void DefaultDecorator::MoveBy(float x, float y) { MoveBy(BPoint(x,y)); } void DefaultDecorator::MoveBy(BPoint pt) { #ifdef DEBUG_DECORATOR printf("DefaultDecorator: Move By (%.1f, %.1f)\n",pt.x,pt.y); #endif // Move all internal rectangles the appropriate amount _frame.OffsetBy(pt); _closerect.OffsetBy(pt); _tabrect.OffsetBy(pt); _resizerect.OffsetBy(pt); _borderrect.OffsetBy(pt); _zoomrect.OffsetBy(pt); leftborder.OffsetBy(pt); rightborder.OffsetBy(pt); topborder.OffsetBy(pt); bottomborder.OffsetBy(pt); Draw( _borderrect ); } BRegion * DefaultDecorator::GetFootprint(void) { #ifdef DEBUG_DECORATOR printf("DefaultDecorator: Get Footprint\n"); #endif // This function calculates the decorator's footprint in coordinates // relative to the layer. This is most often used to set a WinBorder // object's visible region. BRegion *reg=new BRegion(_borderrect); reg->Include(_tabrect); return reg; } void DefaultDecorator::_DrawTitle(BRect r) { printf("_DrawTitle(%f,%f,%f,%f)\n", r.left, r.top, r.right, r.bottom); // Designed simply to redraw the title when it has changed on // the client side. _layerdata.highcolor=_colors->window_tab_text; _layerdata.lowcolor=(GetFocus())?_colors->window_tab:_colors->inactive_window_tab; int32 titlecount=_ClipTitle((_zoomrect.left-textoffset)-(_closerect.right+textoffset)); BString titlestr( GetTitle() ); if(titlecountDrawString(titlestr.String(),titlecount, BPoint(_closerect.right+textoffset,_closerect.bottom-1),&_layerdata); } void DefaultDecorator::_SetFocus(void) { // SetFocus() performs necessary duties for color swapping and // other things when a window is deactivated or activated. if(GetFocus()) { // ADI: a temporary hack - the colors were TOO dark // button_highcol.SetColor(tint_color(_colors->window_tab.GetColor32(),B_LIGHTEN_2_TINT)); // button_lowcol.SetColor(tint_color(_colors->window_tab.GetColor32(),B_DARKEN_2_TINT)); button_highcol.SetColor( RGBColor( 255, 255, 0 ) ); button_lowcol.SetColor( RGBColor( 234, 181, 0) ); textcol=_colors->window_tab_text; } else { // ADI: a temporary hack - the colors were TOO dark // button_highcol.SetColor(tint_color(_colors->inactive_window_tab.GetColor32(),B_LIGHTEN_2_TINT)); // button_lowcol.SetColor(tint_color(_colors->inactive_window_tab.GetColor32(),B_DARKEN_2_TINT)); button_highcol.SetColor( RGBColor(234, 181, 0) ); button_lowcol.SetColor( RGBColor( 255, 255, 0 ) ); textcol=_colors->inactive_window_tab_text; } } void DefaultDecorator::Draw(BRect update) { #ifdef DEBUG_DECORATOR printf("DefaultDecorator: Draw(%.1f,%.1f,%.1f,%.1f)\n",update.left,update.top,update.right,update.bottom); #endif // We need to draw a few things: the tab, the resize thumb, the borders, // and the buttons // Draw the top view's client area - just a hack :) _layerdata.highcolor=_colors->document_background; /* if(_borderrect.Intersects(update)) _driver->FillRect(_borderrect & update,&_layerdata,pat_solidhigh); */ _DrawFrame(update); _DrawTab(update); } void DefaultDecorator::Draw(void) { // Easy way to draw everything - no worries about drawing only certain // things // Draw the top view's client area - just a hack :) // _layerdata.highcolor=_colors->document_background; // _driver->FillRect(_borderrect,&_layerdata,pat_solidhigh); DrawFrame(); DrawTab(); } void DefaultDecorator::_DrawZoom(BRect r) { printf("_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() ); } void DefaultDecorator::_DrawClose(BRect r) { printf("_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()); } void DefaultDecorator::_DrawTab(BRect r) { printf("_DrawTab(%f,%f,%f,%f)\n", r.left, r.top, r.right, r.bottom); // If a window has a tab, this will draw it and any buttons which are // in it. if(_look==B_NO_BORDER_WINDOW_LOOK) return; _layerdata.highcolor=(GetFocus())?_colors->window_tab:_colors->inactive_window_tab; _driver->FillRect(_tabrect,&_layerdata,pat_solidhigh); _layerdata.highcolor=framecolors[2]; _driver->StrokeLine(_tabrect.LeftTop(),_tabrect.LeftBottom(),&_layerdata,pat_solidhigh); _driver->StrokeLine(_tabrect.LeftTop(),_tabrect.RightTop(),&_layerdata,pat_solidhigh); _layerdata.highcolor=framecolors[4]; _driver->StrokeLine(_tabrect.RightTop(),_tabrect.RightBottom(),&_layerdata,pat_solidhigh); _layerdata.highcolor=framecolors[1]; _driver->StrokeLine( BPoint( _tabrect.left + 2, _tabrect.bottom ), BPoint( _tabrect.right - 2, _tabrect.bottom ), &_layerdata,pat_solidhigh); _layerdata.highcolor = RGBColor( 255, 255, 0 ); _driver->StrokeLine( BPoint( _tabrect.left + 1, _tabrect.top + 1), BPoint( _tabrect.left + 1, _tabrect.bottom), &_layerdata, pat_solidhigh); _driver->StrokeLine( BPoint( _tabrect.left + 1, _tabrect.top + 1), BPoint( _tabrect.right - 1, _tabrect.top + 1), &_layerdata, pat_solidhigh); _layerdata.highcolor = RGBColor( 175, 123, 0 ); _driver->StrokeLine( BPoint( _tabrect.right - 1, _tabrect.top + 2), BPoint( _tabrect.right - 1, _tabrect.bottom), &_layerdata, pat_solidhigh); _DrawTitle(_tabrect); // Draw the buttons if we're supposed to if(!(_flags & B_NOT_CLOSABLE)) _DrawClose(_closerect); if(!(_flags & B_NOT_ZOOMABLE)) _DrawZoom(_zoomrect); } void DefaultDecorator::_SetColors(void) { _SetFocus(); } void DefaultDecorator::DrawBlendedRect(BRect r, bool down) { // This bad boy is used to draw a rectangle with a gradient. // Note that it is not part of the Decorator API - it's specific // to just the DefaultDecorator. Called by DrawZoom and DrawClose _layerdata.highcolor = RGBColor( 175, 123, 0 ); _driver->StrokeLine( r.LeftTop(), BPoint( r.left, r.bottom - 1 ), &_layerdata, pat_solidhigh); _driver->StrokeLine( r.LeftTop(), BPoint( r.right - 1, r.top ), &_layerdata, pat_solidhigh); _driver->StrokeLine( BPoint( r.right - 1, r.top + 2), BPoint( r.right - 1, r.bottom - 1), &_layerdata, pat_solidhigh); _driver->StrokeLine( BPoint( r.left + 2, r.bottom -1), BPoint( r.right - 2, r.bottom - 1), &_layerdata, pat_solidhigh); _layerdata.highcolor = RGBColor( 255, 255, 0 ); _driver->StrokeRect( BRect( r.left + 1, r.top + 1, r.right, r.bottom), &_layerdata, pat_solidhigh); r.InsetBy( 2, 2 ); int32 w=r.IntegerWidth(), h=r.IntegerHeight(); rgb_color tmpcol,halfcol, startcol, endcol; float rstep,gstep,bstep,i; int steps=(wStrokeLine(BPoint(r.left,r.top+i), BPoint(r.left+i,r.top),&_layerdata,pat_solidhigh); SetRGBColor(&tmpcol, uint8(halfcol.red-(i*rstep)), uint8(halfcol.green-(i*gstep)), uint8(halfcol.blue-(i*bstep))); _layerdata.highcolor=tmpcol; _driver->StrokeLine(BPoint(r.left+steps,r.top+i), BPoint(r.left+i,r.top+steps),&_layerdata,pat_solidhigh); } } void DefaultDecorator::_DrawFrame(BRect invalid) { // We need to test each side to determine whether or not it needs drawn. Additionally, // we must clip the lines drawn by this function to the invalid rectangle we are given #ifdef USE_VIEW_FILL_HACK _driver->FillRect(_frame,&_layerdata,pat_solidhigh); #endif if(!borderwidth){ return; } // Data specifically for the StrokeLineArray call. int32 numlines=0, maxlines=20; BPoint points[maxlines*2]; RGBColor colors[maxlines]; // For quick calculation of gradients for each side. Top is same as left, right is same as // bottom // int8 rightindices[borderwidth],leftindices[borderwidth]; int8 *rightindices=new int8[borderwidth], *leftindices=new int8[borderwidth]; if(borderwidth==5) { leftindices[0]=2; leftindices[1]=0; leftindices[2]=1; leftindices[3]=3; leftindices[4]=2; rightindices[0]=2; rightindices[1]=0; rightindices[2]=1; rightindices[3]=3; rightindices[4]=4; } else { // TODO: figure out border colors for floating window look leftindices[0]=2; leftindices[1]=2; leftindices[2]=1; leftindices[3]=1; leftindices[4]=4; rightindices[0]=2; rightindices[1]=2; rightindices[2]=1; rightindices[3]=1; rightindices[4]=4; } // Variables used in each calculation int32 startx,endx,starty,endy,i; bool topcorner,bottomcorner,leftcorner,rightcorner; int8 step,colorindex; BRect r; BPoint start, end; // Right side if(TestRectIntersection(rightborder,invalid)) { // We may not have to redraw the entire width of the frame itself. Rare case, but // it must be accounted for. startx=(int32) MAX(invalid.left,rightborder.left); endx=(int32) MIN(invalid.right,rightborder.right); // We'll need these flags to see if we must include the corners in final line // calculations r=(rightborder); r.bottom=r.top+borderwidth; topcorner=TestRectIntersection(invalid,r); r=rightborder; r.top=r.bottom-borderwidth; bottomcorner=TestRectIntersection(invalid,r); step=(borderwidth==5)?1:2; colorindex=0; // Generate the lines for this side for(i=startx+1; i<=endx; i++) { start.x=end.x=i; if(topcorner) { start.y=rightborder.top+(borderwidth-(i-rightborder.left)); start.y=MAX(start.y,invalid.top); } else start.y=MAX(start.y+borderwidth,invalid.top); if(bottomcorner) { end.y=rightborder.bottom-(borderwidth-(i-rightborder.left)); end.y=MIN(end.y,invalid.bottom); } else end.y=MIN(end.y-borderwidth,invalid.bottom); // Make the appropriate points[numlines*2]=start; points[(numlines*2)+1]=end; colors[numlines]=framecolors[rightindices[colorindex]]; colorindex+=step; numlines++; } } // Left side if(TestRectIntersection(leftborder,invalid)) { // We may not have to redraw the entire width of the frame itself. Rare case, but // it must be accounted for. startx=(int32) MAX(invalid.left,leftborder.left); endx=(int32) MIN(invalid.right,leftborder.right); // We'll need these flags to see if we must include the corners in final line // calculations r=leftborder; r.bottom=r.top+borderwidth; topcorner=TestRectIntersection(invalid,r); r=leftborder; r.top=r.bottom-borderwidth; bottomcorner=TestRectIntersection(invalid,r); step=(borderwidth==5)?1:2; colorindex=0; // Generate the lines for this side for(i=startx; iStrokeLineArray(points,numlines,colors,&_layerdata); delete rightindices; delete leftindices; // Draw the resize thumb if we're supposed to if(!(_flags & B_NOT_RESIZABLE)) { r=_resizerect; // int32 w=r.IntegerWidth(), h=r.IntegerHeight(); // This code is strictly for B_DOCUMENT_WINDOW looks if(_look==B_DOCUMENT_WINDOW_LOOK) { r.right-=4; r.bottom-=4; _layerdata.highcolor=framecolors[2]; _driver->StrokeLine(r.LeftTop(),r.RightTop(),&_layerdata,pat_solidhigh); _driver->StrokeLine(r.LeftTop(),r.LeftBottom(),&_layerdata,pat_solidhigh); r.OffsetBy(1,1); _layerdata.highcolor=framecolors[0]; _driver->StrokeLine(r.LeftTop(),r.RightTop(),&_layerdata,pat_solidhigh); _driver->StrokeLine(r.LeftTop(),r.LeftBottom(),&_layerdata,pat_solidhigh); r.OffsetBy(1,1); _layerdata.highcolor=framecolors[1]; _driver->FillRect(r,&_layerdata,pat_solidhigh); /* r.left+=2; r.top+=2; r.right-=3; r.bottom-=3; */ r.right-=2; r.bottom-=2; int32 w=r.IntegerWidth(), h=r.IntegerHeight(); rgb_color halfcol, startcol, endcol; float rstep,gstep,bstep,i; int steps=(wLock(); for(i=0;i<=steps; i++) { _layerdata.highcolor.SetColor(uint8(startcol.red-(i*rstep)), uint8(startcol.green-(i*gstep)), uint8(startcol.blue-(i*bstep))); _driver->StrokeLine(BPoint(r.left,r.top+i), BPoint(r.left+i,r.top),&_layerdata,pat_solidhigh); _layerdata.highcolor.SetColor(uint8(halfcol.red-(i*rstep)), uint8(halfcol.green-(i*gstep)), uint8(halfcol.blue-(i*bstep))); _driver->StrokeLine(BPoint(r.left+steps,r.top+i), BPoint(r.left+i,r.top+steps),&_layerdata,pat_solidhigh); } _driver->Unlock(); // _layerdata.highcolor=framecolors[4]; // _driver->StrokeRect(r,&_layerdata,pat_solidhigh); } else { _layerdata.highcolor=framecolors[2]; _driver->StrokeLine(BPoint(r.right-4,r.top),BPoint(r.right-2,r.top), &_layerdata,pat_solidhigh); _driver->StrokeLine(BPoint(r.left,r.bottom-4),BPoint(r.left,r.bottom-2), &_layerdata,pat_solidhigh); } } }