apps-gorm/GormViewWithContentViewEditor.m
Gregory John Casamento 82e6a77348 Reconcile the position of a view with it's parent. Ensures that the subview will always be pasted into a viewable area.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/apps/gorm/trunk@20527 72102866-910b-0410-8b05-ffd578937521
2005-01-08 17:30:09 +00:00

1249 lines
30 KiB
Objective-C

/* GormViewWithContentViewEditor.m
*
* Copyright (C) 2002 Free Software Foundation, Inc.
*
* Author: Pierre-Yves Rivaille <pyrivail@ens-lyon.fr>
* Date: 2002
*
* This file is part of GNUstep.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <AppKit/AppKit.h>
#include "GormPrivate.h"
#include "GormViewWithContentViewEditor.h"
#include "GormPlacementInfo.h"
#include "GormSplitViewEditor.h"
@interface GormViewEditor (Private)
- (NSRect) _displayMovingFrameWithHint: (NSRect) frame
andPlacementInfo: (GormPlacementInfo *)gpi;
@end
@implementation GormViewWithContentViewEditor
- (id) initWithObject: (id) anObject
inDocument: (id<IBDocuments>)aDocument
{
_displaySelection = YES;
//GuideLine
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(guideline:)
name: GormToggleGuidelineNotification
object:nil];
_followGuideLine = YES;
self = [super initWithObject: anObject
inDocument: aDocument];
return self;
}
-(void) guideline:(NSNotification *)notification
{
if ( _followGuideLine )
_followGuideLine = NO;
else
_followGuideLine = YES;
}
- (void) handleMouseOnKnob: (IBKnobPosition) knob
ofView: (GormViewEditor *) view
withEvent: (NSEvent *) theEvent
{
NSPoint mouseDownPoint = [[view superview]
convertPoint: [theEvent locationInWindow]
fromView: nil];
NSDate *future = [NSDate distantFuture];
BOOL acceptsMouseMoved;
unsigned eventMask;
NSEvent *e;
NSEventType eType;
NSRect r = [view frame];
NSPoint maxMouse;
NSPoint minMouse;
NSRect firstRect = [view frame];
NSRect lastRect = [view frame];
NSPoint lastPoint = mouseDownPoint;
NSPoint point = mouseDownPoint;
NSView *superview;
GormPlacementInfo *gpi;
eventMask = NSLeftMouseUpMask | NSLeftMouseDraggedMask
| NSMouseMovedMask | NSPeriodicMask;
// Save window state info.
acceptsMouseMoved = [[self window] acceptsMouseMovedEvents];
[[self window] setAcceptsMouseMovedEvents: YES];
superview = [view superview];
[superview lockFocus];
_displaySelection = NO;
/*
* Get size limits for resizing or moving and calculate maximum
* and minimum mouse positions that won't cause us to exceed
* those limits.
*/
{
NSSize max = [view maximumSizeFromKnobPosition: knob];
NSSize min = [view minimumSizeFromKnobPosition: knob];
r = [superview frame];
minMouse = NSMakePoint(NSMinX(r), NSMinY(r));
maxMouse = NSMakePoint(NSMaxX(r), NSMaxY(r));
r = [view frame];
switch (knob)
{
case IBBottomLeftKnobPosition:
maxMouse.x = NSMaxX(r) - min.width;
minMouse.x = NSMaxX(r) - max.width;
maxMouse.y = NSMaxY(r) - min.height;
minMouse.y = NSMaxY(r) - max.height;
break;
case IBMiddleLeftKnobPosition:
maxMouse.x = NSMaxX(r) - min.width;
minMouse.x = NSMaxX(r) - max.width;
break;
case IBTopLeftKnobPosition:
maxMouse.x = NSMaxX(r) - min.width;
minMouse.x = NSMaxX(r) - max.width;
maxMouse.y = NSMinY(r) + max.height;
minMouse.y = NSMinY(r) + min.height;
break;
case IBTopMiddleKnobPosition:
maxMouse.y = NSMinY(r) + max.height;
minMouse.y = NSMinY(r) + min.height;
break;
case IBTopRightKnobPosition:
maxMouse.x = NSMinX(r) + max.width;
minMouse.x = NSMinX(r) + min.width;
maxMouse.y = NSMinY(r) + max.height;
minMouse.y = NSMinY(r) + min.height;
break;
case IBMiddleRightKnobPosition:
maxMouse.x = NSMinX(r) + max.width;
minMouse.x = NSMinX(r) + min.width;
break;
case IBBottomRightKnobPosition:
maxMouse.x = NSMinX(r) + max.width;
minMouse.x = NSMinX(r) + min.width;
maxMouse.y = NSMaxY(r) - min.height;
minMouse.y = NSMaxY(r) - max.height;
break;
case IBBottomMiddleKnobPosition:
maxMouse.y = NSMaxY(r) - min.height;
minMouse.y = NSMaxY(r) - max.height;
break;
case IBNoneKnobPosition:
break; /* NOT REACHED */
}
}
/* Set the arrows cursor in case it might be something else */
[[NSCursor arrowCursor] push];
/*
* Track mouse movements until left mouse up.
* While we keep track of all mouse movements, we only act on a
* movement when a periodic event arives (every 20th of a second)
* in order to avoid excessive amounts of drawing.
*/
[NSEvent startPeriodicEventsAfterDelay: 0.1 withPeriod: 0.05];
e = [NSApp nextEventMatchingMask: eventMask
untilDate: future
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
eType = [e type];
if ([view respondsToSelector: @selector(initializeResizingInFrame:withKnob:)])
{
gpi = [(id)view initializeResizingInFrame: superview
withKnob: knob];
}
else
{
gpi = nil;
}
while (eType != NSLeftMouseUp)
{
if (eType != NSPeriodic)
{
point = [superview convertPoint: [e locationInWindow]
fromView: nil];
/*
if (edit_view != self)
point = _constrainPointToBounds(point, [edit_view bounds]);
*/
}
else if (NSEqualPoints(point, lastPoint) == NO)
{
[[self window] disableFlushWindow];
{
float xDiff;
float yDiff;
if (point.x < minMouse.x)
point.x = minMouse.x;
if (point.y < minMouse.y)
point.y = minMouse.y;
if (point.x > maxMouse.x)
point.x = maxMouse.x;
if (point.y > maxMouse.y)
point.y = maxMouse.y;
xDiff = point.x - lastPoint.x;
yDiff = point.y - lastPoint.y;
lastPoint = point;
{
r = GormExtBoundsForRect(r/*constrainRect*/);
r.origin.x--;
r.origin.y--;
r.size.width += 2;
r.size.height += 2;
// [superview displayRect: r];
r = lastRect;
switch (knob)
{
case IBBottomLeftKnobPosition:
r.origin.x += xDiff;
r.origin.y += yDiff;
r.size.width -= xDiff;
r.size.height -= yDiff;
break;
case IBMiddleLeftKnobPosition:
r.origin.x += xDiff;
r.size.width -= xDiff;
break;
case IBTopLeftKnobPosition:
r.origin.x += xDiff;
r.size.width -= xDiff;
r.size.height += yDiff;
break;
case IBTopMiddleKnobPosition:
r.size.height += yDiff;
break;
case IBTopRightKnobPosition:
r.size.width += xDiff;
r.size.height += yDiff;
break;
case IBMiddleRightKnobPosition:
r.size.width += xDiff;
break;
case IBBottomRightKnobPosition:
r.origin.y += yDiff;
r.size.width += xDiff;
r.size.height -= yDiff;
break;
case IBBottomMiddleKnobPosition:
r.origin.y += yDiff;
r.size.height -= yDiff;
break;
case IBNoneKnobPosition:
break; /* NOT REACHED */
}
lastRect = r;
if ([view respondsToSelector:
@selector(updateResizingWithFrame:andEvent:andPlacementInfo:)])
{
[view updateResizingWithFrame: r
andEvent: theEvent
andPlacementInfo: gpi];
}
}
/*
* Flush any drawing performed for this event.
*/
[[self window] enableFlushWindow];
[[self window] flushWindow];
}
}
e = [NSApp nextEventMatchingMask: eventMask
untilDate: future
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
eType = [e type];
}
[NSEvent stopPeriodicEvents];
[NSCursor pop];
/* Typically after a view has been dragged in a window, NSWindow
sends a spurious moustEntered event. Sending the mouseUp
event back to the NSWindow resets the NSWindow's idea of the
last mouse point so it doesn't think that the mouse has
entered the view (since it was always there, it's just that
the view moved). */
[[self window] postEvent: e atStart: NO];
{
NSRect redrawRect;
/*
* This was a subview resize, so we must clean up by removing
* the highlighted knob and the wireframe around the view.
*/
[view updateResizingWithFrame: r
andEvent: theEvent
andPlacementInfo: gpi];
[view validateFrame: r
withEvent: theEvent
andPlacementInfo: gpi];
r = GormExtBoundsForRect(lastRect);
r.origin.x--;
r.origin.y--;
r.size.width += 2;
r.size.height += 2;
/*
* If this was a simple resize, we must redraw the union of
* the original frame, and the final frame, and the area
* where we were drawing the wireframe and handles.
*/
redrawRect = NSUnionRect(r, redrawRect);
redrawRect = NSUnionRect(firstRect, redrawRect);
}
if (NSEqualPoints(point, mouseDownPoint) == NO)
{
/*
* A subview was moved or resized, so we must mark the
* doucment as edited.
*/
[document touch];
}
[superview unlockFocus];
_displaySelection = YES;
[self setNeedsDisplay: YES];
/*
* Restore state to what it was on entry.
*/
[[self window] setAcceptsMouseMovedEvents: acceptsMouseMoved];
}
- (void) handleMouseOnView: (GormViewEditor *) view
withEvent: (NSEvent *) theEvent
{
NSPoint mouseDownPoint = [[view superview]
convertPoint: [theEvent locationInWindow]
fromView: nil];
NSDate *future = [NSDate distantFuture];
NSView *subview;
BOOL acceptsMouseMoved;
BOOL dragStarted = NO;
unsigned eventMask;
NSEvent *e;
NSEventType eType;
NSRect r;
NSPoint maxMouse;
NSPoint minMouse;
NSPoint lastPoint = mouseDownPoint;
NSPoint point = mouseDownPoint;
NSView *superview;
NSEnumerator *enumerator;
NSRect oldMovingFrame;
NSRect suggestedFrame;
GormPlacementInfo *gpi = nil;
BOOL shouldUpdateSelection = YES;
BOOL mouseDidMove = NO;
eventMask = NSLeftMouseUpMask | NSLeftMouseDraggedMask
| NSMouseMovedMask | NSPeriodicMask;
// Save window state info.
acceptsMouseMoved = [[self window] acceptsMouseMovedEvents];
[[self window] setAcceptsMouseMovedEvents: YES];
if (view == nil)
{
return;
}
if ([theEvent modifierFlags] & NSShiftKeyMask)
{
if ([selection containsObject: view])
{
NSMutableArray *newSelection = [selection mutableCopy];
[newSelection removeObjectIdenticalTo: view];
[self selectObjects: newSelection];
RELEASE(newSelection);
return;
}
else
{
NSArray *newSelection;
newSelection = [selection arrayByAddingObject: view];
[self selectObjects: newSelection];
}
shouldUpdateSelection = NO;
}
else
{
if ([selection containsObject: view])
{
if ([selection count] == 1)
shouldUpdateSelection = NO;
}
else
{
shouldUpdateSelection = NO;
[self selectObjects: [NSArray arrayWithObject: view]];
}
}
superview = [view superview];
[superview lockFocus];
{
NSRect vf = [view frame];
NSRect sf = [superview bounds];
NSPoint tr = NSMakePoint(NSMaxX(vf), NSMaxY(vf));
NSPoint bl = NSMakePoint(NSMinX(vf), NSMinY(vf));
enumerator = [selection objectEnumerator];
while ((subview = [enumerator nextObject]) != nil)
{
if (subview != view)
{
float tmp;
vf = [subview frame];
tmp = NSMaxX(vf);
if (tmp > tr.x)
tr.x = tmp;
tmp = NSMaxY(vf);
if (tmp > tr.y)
tr.y = tmp;
tmp = NSMinX(vf);
if (tmp < bl.x)
bl.x = tmp;
tmp = NSMinY(vf);
if (tmp < bl.y)
bl.y = tmp;
}
}
minMouse.x = point.x - bl.x;
minMouse.y = point.y - bl.y;
maxMouse.x = NSMaxX(sf) - tr.x + point.x;
maxMouse.y = NSMaxY(sf) - tr.y + point.y;
}
if ([selection count] == 1)
{
oldMovingFrame = [[selection objectAtIndex: 0] frame];
gpi = [[selection objectAtIndex: 0] initializeResizingInFrame:
[self superview]
withKnob: IBNoneKnobPosition];
suggestedFrame = oldMovingFrame;
}
// Set the arrows cursor in case it might be something else
[[NSCursor arrowCursor] push];
// Track mouse movements until left mouse up.
// While we keep track of all mouse movements, we only act on a
// movement when a periodic event arives (every 20th of a second)
// in order to avoid excessive amounts of drawing.
[NSEvent startPeriodicEventsAfterDelay: 0.1 withPeriod: 0.05];
e = [NSApp nextEventMatchingMask: eventMask
untilDate: future
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
eType = [e type];
{
while ((eType != NSLeftMouseUp) && !mouseDidMove)
{
if (eType != NSPeriodic)
{
point = [superview convertPoint: [e locationInWindow]
fromView: nil];
if (NSEqualPoints(mouseDownPoint, point) == NO)
mouseDidMove = YES;
}
e = [NSApp nextEventMatchingMask: eventMask
untilDate: future
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
eType = [e type];
}
}
while (eType != NSLeftMouseUp)
{
if (eType != NSPeriodic)
{
point = [superview convertPoint: [e locationInWindow]
fromView: nil];
}
else if (NSEqualPoints(point, lastPoint) == NO)
{
[[self window] disableFlushWindow];
{
float xDiff;
float yDiff;
if (point.x < minMouse.x)
point.x = minMouse.x;
if (point.y < minMouse.y)
point.y = minMouse.y;
if (point.x > maxMouse.x)
point.x = maxMouse.x;
if (point.y > maxMouse.y)
point.y = maxMouse.y;
xDiff = point.x - lastPoint.x;
yDiff = point.y - lastPoint.y;
lastPoint = point;
if (dragStarted == NO)
{
// Remove selection knobs before moving selection.
dragStarted = YES;
_displaySelection = NO;
[self setNeedsDisplay: YES];
}
if ([selection count] == 1)
{
[[selection objectAtIndex: 0]
setFrameOrigin:
NSMakePoint(NSMaxX([self bounds]),
NSMaxY([self bounds]))];
[superview display];
r = oldMovingFrame;
r.origin.x += xDiff;
r.origin.y += yDiff;
r.origin.x = (int) r.origin.x;
r.origin.y = (int) r.origin.y;
r.size.width = (int) r.size.width;
r.size.height = (int) r.size.height;
oldMovingFrame = r;
//case guideLine
if ( _followGuideLine )
suggestedFrame = [[selection objectAtIndex: 0]
_displayMovingFrameWithHint: r
andPlacementInfo: gpi];
else
{
suggestedFrame = NSMakeRect (NSMinX(r),
NSMinY(r),
NSMaxX(r) - NSMinX(r),
NSMaxY(r) - NSMinY(r));
}
[[selection objectAtIndex: 0] setFrame:
suggestedFrame];
[[selection objectAtIndex: 0] setNeedsDisplay: YES];
}
else
{
enumerator = [selection objectEnumerator];
while ((subview = [enumerator nextObject]) != nil)
{
NSRect oldFrame = [subview frame];
r = oldFrame;
r.origin.x += xDiff;
r.origin.y += yDiff;
r.origin.x = (int) r.origin.x;
r.origin.y = (int) r.origin.y;
r.size.width = (int) r.size.width;
r.size.height = (int) r.size.height;
[subview setFrame: r];
[superview setNeedsDisplayInRect: oldFrame];
[subview setNeedsDisplay: YES];
}
}
/*
* Flush any drawing performed for this event.
*/
[[self window] displayIfNeeded];
[[self window] enableFlushWindow];
[[self window] flushWindow];
}
}
e = [NSApp nextEventMatchingMask: eventMask
untilDate: future
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
eType = [e type];
}
_displaySelection = YES;
if ([selection count] == 1)
[[selection objectAtIndex: 0] setFrame: suggestedFrame];
if (mouseDidMove == NO && shouldUpdateSelection == YES)
{
[self selectObjects: [NSArray arrayWithObject: view]];
}
[self setNeedsDisplay: YES];
[NSEvent stopPeriodicEvents];
[NSCursor pop];
/* Typically after a view has been dragged in a window, NSWindow
sends a spurious mouseEntered event. Sending the mouseUp
event back to the NSWindow resets the NSWindow's idea of the
last mouse point so it doesn't think that the mouse has
entered the view (since it was always there, it's just that
the view moved). */
[[self window] postEvent: e atStart: NO];
if (NSEqualPoints(point, mouseDownPoint) == NO)
{
// A subview was moved or resized, so we must mark the doucment as edited.
[document touch];
}
[superview unlockFocus];
// Restore window state to what it was when entering the method.
[[self window] setAcceptsMouseMovedEvents: acceptsMouseMoved];
}
- (void) moveSelectionByX: (float)x
andY: (float)y
{
int i;
int count = [selection count];
for (i = 0; i < count; i++)
{
id v = [selection objectAtIndex: i];
NSRect f = [v frame];
f.origin.x += x;
f.origin.y += y;
[v setFrameOrigin: f.origin];
}
}
- (void) resizeSelectionByX: (float)x
andY: (float)y
{
int i;
int count = [selection count];
for (i = 0; i < count; i++)
{
id v = [selection objectAtIndex: i];
NSRect f = [v frame];
f.size.width += x;
f.size.height += y;
[v setFrameSize: f.size];
}
}
- (void) keyDown: (NSEvent *)theEvent
{
NSString *characters = [theEvent characters];
unichar character = 0;
float moveBy = 1.0;
if ([characters length] > 0)
{
character = [characters characterAtIndex: 0];
}
if (([theEvent modifierFlags] & NSShiftKeyMask) == NSShiftKeyMask)
{
if (([theEvent modifierFlags] & NSAlternateKeyMask) == NSAlternateKeyMask)
{
moveBy = 10.0;
}
if ([selection count] == 1)
{
switch (character)
{
case NSUpArrowFunctionKey:
[self resizeSelectionByX: 0 andY: 1*moveBy];
[self setNeedsDisplay: YES];
return;
case NSDownArrowFunctionKey:
[self resizeSelectionByX: 0 andY: -1*moveBy];
[self setNeedsDisplay: YES];
return;
case NSLeftArrowFunctionKey:
[self resizeSelectionByX: -1*moveBy andY: 0];
[self setNeedsDisplay: YES];
return;
case NSRightArrowFunctionKey:
[self resizeSelectionByX: 1*moveBy andY: 0];
[self setNeedsDisplay: YES];
return;
}
}
}
else
{
if (([theEvent modifierFlags] & NSAlternateKeyMask) == NSAlternateKeyMask)
{
moveBy = 10.0;
}
if ([selection count] > 0)
{
switch (character)
{
case NSUpArrowFunctionKey:
[self moveSelectionByX: 0 andY: 1*moveBy];
[self setNeedsDisplay: YES];
return;
case NSDownArrowFunctionKey:
[self moveSelectionByX: 0 andY: -1*moveBy];
[self setNeedsDisplay: YES];
return;
case NSLeftArrowFunctionKey:
[self moveSelectionByX: -1*moveBy andY: 0];
[self setNeedsDisplay: YES];
return;
case NSRightArrowFunctionKey:
[self moveSelectionByX: 1*moveBy andY: 0];
[self setNeedsDisplay: YES];
return;
}
}
}
[super keyDown: theEvent];
}
- (BOOL) acceptsTypeFromArray: (NSArray*)types
{
if ([super acceptsTypeFromArray: types])
{
return YES;
}
else
{
return [types containsObject: IBViewPboardType];
}
}
- (void) postDrawForView: (GormViewEditor *) viewEditor
{
if (_displaySelection == NO)
{
return;
}
if (((id)openedSubeditor == (id)viewEditor)
&& (openedSubeditor != nil)
&& ![openedSubeditor isKindOfClass: [GormInternalViewEditor class]])
{
GormDrawOpenKnobsForRect([viewEditor bounds]);
GormShowFastKnobFills();
}
else if ([selection containsObject: viewEditor])
{
GormDrawKnobsForRect([viewEditor bounds]);
GormShowFastKnobFills();
}
}
- (void) postDraw: (NSRect) rect
{
[super postDraw: rect];
if (openedSubeditor
&& ![openedSubeditor isKindOfClass: [GormInternalViewEditor class]])
{
GormDrawOpenKnobsForRect(
[self convertRect: [openedSubeditor bounds]
fromView: openedSubeditor]);
GormShowFastKnobFills();
}
else if (_displaySelection)
{
int i;
int count = [selection count];
for ( i = 0; i < count ; i++ )
{
GormDrawKnobsForRect([self convertRect:
[[selection objectAtIndex: i] bounds]
fromView: [selection objectAtIndex: i]]);
GormShowFastKnobFills();
}
}
}
#undef MAX
#undef MIN
#define MAX(A,B) ((A)>(B)?(A):(B))
#define MIN(A,B) ((A)<(B)?(A):(B))
int _sortViews(id view1, id view2, void *context)
{
BOOL isVertical = *((BOOL *)context);
int order = NSOrderedSame;
NSRect rect1 = [[view1 editedObject] frame];
NSRect rect2 = [[view2 editedObject] frame];
if(!isVertical)
{
float y1 = rect1.origin.y;
float y2 = rect2.origin.y;
if(y1 == y2)
order = NSOrderedSame;
else
order = (y1 > y2)?NSOrderedAscending:NSOrderedDescending;
}
else
{
float x1 = rect1.origin.x;
float x2 = rect2.origin.x;
if(x1 == x2)
order = NSOrderedSame;
else
order = (x1 < x2)?NSOrderedAscending:NSOrderedDescending;
}
return order;
}
- (NSArray *) _sortByPosition: (NSArray *)subviews
isVertical: (BOOL)isVertical
{
NSMutableArray *array = [subviews mutableCopy];
NSMutableArray *result = [array sortedArrayUsingFunction: _sortViews
context: &isVertical];
return result;
}
- (BOOL) _shouldBeVertical: (NSArray *)subviews
{
BOOL vertical = NO;
NSEnumerator *enumerator = [subviews objectEnumerator];
GormViewEditor *editor = nil;
NSRect prevRect = NSZeroRect;
NSRect currRect = NSZeroRect;
int count = 0;
// iterate over the list of views...
while((editor = [enumerator nextObject]) != nil)
{
NSView *subview = [editor editedObject];
currRect = [subview frame];
if(!NSEqualRects(prevRect,NSZeroRect))
{
float
x1 = prevRect.origin.x, // pull these for convenience.
x2 = currRect.origin.x,
y1 = prevRect.origin.y,
y2 = currRect.origin.y,
h1 = prevRect.size.height,
w1 = prevRect.size.width;
if((x1 < x2 || x1 > x2) && ((y2 >= y1 && y2 <= (y1 + h1)) ||
(y2 <= y1 && y2 >= (y1 - h1))))
{
count++;
}
if((y1 < y2 || y1 > y2) && ((x2 >= x1 && x2 <= (x1 + w1)) ||
(x2 <= x1 && x2 >= (x1 - w1))))
{
count--;
}
}
prevRect = currRect;
}
NSDebugLog(@"The vote is %d",count);
if(count >= 0)
vertical = YES;
else
vertical = NO;
// return the result...
return vertical;
}
- (void) groupSelectionInSplitView
{
NSEnumerator *enumerator = nil;
GormViewEditor *subview = nil;
NSSplitView *splitView = nil;
NSRect rect = NSZeroRect;
GormViewEditor *editor = nil;
NSView *superview = nil;
NSArray *sortedviews = nil;
BOOL vertical = NO;
if ([selection count] < 2)
{
return;
}
enumerator = [selection objectEnumerator];
while ((subview = [enumerator nextObject]) != nil)
{
superview = [subview superview];
rect = NSUnionRect(rect, [subview frame]);
[subview deactivate];
}
splitView = [[NSSplitView alloc] initWithFrame: rect];
[document attachObject: splitView
toParent: _editedObject];
[superview addSubview: splitView];
// positionally determine orientation
vertical = [self _shouldBeVertical: selection];
sortedviews = [self _sortByPosition: selection isVertical: vertical];
[splitView setVertical: vertical];
enumerator = [sortedviews objectEnumerator];
editor = (GormViewEditor *)[document editorForObject: splitView
inEditor: self
create: YES];
while ((subview = [enumerator nextObject]) != nil)
{
id eO = [subview editedObject];
[splitView addSubview: [subview editedObject]];
[document attachObject: [subview editedObject]
toParent: splitView];
[subview close];
[document editorForObject: eO
inEditor: editor
create: YES];
}
[self selectObjects: [NSArray arrayWithObject: editor]];
}
- (void) groupSelectionInBox
{
NSEnumerator *enumerator = nil;
GormViewEditor *subview = nil;
NSBox *box = nil;
NSRect rect = NSZeroRect;
GormViewEditor *editor = nil;
NSView *superview = nil;
if ([selection count] < 1)
{
return;
}
enumerator = [selection objectEnumerator];
while ((subview = [enumerator nextObject]) != nil)
{
superview = [subview superview];
rect = NSUnionRect(rect, [subview frame]);
[subview deactivate];
}
box = [[NSBox alloc] initWithFrame: NSZeroRect];
[box setFrameFromContentFrame: rect];
[document attachObject: box
toParent: _editedObject];
[superview addSubview: box];
enumerator = [selection objectEnumerator];
while ((subview = [enumerator nextObject]) != nil)
{
NSPoint frameOrigin;
[box addSubview: [subview editedObject]];
frameOrigin = [[subview editedObject] frame].origin;
frameOrigin.x -= rect.origin.x;
frameOrigin.y -= rect.origin.y;
[[subview editedObject] setFrameOrigin: frameOrigin];
[subview close];
}
editor = (GormViewEditor *)[document editorForObject: box
inEditor: self
create: YES];
[self selectObjects: [NSArray arrayWithObject: editor]];
}
- (void) groupSelectionInScrollView
{
NSEnumerator *enumerator = nil;
GormViewEditor *subview = nil;
NSView *view = nil;
NSScrollView *scrollView = nil;
NSRect rect = NSZeroRect;
GormViewEditor *editor = nil;
NSView *superview = nil;
if ([selection count] < 1)
{
return;
}
// if there is more than one view we must join them together.
if([selection count] > 1)
{
// deactivate the editor for each subview.
enumerator = [selection objectEnumerator];
while ((subview = [enumerator nextObject]) != nil)
{
superview = [subview superview];
rect = NSUnionRect(rect, [subview frame]);
[subview deactivate];
}
// create the containing view.
view = [[NSView alloc] initWithFrame:
NSMakeRect(0, 0, rect.size.width, rect.size.height)];
// create scroll view now.
scrollView = [[NSScrollView alloc] initWithFrame: rect];
[scrollView setHasHorizontalScroller: YES];
[scrollView setHasVerticalScroller: YES];
[scrollView setBorderType: NSBezelBorder];
// attach the scroll view...
[document attachObject: scrollView
toParent: _editedObject];
[superview addSubview: scrollView];
[scrollView setDocumentView: view];
// add the views.
enumerator = [selection objectEnumerator];
while ((subview = [enumerator nextObject]) != nil)
{
NSPoint frameOrigin;
[view addSubview: [subview editedObject]];
frameOrigin = [[subview editedObject] frame].origin;
frameOrigin.x -= rect.origin.x;
frameOrigin.y -= rect.origin.y;
[[subview editedObject] setFrameOrigin: frameOrigin];
[subview close];
}
}
else if([selection count] == 1)
{
NSPoint frameOrigin;
id v = nil;
// since we have one view, it will be used as the document view.
subview = [selection objectAtIndex: 0];
superview = [subview superview];
rect = NSUnionRect(rect, [subview frame]);
[subview deactivate];
// create scroll view now.
scrollView = [[NSScrollView alloc] initWithFrame: rect];
[scrollView setHasHorizontalScroller: YES];
[scrollView setHasVerticalScroller: YES];
[scrollView setBorderType: NSBezelBorder];
// attach the scroll view...
[document attachObject: scrollView
toParent: _editedObject];
[superview addSubview: scrollView];
// add the view
v = [subview editedObject];
[scrollView setDocumentView: v];
// set the origin..
frameOrigin = [v frame].origin;
frameOrigin.x -= rect.origin.x;
frameOrigin.y -= rect.origin.y;
[v setFrameOrigin: frameOrigin];
[subview close];
}
editor = (GormViewEditor *)[document editorForObject: scrollView
inEditor: self
create: YES];
[self selectObjects: [NSArray arrayWithObject: editor]];
}
@class GormBoxEditor;
@class GormSplitViewEditor;
@class GormScrollViewEditor;
- (void) ungroup
{
NSView *toUngroup;
if ([selection count] != 1)
return;
NSDebugLog(@"ungroup called");
toUngroup = [selection objectAtIndex: 0];
NSDebugLog(@"toUngroup = %@",[toUngroup description]);
if ([toUngroup isKindOfClass: [GormBoxEditor class]]
|| [toUngroup isKindOfClass: [GormSplitViewEditor class]]
|| [toUngroup isKindOfClass: [GormScrollViewEditor class]]
)
{
id contentView = toUngroup;
NSMutableArray *newSelection = [NSMutableArray array];
NSArray *views;
int i;
views = [contentView destroyAndListSubviews];
for (i = 0; i < [views count]; i++)
{
[_editedObject addSubview: [views objectAtIndex: i]];
[newSelection addObject:
[document editorForObject: [views objectAtIndex: i]
inEditor: self
create: YES]];
}
[self selectObjects: newSelection];
}
}
- (void) _addViewToDocument: (NSView *)view
{
NSEnumerator *en = nil;
NSView *sub = nil;
if([sub isKindOfClass: [GormViewEditor class]])
return;
[document attachObject: view toParent: nil];
en = [[view subviews] objectEnumerator];
while((sub = [en nextObject]) != nil)
{
[self _addViewToDocument: sub];
}
}
- (void) pasteInView: (NSView *)view
{
NSPasteboard *pb = [NSPasteboard generalPasteboard];
NSMutableArray *array = [NSMutableArray array];
NSArray *views;
NSEnumerator *enumerator;
NSView *sub;
/*
* Ask the document to get the copied views from the pasteboard and add
* them to it's collection of known objects.
*/
views = [document pasteType: IBViewPboardType
fromPasteboard: pb
parent: _editedObject];
/*
* Now make all the views subviews of ourself.
*/
enumerator = [views objectEnumerator];
while ((sub = [enumerator nextObject]) != nil)
{
if ([sub isKindOfClass: [NSView class]] == YES)
{
//
// Correct the frame if it is outside of the containing view.
// this prevents issues where the subview is placed outside the
// viewable region of the superview.
//
if(NSContainsRect([view frame], [sub frame]) == NO)
{
NSRect newFrame = [sub frame];
newFrame.origin.x = 0;
newFrame.origin.y = 0;
[sub setFrame: newFrame];
}
[view addSubview: sub];
[self _addViewToDocument: sub];
[array addObject:
[document editorForObject: sub
inEditor: self
create: YES]];
}
}
[self selectObjects: array];
}
@end