Make toolbar resizing behavior match the Cocoa behavior

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@30440 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Doug Simons 2010-05-21 15:01:45 +00:00
parent 70ab53498d
commit 24fad47739
3 changed files with 142 additions and 89 deletions

View file

@ -1,3 +1,11 @@
2010-05-21 Doug Simons <doug.simons@testplant.com>
* Source/GSToolbarView.m:
* Source/NSToolbarItem.m:
Make toolbar resizing behavior match the Cocoa behavior for dividing
extra space between flexible spaces and other flexible items. Ensure
custom view items are resized properly, taking minSize into account.
2010-05-20 04:14-EDT Gregory John Casamento <greg.casamento@gmail.com>
* Headers/Additions/GNUstepGUI/GSTheme.h: Added method

View file

@ -60,6 +60,9 @@ typedef enum {
ToolbarViewSmallHeight = 52
} ToolbarViewHeight;
// Borrow this from NSToolbarItem.m
static const int InsetItemViewX = 10;
static const int ClippedItemsViewWidth = 28;
// Internal
@ -652,106 +655,143 @@ static void initSystemExtensionsColors(void)
- (void) _takeInAccountFlexibleSpaces
{
// Borrow this from NSToolbarItem.m
static const int InsetItemViewX = 10;
NSArray *items = [_toolbar items];
NSEnumerator *e;
NSToolbarItem *item;
float lengthAvailable;
unsigned int flexibleSpaceItemsNumber = 0;
NSView *backView, *view;
CGFloat lengthAvailable;
BOOL mustAdjustNext = NO;
CGFloat x = 0.0;
CGFloat maxX = 0.0;
CGFloat currX;
// resizement of a flexible item
CGFloat rel = 1.0;
// Width of a flexible space
CGFloat flexWidth = 0.0;
if ([items count] == 0)
CGFloat x = 0, visibleItemsMinWidth = 0, backViewsWidth = 0;
NSMutableArray *variableWidthItems = [NSMutableArray array];
int flexibleItemsCount = 0, maxWidthItemsCount = 0;
CGFloat spacePerFlexItem, extraSpace = 0;
CGFloat toolbarWidth = [self frame].size.width;
int i, n = [items count];
NSMutableArray *visibleItems = [NSMutableArray array];
static const int FlexItemWeight = 4; // non-space flexible item counts as much as 4 flexible spaces
if (n == 0)
return;
currX = NSMaxX([[[items lastObject] _backView] frame]);
lengthAvailable = NSWidth([self frame]) - currX;
// First determine which items can fit in toolbar if all are at their minimum width.
// We'd like to show as many items as possible. These are our visibleItems.
for (i=0; i < n; i++)
{
item = [items objectAtIndex:i];
backView = [item _backView];
view = [item view];
if (view != nil)
backViewsWidth += [item minSize].width + 2*InsetItemViewX;
else
backViewsWidth += [backView frame].size.width;
if ((backViewsWidth + ClippedItemsViewWidth <= toolbarWidth)
|| (i == n - 1 && backViewsWidth <= toolbarWidth))
{
visibleItemsMinWidth = backViewsWidth;
[visibleItems addObject:item];
}
else
{
break;
}
}
// next, figure out how much additional space there is for expanding flexible items
lengthAvailable = toolbarWidth - visibleItemsMinWidth;
if ([visibleItems count] < n)
lengthAvailable -= ClippedItemsViewWidth;
if (lengthAvailable < 1)
return;
e = [items objectEnumerator];
while ((item = [e nextObject]) != nil)
{
if ([item _isFlexibleSpace])
{
flexibleSpaceItemsNumber++;
}
// Currently only item with a view are resizable
if ([item view] != nil)
{
maxX += [item maxSize].width + 2 * InsetItemViewX;
}
else
{
maxX += NSWidth([[item _backView] frame]);
}
}
// Could the items fill more space?
if (maxX >= currX)
{
rel = lengthAvailable / (maxX - currX);
if (rel > 1.0)
rel = 1.0;
}
// Are there any flexible spaces to fill the rest?
if (flexibleSpaceItemsNumber > 0)
{
flexWidth = (NSWidth([self frame]) - maxX) / flexibleSpaceItemsNumber;
if (flexWidth < 0.0)
flexWidth = 0.0;
}
e = [items objectEnumerator];
// We want to divide available space evenly among all flexible items, but some items may
// reach their maximum width, making more space available for the other items.
// To do this, first we count the flexible items, gathering a list of those that may
// have a maximum width.
// To match observed behavior on Cocoa (which is NOT as documented!) we allocate only 1/4
// as much space to flexible spaces as we do to other flexible items.
e = [visibleItems objectEnumerator];
while ((item = [e nextObject]) != nil)
{
NSView *view = [item view];
NSView *backView = [item _backView];
CGFloat diff = [item maxSize].width - [item minSize].width;
if ([item _isFlexibleSpace])
{
NSRect backViewFrame = [backView frame];
[backView setFrame: NSMakeRect(x, backViewFrame.origin.y,
flexWidth, backViewFrame.size.height)];
mustAdjustNext = YES;
flexibleItemsCount++;
}
if ((view != nil) && (diff > 0))
else
{
NSRect backViewFrame = [backView frame];
NSRect viewFrame = [view frame];
[backView setFrame: NSMakeRect(x, backViewFrame.origin.y,
(rel * diff) + [item minSize].width,
backViewFrame.size.height)];
// Subtract InsetItemViewX
viewFrame.size.width = (rel * diff) + [item minSize].width
- 2 * InsetItemViewX;
[view setFrame: viewFrame];
mustAdjustNext = YES;
CGFloat minWidth = [item minSize].width;
CGFloat maxWidth = [item maxSize].width;
if (minWidth < maxWidth)
{
[variableWidthItems addObject:item];
flexibleItemsCount += FlexItemWeight; // gets FlexItemWeight times the weight of a flexible space
}
}
else if (mustAdjustNext)
{
NSRect backViewFrame = [backView frame];
[backView setFrame: NSMakeRect(x, backViewFrame.origin.y,
backViewFrame.size.width, backViewFrame.size.height)];
}
x += NSWidth([backView frame]);
}
if (flexibleItemsCount == 0)
return;
// Now go through any variableWidthItems to see if the available space per item would
// cause any of them to exceed their maximum width, and calculate the extra space available
spacePerFlexItem = MAX(lengthAvailable / flexibleItemsCount, 0);
e = [variableWidthItems objectEnumerator];
while ((item = [e nextObject]) != nil)
{
CGFloat minWidth = [item minSize].width;
CGFloat maxWidth = [item maxSize].width;
if (maxWidth-minWidth < spacePerFlexItem * FlexItemWeight)
{
extraSpace += spacePerFlexItem * FlexItemWeight - (maxWidth-minWidth); // give back unneeded space
maxWidthItemsCount += FlexItemWeight;
}
}
// Recalculate spacePerFlexItem (unless all flexible items are going to their max width)
if (flexibleItemsCount > maxWidthItemsCount)
spacePerFlexItem += extraSpace / (flexibleItemsCount-maxWidthItemsCount);
// Finally, go through all items, adjusting their width and positioning them as needed
e = [items objectEnumerator];
while ((item = [e nextObject]) != nil)
{
backView = [item _backView];
if ([item _isFlexibleSpace])
{
NSRect backViewFrame = [backView frame];
[backView setFrame: NSMakeRect(x, backViewFrame.origin.y,
spacePerFlexItem,
backViewFrame.size.height)];
mustAdjustNext = YES;
}
else if ([variableWidthItems indexOfObjectIdenticalTo:item] != NSNotFound)
{
NSRect backViewFrame = [backView frame];
CGFloat maxFlex = [item maxSize].width - [item minSize].width;
CGFloat flexAmount = MIN(maxFlex, spacePerFlexItem * FlexItemWeight);
CGFloat newWidth = [item minSize].width + flexAmount + 2 * InsetItemViewX;
[backView setFrame: NSMakeRect(x, backViewFrame.origin.y,
newWidth,
backViewFrame.size.height)];
mustAdjustNext = YES;
}
else if (mustAdjustNext)
{
NSRect backViewFrame = [backView frame];
[backView setFrame: NSMakeRect(x, backViewFrame.origin.y,
backViewFrame.size.width, backViewFrame.size.height)];
}
view = [item view];
if (view != nil)
{
NSRect viewFrame = [view frame];
// Subtract InsetItemViewX
viewFrame.size.width = [backView frame].size.width - 2 * InsetItemViewX;
viewFrame.origin.x = InsetItemViewX;
[view setFrame: viewFrame];
}
x += [backView frame].size.width;
}
}
- (void) _handleViewsVisibility
@ -874,7 +914,7 @@ static void initSystemExtensionsColors(void)
- (NSArray *) _visibleBackViews
{
NSArray *items = [_toolbar items];
NSView *backView;
NSView *backView, *view;
int i, n = [items count];
float backViewsWidth = 0, toolbarWidth = [self frame].size.width;
@ -882,9 +922,13 @@ static void initSystemExtensionsColors(void)
for (i = 0; i < n; i++)
{
backView = [[items objectAtIndex:i] _backView];
backViewsWidth += [backView frame].size.width;
NSToolbarItem *item = [items objectAtIndex:i];
backView = [item _backView];
view = [item view];
if (view != nil)
backViewsWidth += [item minSize].width + 2*InsetItemViewX;
else
backViewsWidth += [backView frame].size.width;
if ((backViewsWidth + ClippedItemsViewWidth <= toolbarWidth)
|| (i == n - 1 && backViewsWidth <= toolbarWidth))

View file

@ -619,9 +619,10 @@ NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType";
[(id)view sizeToFit];
newSize = [view frame].size;
if (newSize.width < minSize.width || newSize.height < minSize.height)
if (minSize.width > 0 || newSize.height < minSize.height)
{
newSize.width = MAX(newSize.width, minSize.width);
if (minSize.width > 0)
newSize.width = minSize.width;
newSize.height = MAX(newSize.height, minSize.height);
[view setFrameSize: newSize];
}