* Headers/Additions/GNUstepGUI/GSTheme.h: Remove GSScrollViewBottomCorner

part name, instead themes should just provide a part called NSScrollView.

	Add -scrollViewScrollersOverlapBorders method.

	* Source/GSTheme.m: Remove GSScrollViewBottomCorner part name.
	* Source/GSThemeDrawing.m: Add -scrollViewScrollersOverlapBorders.
	* Source/GSThemeDrawing.m (-drawBrowserRect:...): If
	-scrollViewScrollersOverlapBorders is enabled, fill the browser background
	with the NSScrollView tile.
	* Source/GSThemeDrawing.m (-drawScrollViewRect:...): If
	-scrollViewScrollersOverlapBorders is enabled, fill the scroll view background
	with the NSScrollView tile.
	* Source/NSScroller.m (-rectForPart:): Change the meaning of the
	GSScrollerKnobOvershoot default so the knob only overlaps the buttons
	by this much (rather than both ends of the track). Turns out this is more
	useful for themes.
	* Source/NSScrollView.m (-tile): Add support for
	-[GSTheme scrollViewScrollersOverlapBorders]
	* Source/NSBrowser.m (-tile): Add support for
	-[GSTheme scrollViewScrollersOverlapBorders] and
	-[GSTheme scrollViewUseBottomCorner]

	The overall point of these additions is to support NSScrollView and
	NSBrowser looking like: http://jesseross.com/clients/gnustep/ui/concepts/


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@37238 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
ericwa 2013-10-15 23:26:51 +00:00
parent 7ebdcd6517
commit 240f754c33
7 changed files with 209 additions and 54 deletions

View file

@ -1,3 +1,31 @@
2013-10-15 Eric Wasylishen <ewasylishen@gmail.com>
* Headers/Additions/GNUstepGUI/GSTheme.h: Remove GSScrollViewBottomCorner
part name, instead themes should just provide a part called NSScrollView.
Add -scrollViewScrollersOverlapBorders method.
* Source/GSTheme.m: Remove GSScrollViewBottomCorner part name.
* Source/GSThemeDrawing.m: Add -scrollViewScrollersOverlapBorders.
* Source/GSThemeDrawing.m (-drawBrowserRect:...): If
-scrollViewScrollersOverlapBorders is enabled, fill the browser background
with the NSScrollView tile.
* Source/GSThemeDrawing.m (-drawScrollViewRect:...): If
-scrollViewScrollersOverlapBorders is enabled, fill the scroll view background
with the NSScrollView tile.
* Source/NSScroller.m (-rectForPart:): Change the meaning of the
GSScrollerKnobOvershoot default so the knob only overlaps the buttons
by this much (rather than both ends of the track). Turns out this is more
useful for themes.
* Source/NSScrollView.m (-tile): Add support for
-[GSTheme scrollViewScrollersOverlapBorders]
* Source/NSBrowser.m (-tile): Add support for
-[GSTheme scrollViewScrollersOverlapBorders] and
-[GSTheme scrollViewUseBottomCorner]
The overall point of these additions is to support NSScrollView and
NSBrowser looking like: http://jesseross.com/clients/gnustep/ui/concepts/
2013-10-15 Eric Wasylishen <ewasylishen@gmail.com> 2013-10-15 Eric Wasylishen <ewasylishen@gmail.com>
* Source/NSTableView.m (-tile): Check the GSScrollViewNoInnerBorder * Source/NSTableView.m (-tile): Check the GSScrollViewNoInnerBorder

View file

@ -268,9 +268,6 @@ APPKIT_EXPORT NSString *GSScrollerUpArrow;
APPKIT_EXPORT NSString *GSScrollerVerticalKnob; APPKIT_EXPORT NSString *GSScrollerVerticalKnob;
APPKIT_EXPORT NSString *GSScrollerVerticalSlot; APPKIT_EXPORT NSString *GSScrollerVerticalSlot;
/* Scroll view parts */
APPKIT_EXPORT NSString *GSScrollViewBottomCorner;
/* Names for table view parts */ /* Names for table view parts */
APPKIT_EXPORT NSString *GSTableHeader; APPKIT_EXPORT NSString *GSTableHeader;
APPKIT_EXPORT NSString *GSTableCorner; APPKIT_EXPORT NSString *GSTableCorner;
@ -891,7 +888,22 @@ APPKIT_EXPORT NSString *GSThemeWillDeactivateNotification;
*/ */
- (float) defaultScrollerWidth; - (float) defaultScrollerWidth;
- (BOOL) scrolViewUseBottomCorner; /**
* If YES, instructs NSScrollView to leave an empty square space where
* the horizontal and vertical scrollers meet.
*
* Controlled by user default GSScrollViewUseBottomCorner; default YES.
*/
- (BOOL) scrollViewUseBottomCorner;
/**
* If YES, instructs NSScrollView to make the scrollers overlap the border.
* The scroll view border is drawn using the NSScrollView part, which
* must be provided by the theme if this method returns YES.
*
* Controlled by user default GSScrollViewScrollersOverlapBorders; default NO;
*/
- (BOOL) scrollViewScrollersOverlapBorders;
/** /**
* Method for toolbar theming. * Method for toolbar theming.

View file

@ -77,9 +77,6 @@ NSString *GSScrollerUpArrow = @"GSScrollerUpArrow";
NSString *GSScrollerVerticalKnob = @"GSScrollerVerticalKnob"; NSString *GSScrollerVerticalKnob = @"GSScrollerVerticalKnob";
NSString *GSScrollerVerticalSlot = @"GSScrollerVerticalSlot"; NSString *GSScrollerVerticalSlot = @"GSScrollerVerticalSlot";
// Scroll view parts
NSString *GSScrollViewBottomCorner = @"GSScrollViewBottomCorner";
// Table view part names // Table view part names
NSString *GSTableHeader = @"GSTableHeader"; NSString *GSTableHeader = @"GSTableHeader";
NSString *GSTableCorner = @"GSTableCorner"; NSString *GSTableCorner = @"GSTableCorner";

View file

@ -611,7 +611,7 @@
return defaultScrollerWidth; return defaultScrollerWidth;
} }
- (BOOL) scrolViewUseBottomCorner - (BOOL) scrollViewUseBottomCorner
{ {
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
if ([defs objectForKey: @"GSScrollViewUseBottomCorner"] != nil) if ([defs objectForKey: @"GSScrollViewUseBottomCorner"] != nil)
@ -621,6 +621,16 @@
return YES; return YES;
} }
- (BOOL) scrollViewScrollersOverlapBorders
{
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
if ([defs objectForKey: @"GSScrollViewScrollersOverlapBorders"] != nil)
{
return [defs boolForKey: @"GSScrollViewScrollersOverlapBorders"];
}
return NO;
}
- (NSColor *) toolbarBackgroundColor - (NSColor *) toolbarBackgroundColor
{ {
NSColor *color; NSColor *color;
@ -2435,6 +2445,21 @@ typedef enum {
} }
} }
} }
if (![self browserUseBezels]
&& [self scrollViewScrollersOverlapBorders])
{
NSRect baseRect = NSMakeRect(0, 0, bounds.size.width, 1);
NSRect colFrame = [browser frameOfColumn: [browser firstVisibleColumn]];
NSRect scrollViewRect = NSUnionRect(baseRect, colFrame);
GSDrawTiles *tiles = [self tilesNamed: @"NSScrollView"
state: GSThemeNormalState];
[self fillRect: scrollViewRect
withTiles: tiles
background: [NSColor clearColor]];
}
} }
- (CGFloat) browserColumnSeparation - (CGFloat) browserColumnSeparation
@ -2521,6 +2546,7 @@ typedef enum {
NSRect bounds = [view bounds]; NSRect bounds = [view bounds];
BOOL hasInnerBorder = ![[NSUserDefaults standardUserDefaults] BOOL hasInnerBorder = ![[NSUserDefaults standardUserDefaults]
boolForKey: @"GSScrollViewNoInnerBorder"]; boolForKey: @"GSScrollViewNoInnerBorder"];
GSDrawTiles *tiles = nil;
name = [theme nameForElement: self]; name = [theme nameForElement: self];
if (name == nil) if (name == nil)
@ -2528,28 +2554,38 @@ typedef enum {
name = @"NSScrollView"; name = @"NSScrollView";
} }
color = [theme colorNamed: name state: GSThemeNormalState]; color = [theme colorNamed: name state: GSThemeNormalState];
tiles = [theme tilesNamed: name state: GSThemeNormalState];
if (color == nil) if (color == nil)
{ {
color = [NSColor controlDarkShadowColor]; color = [NSColor controlDarkShadowColor];
} }
switch (borderType) if (tiles == nil)
{ {
case NSNoBorder: switch (borderType)
break; {
case NSNoBorder:
case NSLineBorder: break;
[color set];
NSFrameRect(bounds); case NSLineBorder:
break; [color set];
NSFrameRect(bounds);
case NSBezelBorder: break;
[theme drawGrayBezel: bounds withClip: rect];
break; case NSBezelBorder:
[theme drawGrayBezel: bounds withClip: rect];
case NSGrooveBorder: break;
[theme drawGroove: bounds withClip: rect];
break; case NSGrooveBorder:
[theme drawGroove: bounds withClip: rect];
break;
}
}
else
{
[self fillRect: bounds
withTiles: tiles
background: [NSColor clearColor]];
} }
if (hasInnerBorder) if (hasInnerBorder)
@ -2600,26 +2636,6 @@ typedef enum {
DPSstroke(ctxt); DPSstroke(ctxt);
} }
} }
if (![self scrolViewUseBottomCorner]
&& [scrollView hasHorizontalScroller]
&& [scrollView hasVerticalScroller])
{
NSScroller *vertScroller = [scrollView verticalScroller];
NSScroller *horizScroller = [scrollView horizontalScroller];
NSRect bottomCornerRect = NSMakeRect([vertScroller frame].origin.x,
[horizScroller frame].origin.y,
NSWidth([vertScroller frame]),
NSHeight([horizScroller frame]));
GSDrawTiles *tiles = [self tilesNamed: GSScrollViewBottomCorner
state: GSThemeNormalState];
[self fillRect: bottomCornerRect
withTiles: tiles
background: [NSColor clearColor]];
}
} }
- (void) drawSliderBorderAndBackground: (NSBorderType)aType - (void) drawSliderBorderAndBackground: (NSBorderType)aType

View file

@ -1811,6 +1811,12 @@ static BOOL browserUseBezels;
else else
rect.size.width = _frame.size.width - rect.size.width = _frame.size.width -
(rect.origin.x + bezelBorderSize.width); (rect.origin.x + bezelBorderSize.width);
// FIXME: Assumes left-side scrollers
if ([[GSTheme theme] scrollViewScrollersOverlapBorders])
{
rect.size.width -= 1;
}
} }
if (rect.size.width < 0) if (rect.size.width < 0)
@ -1863,6 +1869,8 @@ static BOOL browserUseBezels;
NSSize bezelBorderSize = NSZeroSize; NSSize bezelBorderSize = NSZeroSize;
NSInteger i, num, columnCount, delta; NSInteger i, num, columnCount, delta;
CGFloat frameWidth; CGFloat frameWidth;
const BOOL overlapBorders = [[GSTheme theme] scrollViewScrollersOverlapBorders];
const BOOL useBottomCorner = [[GSTheme theme] scrollViewUseBottomCorner];
if (browserUseBezels) if (browserUseBezels)
bezelBorderSize = [[GSTheme theme] sizeForBorderType: NSBezelBorder]; bezelBorderSize = [[GSTheme theme] sizeForBorderType: NSBezelBorder];
@ -1892,6 +1900,21 @@ static BOOL browserUseBezels;
else else
_columnSize.height -= scrollerWidth + (2 * bezelBorderSize.height); _columnSize.height -= scrollerWidth + (2 * bezelBorderSize.height);
// "Bottom corner" box
if (!browserUseBezels && !useBottomCorner)
{
_scrollerRect.origin.x += scrollerWidth;
_scrollerRect.size.width -= scrollerWidth;
}
/** Horizontall expand the scroller by GSScrollerKnobOvershoot on the left */
if (overlapBorders)
{
// FIXME: Assumes left scroller
_scrollerRect.origin.x -= 1;
_scrollerRect.size.width += 1;
}
if (!NSEqualRects(_scrollerRect, [_horizontalScroller frame])) if (!NSEqualRects(_scrollerRect, [_horizontalScroller frame]))
{ {
[_horizontalScroller setFrame: _scrollerRect]; [_horizontalScroller setFrame: _scrollerRect];

View file

@ -1064,6 +1064,12 @@ static CGFloat scrollerWidth;
[self tile]; [self tile];
} }
static NSRectEdge
GSOppositeEdge(NSRectEdge edge)
{
return (edge == NSMinXEdge) ? NSMaxXEdge : NSMinXEdge;
}
- (void) tile - (void) tile
{ {
NSRect headerRect, contentRect; NSRect headerRect, contentRect;
@ -1075,8 +1081,9 @@ static CGFloat scrollerWidth;
CGFloat innerBorderWidth = [[NSUserDefaults standardUserDefaults] CGFloat innerBorderWidth = [[NSUserDefaults standardUserDefaults]
boolForKey: @"GSScrollViewNoInnerBorder"] ? 0.0 : 1.0; boolForKey: @"GSScrollViewNoInnerBorder"] ? 0.0 : 1.0;
BOOL useBottomCorner = [[GSTheme theme] scrolViewUseBottomCorner]; const BOOL useBottomCorner = [[GSTheme theme] scrollViewUseBottomCorner];
const BOOL overlapBorders = [[GSTheme theme] scrollViewScrollersOverlapBorders];
style = NSInterfaceStyleForKey(@"NSScrollViewInterfaceStyle", nil); style = NSInterfaceStyleForKey(@"NSScrollViewInterfaceStyle", nil);
if (style == NSMacintoshInterfaceStyle if (style == NSMacintoshInterfaceStyle
@ -1098,7 +1105,11 @@ static CGFloat scrollerWidth;
} }
/* Prepare the contentRect by insetting the borders. */ /* Prepare the contentRect by insetting the borders. */
contentRect = NSInsetRect(_bounds, border.width, border.height); contentRect = _bounds;
if (!overlapBorders)
contentRect = NSInsetRect(contentRect, border.width, border.height);
if (contentRect.size.width < 0 || contentRect.size.height < 0) if (contentRect.size.width < 0 || contentRect.size.height < 0)
{ {
/* FIXME ... should we do something else when given /* FIXME ... should we do something else when given
@ -1108,6 +1119,32 @@ static CGFloat scrollerWidth;
[self _synchronizeHeaderAndCornerView]; [self _synchronizeHeaderAndCornerView];
if (overlapBorders)
{
if (_borderType != NSNoBorder)
{
if (!(_hasHeaderView || _hasCornerView))
{
// Inset 1px on the top
NSDivideRect(contentRect, NULL, &contentRect, 1, topEdge);
}
if (!_hasVertScroller)
{
// Inset 1px on the edge where the vertical scroller would be
NSDivideRect(contentRect, NULL, &contentRect, 1, verticalScrollerEdge);
}
if (!_hasHorizScroller)
{
NSDivideRect(contentRect, NULL, &contentRect, 1, bottomEdge);
}
// The vertical edge without a scroller
{
NSDivideRect(contentRect, NULL, &contentRect, 1,
GSOppositeEdge(verticalScrollerEdge));
}
}
}
/* First, allocate vertical space for the headerView / cornerView /* First, allocate vertical space for the headerView / cornerView
(but - NB - the headerView needs to be placed above the clipview (but - NB - the headerView needs to be placed above the clipview
later on, we can't place it now). */ later on, we can't place it now). */
@ -1151,6 +1188,13 @@ static CGFloat scrollerWidth;
scrollerWidth, bottomEdge); scrollerWidth, bottomEdge);
} }
/** Vertically expand the scroller by 1pt on each end */
if (overlapBorders)
{
vertScrollerRect.origin.y -= 1;
vertScrollerRect.size.height += 2;
}
[_vertScroller setFrame: vertScrollerRect]; [_vertScroller setFrame: vertScrollerRect];
/* Substract 1 for the line that separates the vertical scroller /* Substract 1 for the line that separates the vertical scroller
@ -1167,6 +1211,13 @@ static CGFloat scrollerWidth;
NSDivideRect (contentRect, &horizScrollerRect, &contentRect, NSDivideRect (contentRect, &horizScrollerRect, &contentRect,
scrollerWidth, bottomEdge); scrollerWidth, bottomEdge);
/** Horizontall expand the scroller by 1pt on each end */
if (overlapBorders)
{
horizScrollerRect.origin.x -= 1;
horizScrollerRect.size.width += 2;
}
[_horizScroller setFrame: horizScrollerRect]; [_horizScroller setFrame: horizScrollerRect];
/* Substract 1 for the width for the line that separates the /* Substract 1 for the width for the line that separates the
@ -1300,10 +1351,10 @@ static CGFloat scrollerWidth;
- (BOOL) isOpaque - (BOOL) isOpaque
{ {
// FIXME: Only needs to be NO in a corner case, // FIXME: Only needs to be NO in a corner case,
// when [[GSTheme theme] scrolViewUseBottomCorner] is NO // when [[GSTheme theme] scrollViewUseBottomCorner] is NO
// and the theme tile for the bottom corner is transparent. // and the theme tile for the bottom corner is transparent.
// So maybe cache the value of // So maybe cache the value of
// [[GSTheme theme] scrolViewUseBottomCorner] and check it here. // [[GSTheme theme] scrollViewUseBottomCorner] and check it here.
return NO; return NO;
} }
@ -1739,6 +1790,13 @@ static CGFloat scrollerWidth;
- (void) _themeDidActivate: (NSNotification*)notification - (void) _themeDidActivate: (NSNotification*)notification
{ {
// N.B. Reload cached [NSScroller scrollerWidth] since the
// new theme may have a different scroller width.
//
// Since scrollerWidth is a static, it will get overwritten
// several times; doesn't matter though.
scrollerWidth = [NSScroller scrollerWidth];
[self tile]; [self tile];
} }

View file

@ -68,8 +68,8 @@ static NSCell *horizontalKnobSlotCell = nil;
static NSCell *verticalKnobSlotCell = nil; static NSCell *verticalKnobSlotCell = nil;
static CGFloat scrollerWidth = 0.0; static CGFloat scrollerWidth = 0.0;
/** /**
* This is the amount (in userspace points) by which the knob slides beyond * This is the amount (in userspace points) by which the knob slides over the
* either end of the track. Typical use would be to set it to 1 when both * button ends of the track. Typical use would be to set it to 1 when both
* the knob and the buttons have a 1-point border, so that when the knob is * the knob and the buttons have a 1-point border, so that when the knob is
* at its maximum, it overlaps the button by 1 point giving a resulting * at its maximum, it overlaps the button by 1 point giving a resulting
* 1-point wide border. * 1-point wide border.
@ -1229,8 +1229,29 @@ static float buttonsOffset = 1.0; // buttonsWidth = sw - 2*buttonsOffset
knobHeight = buttonsWidth; knobHeight = buttonsWidth;
/* calc knob's position */ /* calc knob's position */
knobPosition = floor((float)_doubleValue * (slotHeight - knobHeight + (2 * scrollerKnobOvershoot)))
- scrollerKnobOvershoot; {
CGFloat knobOvershootAbove = scrollerKnobOvershoot;
CGFloat knobOvershootBelow = scrollerKnobOvershoot;
if (arrowsSameEnd
&& _arrowsPosition == NSScrollerArrowsMinEnd)
{
knobOvershootBelow = 0;
}
else if (arrowsSameEnd
&& _arrowsPosition == NSScrollerArrowsMaxEnd)
{
knobOvershootAbove = 0;
}
else if (_arrowsPosition == NSScrollerArrowsNone)
{
knobOvershootAbove = 0;
knobOvershootBelow = 0;
}
knobPosition = floor((float)_doubleValue * (slotHeight - knobHeight + knobOvershootAbove + knobOvershootBelow))
- knobOvershootAbove;
}
if (arrowsSameEnd) if (arrowsSameEnd)
{ {