apps-gorm/Palettes/2Controls/GormButtonEditor.m
Gregory John Casamento afcc4ce2e4 Fixed resize issue with textview which edits button title. Also fixed resize issue for dropdown.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/apps/gorm/trunk@25890 72102866-910b-0410-8b05-ffd578937521
2008-01-07 22:40:56 +00:00

512 lines
14 KiB
Objective-C

/* GormButtonEditor.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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
*/
#include <InterfaceBuilder/InterfaceBuilder.h>
#include <AppKit/AppKit.h>
#include <GormCore/GormPrivate.h>
#include <GormCore/GormViewWithSubviewsEditor.h>
#include "GormButtonEditor.h"
#define _EO ((NSButton *)_editedObject)
@interface NSButtonCell (GormObjectAdditions)
- (NSRect) gormTitleRectForFrame: (NSRect) cellFrame
inView: (NSView *)controlView;
@end
@implementation NSButtonCell (GormObjectAdditions)
- (NSRect) gormTitleRectForFrame: (NSRect) cellFrame
inView: (NSView *)controlView
{
unsigned mask;
NSImage *imageToDisplay;
NSRect imageRect;
NSString *titleToDisplay;
NSRect titleRect;
NSSize imageSize = {0, 0};
NSSize titleSize = {0, 0};
NSColor *backgroundColor = nil;
BOOL flippedView = [controlView isFlipped];
NSCellImagePosition ipos = _cell.image_position;
cellFrame = [self drawingRectForBounds: cellFrame];
if (_cell.is_highlighted)
{
mask = _highlightsByMask;
if (_cell.state)
mask &= ~_showAltStateMask;
}
else if (_cell.state)
mask = _showAltStateMask;
else
mask = NSNoCellMask;
/* Pushed in buttons contents are displaced to the bottom right 1px. */
if (_cell.is_bordered && (mask & NSPushInCellMask))
{
cellFrame = NSOffsetRect(cellFrame, 1., flippedView ? 1. : -1.);
}
/* Determine the background color. */
if (mask & (NSChangeGrayCellMask | NSChangeBackgroundCellMask))
{
backgroundColor = [NSColor selectedControlColor];
}
if (backgroundColor == nil)
backgroundColor = [NSColor controlBackgroundColor];
/*
* Determine the image and the title that will be
* displayed. If the NSContentsCellMask is set the
* image and title are swapped only if state is 1 or
* if highlighting is set (when a button is pushed it's
* content is changed to the face of reversed state).
*/
if (mask & NSContentsCellMask)
{
imageToDisplay = _altImage;
if (!imageToDisplay)
imageToDisplay = _cell_image;
titleToDisplay = _altContents;
if (titleToDisplay == nil || [titleToDisplay isEqual: @""])
titleToDisplay = _contents;
}
else
{
imageToDisplay = _cell_image;
titleToDisplay = _contents;
}
if (imageToDisplay)
{
imageSize = [imageToDisplay size];
}
titleSize = [self _sizeText: titleToDisplay];
if (flippedView == YES)
{
if (ipos == NSImageAbove)
{
ipos = NSImageBelow;
}
else if (ipos == NSImageBelow)
{
ipos = NSImageAbove;
}
}
switch (ipos)
{
case NSNoImage:
imageToDisplay = nil;
titleRect = cellFrame;
{
int heightDiff = titleRect.size.height - titleSize.height;
titleRect.origin.y += heightDiff - heightDiff / 2;
titleRect.size.height -= heightDiff;
}
break;
case NSImageOnly:
titleToDisplay = nil;
imageRect = cellFrame;
break;
case NSImageLeft:
imageRect.origin = cellFrame.origin;
imageRect.size.width = imageSize.width;
imageRect.size.height = cellFrame.size.height;
if (_cell.is_bordered || _cell.is_bezeled)
{
imageRect.origin.x += 3;
imageRect.size.height -= 2;
imageRect.origin.y += 1;
}
titleRect = imageRect;
titleRect.origin.x += imageSize.width + GSCellTextImageXDist;
titleRect.size.width = cellFrame.size.width - imageSize.width - GSCellTextImageXDist;
if (_cell.is_bordered || _cell.is_bezeled)
{
titleRect.size.width -= 3;
}
{
int heightDiff = titleRect.size.height - titleSize.height;
titleRect.origin.y += heightDiff - heightDiff / 2;
titleRect.size.height -= heightDiff;
}
break;
case NSImageRight:
imageRect.origin.x = NSMaxX(cellFrame) - imageSize.width;
imageRect.origin.y = cellFrame.origin.y;
imageRect.size.width = imageSize.width;
imageRect.size.height = cellFrame.size.height;
if (_cell.is_bordered || _cell.is_bezeled)
{
imageRect.origin.x -= 3;
imageRect.size.height -= 2;
imageRect.origin.y += 1;
}
titleRect.origin = cellFrame.origin;
titleRect.size.width = cellFrame.size.width - imageSize.width - GSCellTextImageXDist;
titleRect.size.height = cellFrame.size.height;
if (_cell.is_bordered || _cell.is_bezeled)
{
titleRect.origin.x += 3;
titleRect.size.width -= 3;
}
{
int heightDiff = titleRect.size.height - titleSize.height;
titleRect.origin.y += heightDiff - heightDiff / 2;
titleRect.size.height -= heightDiff;
}
break;
case NSImageAbove:
/*
* In this case, imageRect is all the space we can allocate
* above the text.
* The drawing code below will then center the image in imageRect.
*/
titleRect.origin.x = cellFrame.origin.x;
titleRect.origin.y = cellFrame.origin.y;
titleRect.size.width = cellFrame.size.width;
titleRect.size.height = titleSize.height;
imageRect.origin.x = cellFrame.origin.x;
imageRect.origin.y = cellFrame.origin.y;
imageRect.origin.y += titleRect.size.height + GSCellTextImageYDist;
imageRect.size.width = cellFrame.size.width;
imageRect.size.height = cellFrame.size.height;
imageRect.size.height -= titleSize.height + GSCellTextImageYDist;
if (_cell.is_bordered || _cell.is_bezeled)
{
imageRect.size.width -= 6;
imageRect.origin.x += 3;
titleRect.size.width -= 6;
titleRect.origin.x += 3;
imageRect.size.height -= 1;
titleRect.size.height -= 1;
}
break;
case NSImageBelow:
/*
* In this case, imageRect is all the space we can allocate
* below the text.
* The drawing code below will then center the image in imageRect.
*/
titleRect.origin.x = cellFrame.origin.x;
titleRect.origin.y = cellFrame.origin.y + cellFrame.size.height;
titleRect.origin.y -= titleSize.height;
titleRect.size.width = cellFrame.size.width;
titleRect.size.height = titleSize.height;
imageRect.origin.x = cellFrame.origin.x;
imageRect.origin.y = cellFrame.origin.y;
imageRect.size.width = cellFrame.size.width;
imageRect.size.height = cellFrame.size.height;
imageRect.size.height -= titleSize.height + GSCellTextImageYDist;
if (_cell.is_bordered || _cell.is_bezeled)
{
imageRect.size.width -= 6;
imageRect.origin.x += 3;
titleRect.size.width -= 6;
titleRect.origin.x += 3;
imageRect.size.height -= 1;
imageRect.origin.y += 1;
}
break;
case NSImageOverlaps:
titleRect = cellFrame;
imageRect = cellFrame;
{
int heightDiff = titleRect.size.height - titleSize.height;
titleRect.origin.y += heightDiff - heightDiff / 2;
titleRect.size.height -= heightDiff;
}
break;
}
return titleRect;
}
@end
static BOOL done_editing;
static NSRect oldFrame;
@implementation GormButtonEditor
- (void) handleNotification: (NSNotification*)aNotification
{
NSString *name = [aNotification name];
if ([name isEqual: NSControlTextDidEndEditingNotification] == YES)
{
done_editing = YES;
}
else if([name isEqual: IBWillSaveDocumentNotification] == YES)
{
done_editing = YES;
[[NSNotificationCenter defaultCenter]
removeObserver: self
name: IBWillSaveDocumentNotification
object: nil];
[tempTextView resignFirstResponder];
[tempTextView removeFromSuperview];
[tempTextView setDelegate: nil];
tempTextView = nil;
}
}
- (void) textDidChange: (NSNotification *)aNotification
{
[_EO setTitle: [[aNotification object] string]];
[_EO setNeedsDisplay: NO];
[[(id<Gorm>)NSApp inspectorsManager] updateSelection];
}
- (void) textDidEndEditing: (NSNotification *)aNotification
{
[[aNotification object] setDelegate: nil];
[_EO setTitle: [[aNotification object] string]];
[[aNotification object] removeFromSuperview];
{
NSSize suggestedSize;
NSRect newFrame = [_EO frame];
suggestedSize = [[_EO cell] cellSize];
if (suggestedSize.width > newFrame.size.width)
{
newFrame.origin.x = newFrame.origin.x
- (int)((suggestedSize.width - newFrame.size.width) / 2);
newFrame.size.width = suggestedSize.width;
[_EO setFrame: newFrame];
[[self window] disableFlushWindow];
[[self window] display];
[[self window] enableFlushWindow];
[[self window] flushWindow];
}
}
}
/* Edit a textfield. If it's not already editable, make it so, then
edit it */
- (NSEvent *) editTextField: view withEvent: (NSEvent *)theEvent
{
unsigned eventMask;
BOOL wasEditable;
BOOL didDrawBackground;
NSTextField *editField;
NSRect frame;
NSRect originalFrame;
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
NSDate *future = [NSDate distantFuture];
NSEvent *e;
editField = view;
originalFrame = frame = [editField frame];
wasEditable = [editField isEditable];
[editField setEditable: YES];
didDrawBackground = [editField drawsBackground];
[editField setDrawsBackground: YES];
[nc addObserver: self
selector: @selector(handleNotification:)
name: NSControlTextDidEndEditingNotification
object: nil];
/* Do some modal editing */
[editField selectText: self];
eventMask = NSLeftMouseDownMask | NSLeftMouseUpMask |
NSKeyDownMask | NSKeyUpMask | NSFlagsChangedMask;
done_editing = NO;
while (!done_editing)
{
NSEventType eType;
e = [NSApp nextEventMatchingMask: eventMask
untilDate: future
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
eType = [e type];
switch (eType)
{
case NSLeftMouseDown:
{
NSPoint dp = [self convertPoint: [e locationInWindow]
fromView: nil];
if (NSMouseInRect(dp, frame, NO) == NO)
{
done_editing = YES;
break;
}
}
[[editField currentEditor] mouseDown: e];
break;
case NSLeftMouseUp:
[[editField currentEditor] mouseUp: e];
break;
case NSLeftMouseDragged:
[[editField currentEditor] mouseDragged: e];
break;
case NSKeyDown:
[[editField currentEditor] keyDown: e];
break;
case NSKeyUp:
[[editField currentEditor] keyUp: e];
break;
case NSFlagsChanged:
[[editField currentEditor] flagsChanged: e];
break;
default:
NSLog(@"Internal Error: Unhandled event during editing: %@", e);
break;
}
}
[editField setEditable: wasEditable];
[editField setDrawsBackground: didDrawBackground];
[nc removeObserver: self
name: NSControlTextDidEndEditingNotification
object: nil];
[[editField currentEditor] resignFirstResponder];
[self setNeedsDisplay: YES];
tempTextView = nil;
return e;
}
- (NSTextView *) startEditingInFrame: (NSRect) frame
{
NSTextView *textView = [[NSTextView alloc] initWithFrame: frame];
NSTextContainer *textContainer = [textView textContainer];
tempTextView = textView;
[textContainer setContainerSize: NSMakeSize(3000, NSHeight([textView frame]))];
[textContainer setWidthTracksTextView: NO];
[textContainer setHeightTracksTextView: NO];
[textView setHorizontallyResizable: NO];
[textView setVerticallyResizable: NO];
[textView setMinSize: frame.size];
[textView setMaxSize: frame.size];
[textView setAutoresizingMask: NSViewMinXMargin | NSViewMaxXMargin];
[textView setSelectable: YES];
[textView setEditable: YES];
[textView setRichText: NO];
[textView setImportsGraphics: NO];
[textView setFieldEditor: YES];
[textView setHorizontallyResizable: YES];
[textView setDelegate: self];
[textView setPostsFrameChangedNotifications:YES];
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(textViewFrameChanged:)
name: NSViewFrameDidChangeNotification
object: textView];
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(handleNotification:)
name: IBWillSaveDocumentNotification
object: nil];
oldFrame = frame;
return textView;
}
- (void) textViewFrameChanged: (NSNotification *)aNot
{
static BOOL inside = NO;
NSRect newFrame;
if (inside)
return;
inside = YES;
[[[self window] contentView] setNeedsDisplayInRect: oldFrame];
newFrame = [[aNot object] frame];
if ([[aNot object] alignment] == NSCenterTextAlignment)
{
NSRect frame = [[_EO cell]
gormTitleRectForFrame: [_EO frame]
inView: _EO];
int difference = newFrame.size.width - frame.size.width;
newFrame.origin.x = frame.origin.x - (int) (difference / 2);
[[aNot object] setFrame: newFrame];
oldFrame = newFrame;
}
[[self superview] setNeedsDisplayInRect: oldFrame];
inside = NO;
}
- (void) mouseDown: (NSEvent*)theEvent
{
// double-clicked -> let's edit
if (([theEvent clickCount] == 2) && [parent isOpened])
{
NSRect frame = [[_EO cell]
gormTitleRectForFrame: [_EO frame]
inView: _EO];
NSTextView *tv = [self startEditingInFrame: frame];
[[self superview] addSubview: tv];
[tv setText: [_EO stringValue]];
[tv setAlignment: [_EO alignment]];
[tv setFont: [_EO font]];
[[self window] display];
[[self window] makeFirstResponder: tv];
[tv mouseDown: theEvent];
}
else
{
[super mouseDown: theEvent];
}
}
@end