• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: expanding the view area of a window - please help
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: expanding the view area of a window - please help


  • Subject: Re: expanding the view area of a window - please help
  • From: Kurt Revis <email@hidden>
  • Date: Mon, 18 Mar 2002 08:12:51 -0800

On Monday, March 18, 2002, at 07:34 AM, Manuel Arturo Marques Pita wrote:

What I'd like to do for ths second option (customise) is to have the same
thing they implement in applications such as Illustrator in which at the
botton of a window/panel there is a long rectangular button that expands that
window and shows more detailed controls. Pressing the button again collapses
the window to its original state, this happens in a nice animated
fashion...

Warning, long explanation ahead!

There are a couple of different things to do here.
* To resize the window, use -[NSWindow setFrame:display:animate:].
* To add the extra controls, get the view that they should be inside of (this may be your window's content view, or some other NSView or NSBox inside of that), and add each extra view using -[NSView addSubview:].

Getting all of the other details right is a little tricky, though:
* You need to make sure that your extra controls are in the nextKeyView loop when they are in the window, and take them out of the loop when they aren't.
* If your window is resizeable, and the "normal" controls in it are set up to resize with the window, their resize behavior needs to be different while the window is automatically resizing. (I forget all of the details...it's been a while since I handled this.)
* If your window isn't visible, don't animate the resize--it will take time even though nothing is actually shown on screen.

Here is the class I use. To see it in action, download my app MIDI Monitor: http://www.snoize.com/MIDIMonitor/

You use it by creating your window in a nib in the normal way, with everything set up in the configuration when the extra controls are shown. Select the extra controls, and select Layout->Make Subviews Of->Custom View in IB. Make the custom view be an instance of this class (DisclosableView). Hook up a button to the -toggleDisclosure: action of the DisclosableView.

(You will undoubtedly want to experiment with how your controls and the disclosable view are positioned. You can also set the disclosable view to have a non-zero height when the items in it are hidden, using -setHiddenHeight:.)

Hope this helps. Does anyone else have an implementation of something similar? I don't claim that mine is particularly fantastic or general or anything, but it works for me.


-------------------------------------------------------
DisclosableView.h:
-------------------------------------------------------
#import <Cocoa/Cocoa.h>

@interface DisclosableView : NSView
{
BOOL isShown;
double originalHeight;
double hiddenHeight;
NSArray *hiddenSubviews;
NSView *nonretainedOriginalNextKeyView;
NSView *nonretainedLastChildKeyView;
NSSize sizeBeforeHidden;
}

- (BOOL)isShown;
- (void)setIsShown:(BOOL)value;

- (double)hiddenHeight;
- (void)setHiddenHeight:(double)value;

// Actions
- (IBAction)toggleDisclosure:(id)sender;
- (IBAction)hide:(id)sender;
- (IBAction)show:(id)sender;

@end

-------------------------------------------------------
DisclosableView.m:
-------------------------------------------------------
#import "DisclosableView.h"


@interface DisclosableView (Private)

- (void)changeWindowHeightBy:(double)amount;

@end


@implementation DisclosableView

- (id)initWithFrame:(NSRect)frameRect;
{
if (!(self = [super initWithFrame:frameRect]))
return nil;

isShown = YES;
originalHeight = [self frame].size.height;
hiddenHeight = 0;

return self;
}

- (void)dealloc;
{
[hiddenSubviews release];

[super dealloc];
}

- (void)awakeFromNib;
{
if ([[self superclass] instancesRespondToSelector:@selector(awakeFromNib)])
[super awakeFromNib];

isShown = YES;
originalHeight = [self frame].size.height;
}

- (BOOL)acceptsFirstResponder
{
return NO;
}

- (BOOL)isShown;
{
return isShown;
}

- (void)setIsShown:(BOOL)value;
{
if (isShown != value) {
if (value)
[self show:nil];
else
[self hide:nil];
}
}

- (double)hiddenHeight;
{
return hiddenHeight;
}

- (void)setHiddenHeight:(double)value;
{
hiddenHeight = value;
}

//
// Actions
//

- (IBAction)toggleDisclosure:(id)sender;
{
if (isShown)
[self hide:sender];
else
[self show:sender];
}

- (IBAction)hide:(id)sender;
{
NSView *keyLoopView;
unsigned int subviewIndex;

if (!isShown)
return;

keyLoopView = [self nextKeyView];
if ([keyLoopView isDescendantOf:self]) {
// We need to remove our subviews (which will be hidden) from the key loop.

// Remember our nextKeyView so we can restore it later.
nonretainedOriginalNextKeyView = keyLoopView;

// Find the last view in the key loop which is one of our descendants.
nonretainedLastChildKeyView = keyLoopView;
while ((keyLoopView = [nonretainedLastChildKeyView nextKeyView])) {
if ([keyLoopView isDescendantOf:self])
nonretainedLastChildKeyView = keyLoopView;
else
break;
}

// Set our nextKeyView to its nextKeyView, and set its nextKeyView to nil.
// (If we don't do the last step, when we restore the key loop later, it will be missing views in the backwards direction.)
[self setNextKeyView:keyLoopView];
[nonretainedLastChildKeyView setNextKeyView:nil];
} else {
nonretainedOriginalNextKeyView = nil;
}

hiddenSubviews = [[NSArray alloc] initWithArray:[self subviews]];
subviewIndex = [hiddenSubviews count];
while (subviewIndex--)
[[hiddenSubviews objectAtIndex:subviewIndex] removeFromSuperview];

sizeBeforeHidden = [self frame].size;
[self setFrameSize:NSMakeSize(sizeBeforeHidden.width, hiddenHeight)];

[self changeWindowHeightBy:-(originalHeight - hiddenHeight)];

isShown = NO;
}

- (IBAction)show:(id)sender;
{
unsigned int subviewIndex;

if (isShown)
return;

[self changeWindowHeightBy:(originalHeight - hiddenHeight)];

[self setFrameSize:NSMakeSize([self frame].size.width, originalHeight)];

subviewIndex = [hiddenSubviews count];
while (subviewIndex--)
[self addSubview:[hiddenSubviews objectAtIndex:subviewIndex]];

[hiddenSubviews release];
hiddenSubviews = nil;

[self resizeSubviewsWithOldSize:sizeBeforeHidden];

if (nonretainedOriginalNextKeyView) {
// Restore the key loop to its old configuration.
[nonretainedLastChildKeyView setNextKeyView:[self nextKeyView]];
[self setNextKeyView:nonretainedOriginalNextKeyView];
}

isShown = YES;
}

@end


@implementation DisclosableView (Private)

- (void)changeWindowHeightBy:(double)amount;
{
// This turns out to be more complicated than one might expect, because the way that the other views in the window should move is different than the normal case that the AppKit handles.
// We want the other views in the window to stay the same size. If a view is above us, we want it to stay in the same position relative to the top of the window; likewise, if a view is below us, we want it to stay in the same position relative to the bottom of the window. However, views may have different autoresize masks configured.
// So, we save the old autoresize masks for all of the window's content view's immediate subviews, and set them how we want them.
// Then, we resize the window, and fix up the minimum and maximum sizes for the window.
// Afterwards, we restore the autoresize masks.
// (Also note that we do not want to modify our own autoresize mask.)

NSWindow *window;
NSView *contentView;
NSArray *windowSubviews;
unsigned int windowSubviewCount, windowSubviewIndex;
NSMutableArray *savedAutoresizeMasks;
NSRect newWindowFrame;
NSSize newWindowMinOrMaxSize;

window = [self window];
contentView = [window contentView];

windowSubviews = [contentView subviews];
windowSubviewCount = [windowSubviews count];
savedAutoresizeMasks = [NSMutableArray arrayWithCapacity:windowSubviewCount];

for (windowSubviewIndex = 0; windowSubviewIndex < windowSubviewCount; windowSubviewIndex++) {
NSView *windowSubview;
unsigned int autoresizingMask;

windowSubview = [windowSubviews objectAtIndex:windowSubviewIndex];
autoresizingMask = [windowSubview autoresizingMask];
[savedAutoresizeMasks addObject:[NSNumber numberWithUnsignedInt:autoresizingMask]];

if (windowSubview == self)
continue;

// We never want to anything to change height.
autoresizingMask &= ~NSViewHeightSizable;
if (NSMaxY([windowSubview frame]) >= NSMaxY([self frame])) {
// This subview is above us. Set it to be stuck to the top of the window.
autoresizingMask &= ~NSViewMaxYMargin;
autoresizingMask |= NSViewMinYMargin;
} else {
// This subview is below us. Set it to be stuck to the bottom of the window.
autoresizingMask |= NSViewMaxYMargin;
autoresizingMask &= ~NSViewMinYMargin;
}
[windowSubview setAutoresizingMask:autoresizingMask];
}

newWindowFrame = [window frame];
newWindowFrame.origin.y -= amount;
newWindowFrame.size.height += amount;
if ([window isVisible])
[window setFrame:newWindowFrame display:YES animate:YES];
else
[window setFrame:newWindowFrame display:NO];

newWindowMinOrMaxSize = [window minSize];
newWindowMinOrMaxSize.height += amount;
[window setMinSize:newWindowMinOrMaxSize];

newWindowMinOrMaxSize = [window maxSize];
// If there is no max size set (height of 0), don't change it.
if (newWindowMinOrMaxSize.height > 0) {
newWindowMinOrMaxSize.height += amount;
[window setMaxSize:newWindowMinOrMaxSize];
}

for (windowSubviewIndex = 0; windowSubviewIndex < windowSubviewCount; windowSubviewIndex++) {
NSView *windowSubview;

windowSubview = [windowSubviews objectAtIndex:windowSubviewIndex];
if (windowSubview == self)
continue;

[windowSubview setAutoresizingMask:[[savedAutoresizeMasks objectAtIndex:windowSubviewIndex] unsignedIntValue]];
}
}

@end



--
Kurt Revis
email@hidden
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.

  • Follow-Ups:
    • Re: expanding the view area of a window - please help
      • From: Manuel Arturo Marques Pita <email@hidden>
    • Re: expanding the view area of a window - please help
      • From: Kurt Revis <email@hidden>
References: 
 >expanding the view area of a window - please help (From: Manuel Arturo Marques Pita <email@hidden>)

  • Prev by Date: Re: Need clarification on categories
  • Next by Date: Re: Learning AppleScript?
  • Previous by thread: expanding the view area of a window - please help
  • Next by thread: Re: expanding the view area of a window - please help
  • Index(es):
    • Date
    • Thread