NSSliderCell: implement circular sliders

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@29985 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Eric Wasylishen 2010-03-17 00:18:30 +00:00
parent 45a0301af8
commit b81434b7d0
3 changed files with 196 additions and 75 deletions

View file

@ -1,3 +1,11 @@
2010-03-16 Eric Wasylishen <ewasylishen@gmail.com>
* Source/NSSliderCell.m:
* Headers/AppKit/NSSliderCell.h:
Initial implementation of circular sliders.
I need to refactor NSSliderCell drawing code out to GSTheme
some time soon.
2010-03-16 German Arias <german@xelalug.org>
* Resources/French.lproj/Localizable.strings: Added patch

View file

@ -43,6 +43,12 @@ typedef enum _NSTickMarkPosition
NSTickMarkRight
} NSTickMarkPosition;
typedef enum _NSSliderType
{
NSLinearSlider = 0,
NSCircularSlider
} NSSliderType;
@interface NSSliderCell : NSActionCell <NSCoding>
{
float _minValue;
@ -55,6 +61,7 @@ typedef enum _NSTickMarkPosition
BOOL _allowsTickMarkValuesOnly;
int _numberOfTickMarks;
NSTickMarkPosition _tickMarkPosition;
NSSliderType _type;
}
/* Asking about the cell's behavior */
@ -78,6 +85,7 @@ typedef enum _NSTickMarkPosition
- (id) titleCell;
- (NSColor*) titleColor;
- (NSFont*) titleFont;
- (NSSliderType) sliderType;
/* Changing the cell's appearance */
- (void) setKnobThickness: (float)thickness;
@ -85,6 +93,7 @@ typedef enum _NSTickMarkPosition
- (void) setTitleCell: (NSCell*)aCell;
- (void) setTitleColor: (NSColor*)color;
- (void) setTitleFont: (NSFont*)font;
- (void) setSliderType:(NSSliderType)type;
/* Asking about the value limits */
- (double) minValue;

View file

@ -33,6 +33,7 @@
#import <Foundation/NSValue.h>
#import "AppKit/NSApplication.h"
#import "AppKit/NSBezierPath.h"
#import "AppKit/NSColor.h"
#import "AppKit/NSControl.h"
#import "AppKit/NSEvent.h"
@ -44,55 +45,80 @@
DEFINE_RINT_IF_MISSING
#ifndef M_PI
#define M_PI 3.1415926535897932384626434
#endif
static inline
float _floatValueForMousePoint (NSPoint point, NSRect knobRect,
NSRect slotRect, BOOL isVertical,
float minValue, float maxValue,
NSSliderCell *theCell, BOOL flipped)
NSSliderCell *theCell, BOOL flipped,
BOOL isCircular)
{
float floatValue = 0;
float position;
// Adjust the point to lie inside the knob slot. We don't
// have to worry whether the view is flipped or not.
if (isVertical)
if (isCircular)
{
if (point.y < slotRect.origin.y + knobRect.size.height / 2)
{
position = slotRect.origin.y + knobRect.size.height / 2;
}
else if (point.y > slotRect.origin.y + slotRect.size.height
- knobRect.size.height / 2)
{
position = slotRect.origin.y + slotRect.size.height
- knobRect.size.height / 2;
}
else
position = point.y;
// Compute the float value
floatValue = (position - (slotRect.origin.y + knobRect.size.height/2))
/ (slotRect.size.height - knobRect.size.height);
NSPoint slotCenter = NSMakePoint(NSMidX(slotRect), NSMidY(slotRect));
NSPoint pointRelativeToKnobCenter = NSMakePoint(point.x - slotCenter.x,
point.y - slotCenter.y);
if (flipped)
floatValue = 1 - floatValue;
{
pointRelativeToKnobCenter.y *= -1.0;
}
floatValue = atan2f(pointRelativeToKnobCenter.x,
pointRelativeToKnobCenter.y) / (2.0 * M_PI);
if (floatValue < 0)
{
floatValue += 1.0;
}
// floatValue is 0 for up, 0.25 for right, 0.5 for down, 0.75 for left, etc.
}
else
{
if (point.x < slotRect.origin.x + knobRect.size.width / 2)
// Adjust the point to lie inside the knob slot. We don't
// have to worry whether the view is flipped or not.
if (isVertical)
{
position = slotRect.origin.x + knobRect.size.width / 2;
}
else if (point.x > slotRect.origin.x + slotRect.size.width
- knobRect.size.width / 2)
{
position = slotRect.origin.x + slotRect.size.width
- knobRect.size.width / 2;
if (point.y < slotRect.origin.y + knobRect.size.height / 2)
{
position = slotRect.origin.y + knobRect.size.height / 2;
}
else if (point.y > slotRect.origin.y + slotRect.size.height
- knobRect.size.height / 2)
{
position = slotRect.origin.y + slotRect.size.height
- knobRect.size.height / 2;
}
else
position = point.y;
// Compute the float value
floatValue = (position - (slotRect.origin.y + knobRect.size.height/2))
/ (slotRect.size.height - knobRect.size.height);
if (flipped)
floatValue = 1 - floatValue;
}
else
position = point.x;
{
if (point.x < slotRect.origin.x + knobRect.size.width / 2)
{
position = slotRect.origin.x + knobRect.size.width / 2;
}
else if (point.x > slotRect.origin.x + slotRect.size.width
- knobRect.size.width / 2)
{
position = slotRect.origin.x + slotRect.size.width
- knobRect.size.width / 2;
}
else
position = point.x;
// Compute the float value given the knob size
floatValue = (position - (slotRect.origin.x + knobRect.size.width / 2))
/ (slotRect.size.width - knobRect.size.width);
// Compute the float value given the knob size
floatValue = (position - (slotRect.origin.x + knobRect.size.width / 2))
/ (slotRect.size.width - knobRect.size.width);
}
}
return floatValue * (maxValue - minValue) + minValue;
@ -144,6 +170,7 @@ float _floatValueForMousePoint (NSPoint point, NSRect knobRect,
_cell.is_bordered = YES;
_cell.is_bezeled = NO;
[self setContinuous: YES];
[self setSliderType: NSLinearSlider];
_knobCell = [NSCell new];
_titleCell = [NSTextFieldCell new];
@ -200,8 +227,11 @@ float _floatValueForMousePoint (NSPoint point, NSRect knobRect,
only.</p> */
- (void) drawBarInside: (NSRect)rect flipped: (BOOL)flipped
{
[[NSColor scrollBarColor] set];
NSRectFill(rect);
if (_type == NSLinearSlider)
{
[[NSColor scrollBarColor] set];
NSRectFill(rect);
}
}
/**<p>Returns the rect in which to draw the knob, based on the
@ -220,6 +250,8 @@ float _floatValueForMousePoint (NSPoint point, NSRect knobRect,
NSPoint origin;
float floatValue = [self floatValue];
// FIXME: this method needs to be refactored out to GSTheme
if (_isVertical && flipped)
{
floatValue = _maxValue + _minValue - floatValue;
@ -281,55 +313,101 @@ float _floatValueForMousePoint (NSPoint point, NSRect knobRect,
- (void) drawInteriorWithFrame: (NSRect)cellFrame inView: (NSView*)controlView
{
BOOL vertical = (cellFrame.size.height > cellFrame.size.width);
NSImage *image;
NSSize size;
cellFrame = [self drawingRectForBounds: cellFrame];
_trackRect = cellFrame;
if (vertical != _isVertical)
if (_type == NSCircularSlider)
{
if (vertical == YES)
NSBezierPath *circle;
NSPoint knobCenter;
NSPoint point;
NSRect knobRect;
float fraction, angle, radius;
if (cellFrame.size.width > cellFrame.size.height)
{
image = [NSImage imageNamed: @"common_SliderVert"];
if (image != nil)
{
size = [image size];
[image setScalesWhenResized: YES];
[image setSize: NSMakeSize(cellFrame.size.width, size.height)];
}
knobRect = NSMakeRect(cellFrame.origin.x + ((cellFrame.size.width -
cellFrame.size.height) / 2.0),
cellFrame.origin.y,
cellFrame.size.height,
cellFrame.size.height);
}
else
{
image = [NSImage imageNamed: @"common_SliderHoriz"];
if (image != nil)
{
size = [image size];
[image setScalesWhenResized: YES];
[image setSize: NSMakeSize(size.width, cellFrame.size.height)];
}
knobRect = NSMakeRect(cellFrame.origin.x,
cellFrame.origin.y + ((cellFrame.size.height -
cellFrame.size.width) / 2.0),
cellFrame.size.width,
cellFrame.size.width);
}
[_knobCell setImage: image];
knobCenter = NSMakePoint(NSMidX(knobRect), NSMidY(knobRect));
circle = [NSBezierPath bezierPathWithOvalInRect: knobRect];
[[NSColor controlBackgroundColor] set];
[circle fill];
[[NSColor blackColor] set];
[circle stroke];
fraction = ([self floatValue] - [self minValue]) /
([self maxValue] - [self minValue]);
angle = (fraction * (2.0 * M_PI)) - (M_PI / 2.0);
radius = (knobRect.size.height / 2) - 4;
point = NSMakePoint((radius * cos(angle)) + knobCenter.x,
(radius * sin(angle)) + knobCenter.y);
[[NSBezierPath bezierPathWithOvalInRect: NSMakeRect(point.x - 2,
point.y - 2,
4,
4)] stroke];
}
_isVertical = vertical;
_trackRect = cellFrame;
[self drawBarInside: cellFrame flipped: [controlView isFlipped]];
/* Draw title - Uhmmm - shouldn't this better go into
drawBarInside:flipped: ? */
if (_isVertical == NO)
else if (_type == NSLinearSlider)
{
[_titleCell drawInteriorWithFrame: cellFrame inView: controlView];
}
BOOL vertical = (cellFrame.size.height > cellFrame.size.width);
NSImage *image;
NSSize size;
[self drawKnob];
if (vertical != _isVertical)
{
if (vertical == YES)
{
image = [NSImage imageNamed: @"common_SliderVert"];
if (image != nil)
{
size = [image size];
[image setScalesWhenResized: YES];
[image setSize: NSMakeSize(cellFrame.size.width, size.height)];
}
}
else
{
image = [NSImage imageNamed: @"common_SliderHoriz"];
if (image != nil)
{
size = [image size];
[image setScalesWhenResized: YES];
[image setSize: NSMakeSize(size.width, cellFrame.size.height)];
}
}
[_knobCell setImage: image];
}
_isVertical = vertical;
[self drawBarInside: cellFrame flipped: [controlView isFlipped]];
/* Draw title - Uhmmm - shouldn't this better go into
drawBarInside:flipped: ? */
if (_isVertical == NO)
{
[_titleCell drawInteriorWithFrame: cellFrame inView: controlView];
}
[self drawKnob];
}
}
- (BOOL) isOpaque
{
return YES;
return NO;
}
/**<p> Returns the thickness of the slider's knob. This value is in
@ -497,6 +575,32 @@ float _floatValueForMousePoint (NSPoint point, NSRect knobRect,
[_titleCell setFont: font];
}
/**<p>Returns the slider type: linear or circular.</p>
<p>See Also: -setSliderType:</p>
*/
- (NSSliderType)sliderType
{
return _type;
}
/**<p> Sets the type of the slider: linear or circular.
</p><p>See Also: -sliderType</p>
*/
- (void) setSliderType: (NSSliderType)type
{
_type = type;
if (_type == NSLinearSlider)
{
[self setBordered: YES];
[self setBezeled: NO];
}
else if (_type == NSCircularSlider)
{
[self setBordered: NO];
[self setBezeled: NO];
}
}
/**Returns whether or not the slider is vertical. If, for some
reason, this cannot be determined, for such reasons as the slider is
not yet displayed, this method returns -1. Generally, a slider is
@ -702,7 +806,8 @@ float _floatValueForMousePoint (NSPoint point, NSRect knobRect,
floatValue = _floatValueForMousePoint(point, knobRect,
slotRect, isVertical,
minValue, maxValue,
self, isFlipped);
self, isFlipped,
(_type == NSCircularSlider));
[self setFloatValue: floatValue];
if (isContinuous)
{
@ -744,7 +849,8 @@ float _floatValueForMousePoint (NSPoint point, NSRect knobRect,
floatValue = _floatValueForMousePoint(point, knobRect,
slotRect, isVertical,
minValue, maxValue,
self, isFlipped);
self, isFlipped,
(_type == NSCircularSlider));
if (floatValue != oldFloatValue)
{
if (_allowsTickMarkValuesOnly)
@ -791,7 +897,8 @@ float _floatValueForMousePoint (NSPoint point, NSRect knobRect,
[self setMaxValue: [decoder decodeFloatForKey: @"NSMaxValue"]];
[self setFloatValue: [decoder decodeFloatForKey: @"NSValue"]];
_altIncrementValue = [decoder decodeFloatForKey: @"NSAltIncValue"];
[self setSliderType: [decoder decodeIntForKey: @"NSSliderType"]];
// do these here, since the Cocoa version of the class does not save these values...
_knobCell = [NSCell new];
_titleCell = [NSTextFieldCell new];
@ -799,10 +906,6 @@ float _floatValueForMousePoint (NSPoint point, NSRect knobRect,
[_titleCell setStringValue: @""];
[_titleCell setAlignment: NSCenterTextAlignment];
// if it's from a nib, make it bordered and bezeled so it's more attractive, this
// information is not in the nib.
[self setBordered: YES];
[self setBezeled: NO];
_isVertical = -1;
}
else
@ -836,6 +939,7 @@ float _floatValueForMousePoint (NSPoint point, NSRect knobRect,
[coder encodeFloat: _maxValue forKey: @"NSMaxValue"];
[coder encodeFloat: _altIncrementValue forKey: @"NSAltIncValue"];
[coder encodeFloat: _minValue forKey: @"NSValue"]; // encoded for compatibility
[coder encodeInt: _type forKey: @"NSSliderType"];
}
else
{