libs-gui/Source/GSStandardWindowDecorationView.m
Adam Fedor 7afdd32ac1 Revert library license version to 2 until applications can be converted
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@26619 72102866-910b-0410-8b05-ffd578937521
2008-06-10 04:01:49 +00:00

554 lines
14 KiB
Objective-C

/** <title>GSStandardWindowDecorationView</title>
Copyright (C) 2004 Free Software Foundation, Inc.
Author: Alexander Malmberg <alexander@malmberg.org>
Date: 2004-03-24
This file is part of the GNUstep GUI Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; see the file COPYING.LIB.
If not, see <http://www.gnu.org/licenses/> or write to the
Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <Foundation/NSException.h>
#include "AppKit/NSApplication.h"
#include "AppKit/NSAttributedString.h"
#include "AppKit/NSButton.h"
#include "AppKit/NSEvent.h"
#include "AppKit/NSImage.h"
#include "AppKit/NSParagraphStyle.h"
#include "AppKit/NSScreen.h"
#include "AppKit/NSStringDrawing.h"
#include "AppKit/NSWindow.h"
#include "AppKit/PSOperators.h"
#include "GNUstepGUI/GSDisplayServer.h"
#include "GSWindowDecorationView.h"
@implementation GSStandardWindowDecorationView
/* These include the black border. */
#define TITLE_HEIGHT 23.0
#define RESIZE_HEIGHT 9.0
+ (void) offsets: (float *)l : (float *)r : (float *)t : (float *)b
forStyleMask: (unsigned int)style
{
if (style
& (NSTitledWindowMask | NSClosableWindowMask
| NSMiniaturizableWindowMask | NSResizableWindowMask))
{
*l = *r = *t = *b = 1.0;
}
else
{
*l = *r = *t = *b = 0.0;
}
if (style
& (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask))
{
*t = TITLE_HEIGHT;
}
if (style & NSResizableWindowMask)
{
*b = RESIZE_HEIGHT;
}
}
+ (float) minFrameWidthWithTitle: (NSString *)aTitle
styleMask: (unsigned int)aStyle
{
float l, r, t, b, width;
[self offsets: &l : &r : &t : &b forStyleMask: aStyle];
width = l + r;
if (aStyle & NSTitledWindowMask)
{
width += [aTitle sizeWithAttributes: nil].width;
}
return width;
}
static NSDictionary *titleTextAttributes[3];
static NSColor *titleColor[3];
- (void) updateRects
{
if (hasTitleBar)
{
titleBarRect = NSMakeRect(0.0, _frame.size.height - TITLE_HEIGHT,
_frame.size.width, TITLE_HEIGHT);
}
if (hasResizeBar)
{
resizeBarRect = NSMakeRect(0.0, 0.0, _frame.size.width, RESIZE_HEIGHT);
}
if (hasCloseButton)
{
closeButtonRect = NSMakeRect(
_frame.size.width - 15 - 4, _frame.size.height - 15 - 4, 15, 15);
[closeButton setFrame: closeButtonRect];
}
if (hasMiniaturizeButton)
{
miniaturizeButtonRect = NSMakeRect(
4, _frame.size.height - 15 - 4, 15, 15);
[miniaturizeButton setFrame: miniaturizeButtonRect];
}
}
- (id) initWithFrame: (NSRect)frame
window: (NSWindow *)w
{
if (!titleTextAttributes[0])
{
NSMutableParagraphStyle *p;
p = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[p setLineBreakMode: NSLineBreakByClipping];
titleTextAttributes[0] = [[NSMutableDictionary alloc]
initWithObjectsAndKeys:
[NSFont titleBarFontOfSize: 0], NSFontAttributeName,
[NSColor windowFrameTextColor], NSForegroundColorAttributeName,
p, NSParagraphStyleAttributeName,
nil];
titleTextAttributes[1] = [[NSMutableDictionary alloc]
initWithObjectsAndKeys:
[NSFont titleBarFontOfSize: 0], NSFontAttributeName,
[NSColor blackColor], NSForegroundColorAttributeName, /* TODO: need a named color for this */
p, NSParagraphStyleAttributeName,
nil];
titleTextAttributes[2] = [[NSMutableDictionary alloc]
initWithObjectsAndKeys:
[NSFont titleBarFontOfSize: 0], NSFontAttributeName,
[NSColor windowFrameTextColor], NSForegroundColorAttributeName,
p, NSParagraphStyleAttributeName,
nil];
RELEASE(p);
titleColor[0] = RETAIN([NSColor windowFrameColor]);
titleColor[1] = RETAIN([NSColor lightGrayColor]);
titleColor[2] = RETAIN([NSColor darkGrayColor]);
}
self = [super initWithFrame: frame window: w];
if (!self) return nil;
if ([w styleMask]
& (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask))
{
hasTitleBar = YES;
}
if ([w styleMask] & NSTitledWindowMask)
{
isTitled = YES;
}
if ([w styleMask] & NSClosableWindowMask)
{
hasCloseButton = YES;
closeButton = [NSWindow standardWindowButton: NSWindowCloseButton
forStyleMask: [w styleMask]];
[closeButton setTarget: window];
[self addSubview: closeButton];
}
if ([w styleMask] & NSMiniaturizableWindowMask)
{
hasMiniaturizeButton = YES;
miniaturizeButton = [NSWindow standardWindowButton: NSWindowMiniaturizeButton
forStyleMask: [w styleMask]];
[miniaturizeButton setTarget: window];
[self addSubview: miniaturizeButton];
}
if ([w styleMask] & NSResizableWindowMask)
{
hasResizeBar = YES;
}
[self updateRects];
return self;
}
- (void) drawTitleBar
{
static const NSRectEdge edges[4] = {NSMinXEdge, NSMaxYEdge,
NSMaxXEdge, NSMinYEdge};
float grays[3][4] =
{{NSLightGray, NSLightGray, NSDarkGray, NSDarkGray},
{NSWhite, NSWhite, NSDarkGray, NSDarkGray},
{NSLightGray, NSLightGray, NSBlack, NSBlack}};
NSRect workRect;
NSString *title = [window title];
/*
Draw the black border towards the rest of the window. (The outer black
border is drawn in -drawRect: since it might be drawn even if we don't have
a title bar.
*/
[[NSColor blackColor] set];
PSmoveto(0, NSMinY(titleBarRect) + 0.5);
PSrlineto(titleBarRect.size.width, 0);
PSstroke();
/*
Draw the button-like border.
*/
workRect = titleBarRect;
workRect.origin.x += 1;
workRect.origin.y += 1;
workRect.size.width -= 2;
workRect.size.height -= 2;
workRect = NSDrawTiledRects(workRect, workRect, edges, grays[inputState], 4);
/*
Draw the background.
*/
[titleColor[inputState] set];
NSRectFill(workRect);
/* Draw the title. */
if (isTitled)
{
NSSize titleSize;
if (hasMiniaturizeButton)
{
workRect.origin.x += 17;
workRect.size.width -= 17;
}
if (hasCloseButton)
{
workRect.size.width -= 17;
}
titleSize = [title sizeWithAttributes: titleTextAttributes[inputState]];
if (titleSize.width <= workRect.size.width)
workRect.origin.x = NSMidX(workRect) - titleSize.width / 2;
workRect.origin.y = NSMidY(workRect) - titleSize.height / 2;
workRect.size.height = titleSize.height;
[title drawInRect: workRect
withAttributes: titleTextAttributes[inputState]];
}
}
- (void) drawResizeBar
{
[[NSColor lightGrayColor] set];
PSrectfill(1.0, 1.0, resizeBarRect.size.width - 2.0, RESIZE_HEIGHT - 3.0);
PSsetlinewidth(1.0);
[[NSColor blackColor] set];
PSmoveto(0.0, 0.5);
PSlineto(resizeBarRect.size.width, 0.5);
PSstroke();
[[NSColor darkGrayColor] set];
PSmoveto(1.0, RESIZE_HEIGHT - 0.5);
PSlineto(resizeBarRect.size.width - 1.0, RESIZE_HEIGHT - 0.5);
PSstroke();
[[NSColor whiteColor] set];
PSmoveto(1.0, RESIZE_HEIGHT - 1.5);
PSlineto(resizeBarRect.size.width - 1.0, RESIZE_HEIGHT - 1.5);
PSstroke();
/* Only draw the notches if there's enough space. */
if (resizeBarRect.size.width < 30 * 2)
return;
[[NSColor darkGrayColor] set];
PSmoveto(27.5, 1.0);
PSlineto(27.5, RESIZE_HEIGHT - 2.0);
PSmoveto(resizeBarRect.size.width - 28.5, 1.0);
PSlineto(resizeBarRect.size.width - 28.5, RESIZE_HEIGHT - 2.0);
PSstroke();
[[NSColor whiteColor] set];
PSmoveto(28.5, 1.0);
PSlineto(28.5, RESIZE_HEIGHT - 2.0);
PSmoveto(resizeBarRect.size.width - 27.5, 1.0);
PSlineto(resizeBarRect.size.width - 27.5, RESIZE_HEIGHT - 2.0);
PSstroke();
}
- (void) drawRect: (NSRect)rect
{
if (hasTitleBar && NSIntersectsRect(rect, titleBarRect))
{
[self drawTitleBar];
}
if (hasResizeBar && NSIntersectsRect(rect, resizeBarRect))
{
[self drawResizeBar];
}
if (hasResizeBar || hasTitleBar)
{
PSsetlinewidth(1.0);
[[NSColor blackColor] set];
if (NSMinX(rect) < 1.0)
{
PSmoveto(0.5, 0.0);
PSlineto(0.5, _frame.size.height);
PSstroke();
}
if (NSMaxX(rect) > _frame.size.width - 1.0)
{
PSmoveto(_frame.size.width - 0.5, 0.0);
PSlineto(_frame.size.width - 0.5, _frame.size.height);
PSstroke();
}
if (NSMaxY(rect) > _frame.size.height - 1.0)
{
PSmoveto(0.0, _frame.size.height - 0.5);
PSlineto(_frame.size.width, _frame.size.height - 0.5);
PSstroke();
}
if (NSMinY(rect) < 1.0)
{
PSmoveto(0.0, 0.5);
PSlineto(_frame.size.width, 0.5);
PSstroke();
}
}
[super drawRect: rect];
}
- (void) setTitle: (NSString *)newTitle
{
if (isTitled)
[self setNeedsDisplayInRect: titleBarRect];
[super setTitle: newTitle];
}
- (void) setInputState: (int)state
{
NSAssert(state >= 0 && state <= 2, @"Invalid state!");
[super setInputState: state];
if (hasTitleBar)
[self setNeedsDisplayInRect: titleBarRect];
}
- (void) setDocumentEdited: (BOOL)flag
{
if (flag)
{
[closeButton setImage: [NSImage imageNamed: @"common_CloseBroken"]];
[closeButton setAlternateImage:
[NSImage imageNamed: @"common_CloseBrokenH"]];
}
else
{
[closeButton setImage: [NSImage imageNamed: @"common_Close"]];
[closeButton setAlternateImage:
[NSImage imageNamed: @"common_CloseH"]];
}
[super setDocumentEdited: flag];
}
- (NSPoint) mouseLocationOnScreenOutsideOfEventStream
{
int screen = [[window screen] screenNumber];
return [GSServerForWindow(window) mouseLocationOnScreen: screen
window: NULL];
}
- (void) moveWindowStartingWithEvent: (NSEvent *)event
{
unsigned int mask = NSLeftMouseDraggedMask | NSLeftMouseUpMask;
NSEvent *currentEvent = event;
NSDate *distantPast = [NSDate distantPast];
NSPoint delta, point;
delta = [event locationInWindow];
[window _captureMouse: nil];
do
{
while (currentEvent && [currentEvent type] != NSLeftMouseUp)
{
currentEvent = [_window nextEventMatchingMask: mask
untilDate: distantPast
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
}
point = [self mouseLocationOnScreenOutsideOfEventStream];
[window setFrameOrigin: NSMakePoint(point.x - delta.x,
point.y - delta.y)];
if (currentEvent && [currentEvent type] == NSLeftMouseUp)
break;
currentEvent = [_window nextEventMatchingMask: mask
untilDate: nil
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
} while ([currentEvent type] != NSLeftMouseUp);
[window _releaseMouse: nil];
}
static NSRect
calc_new_frame(NSRect frame, NSPoint point, NSPoint firstPoint,
int mode, NSSize minSize, NSSize maxSize)
{
NSRect newFrame = frame;
newFrame.origin.y = point.y - firstPoint.y;
newFrame.size.height = NSMaxY(frame) - newFrame.origin.y;
if (newFrame.size.height < minSize.height)
{
newFrame.size.height = minSize.height;
newFrame.origin.y = NSMaxY(frame) - newFrame.size.height;
}
if (mode == 0)
{
newFrame.origin.x = point.x - firstPoint.x;
newFrame.size.width = NSMaxX(frame) - newFrame.origin.x;
if (newFrame.size.width < minSize.width)
{
newFrame.size.width = minSize.width;
newFrame.origin.x = NSMaxX(frame) - newFrame.size.width;
}
}
else if (mode == 1)
{
newFrame.size.width = point.x - frame.origin.x + frame.size.width
- firstPoint.x;
if (newFrame.size.width < minSize.width)
{
newFrame.size.width = minSize.width;
newFrame.origin.x = frame.origin.x;
}
}
return newFrame;
}
- (void) resizeWindowStartingWithEvent: (NSEvent *)event
{
unsigned int mask = NSLeftMouseDraggedMask | NSLeftMouseUpMask;
NSEvent *currentEvent = event;
NSDate *distantPast = [NSDate distantPast];
NSPoint firstPoint, point;
NSRect newFrame, frame;
NSSize minSize, maxSize;
/*
0 drag lower left corner
1 drag lower right corner
2 drag lower edge
*/
int mode;
firstPoint = [event locationInWindow];
if (resizeBarRect.size.width < 30 * 2
&& firstPoint.x < resizeBarRect.size.width / 2)
mode = 0;
else if (firstPoint.x > resizeBarRect.size.width - 29)
mode = 1;
else if (firstPoint.x < 29)
mode = 0;
else
mode = 2;
frame = [window frame];
minSize = [window minSize];
maxSize = [window maxSize];
[window _captureMouse: nil];
do
{
while (currentEvent && [currentEvent type] != NSLeftMouseUp)
{
currentEvent = [_window nextEventMatchingMask: mask
untilDate: distantPast
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
}
point = [self mouseLocationOnScreenOutsideOfEventStream];
newFrame
= calc_new_frame(frame, point, firstPoint, mode, minSize, maxSize);
if (currentEvent && [currentEvent type] == NSLeftMouseUp)
break;
currentEvent = [_window nextEventMatchingMask: mask
untilDate: nil
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
} while ([currentEvent type] != NSLeftMouseUp);
[window _releaseMouse: nil];
[window setFrame: newFrame display: YES];
}
- (BOOL) acceptsFirstMouse: (NSEvent*)theEvent
{
return YES;
}
- (void) mouseDown: (NSEvent *)event
{
NSPoint p = [self convertPoint: [event locationInWindow] fromView: nil];
if (NSPointInRect(p, contentRect))
return;
if (NSPointInRect(p, titleBarRect))
{
[self moveWindowStartingWithEvent: event];
return;
}
if (NSPointInRect(p, resizeBarRect))
{
[self resizeWindowStartingWithEvent: event];
return;
}
}
- (void) setFrame: (NSRect)frameRect
{
[super setFrame: frameRect];
[self updateRects];
}
@end