Dieses Dokuwiki verwendet ein von Anymorphic Webdesign erstelltes Thema.

Coding a slider-type control as menu item

Author

Versions

cocos2d 0.99.4

Problem

Sometimes, in a menu, it's necessary to input a value from a continuous range of possibilities: typically, in regular UI this is the work for a slider. Unfortunately, cocos2d doesn't have an actual slider widget, but it's relatively easy to add one.

Solution

The first step has been to tell CCMenu to track a touch: subclass ccTouchMoved:withEvent: as follows

-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
	NSAssert(state == kMenuStateTrackingTouch, @"[Menu ccTouchMoved] -- invalid state");
 
	CCMenuItem *currentItem = [self itemForTouch:touch];
 
	if (currentItem != selectedItem) {
		[selectedItem unselected];
		selectedItem = currentItem;
		[selectedItem selected];
	} else {
		if ([selectedItem respondsToSelector: @selector(dragToPoint:)]) {
			CGPoint touchLocation = [selectedItem convertTouchToNodeSpace: touch];
 
			[selectedItem dragToPoint: touchLocation];
		}
	}
}

Next, define a new CCMenuItem subclass:

@interface CCMenuItemSlider : CCMenuItem <CCRGBAProtocol>
{
	float			minValue_;
	float			maxValue_;
	float			value_;
 
	BOOL			isVertical;
 
	CCNode<CCRGBAProtocol>	*trackImage_, *knobImage_;
}
 
/** returns the minimum */
@property (nonatomic,readwrite) float minValue;
/** returns the maximum */
@property (nonatomic,readwrite) float maxValue;
/** returns the value */
@property (nonatomic,readwrite) float value;
 
/** the image for the sliding track */
@property (nonatomic,readwrite,retain) CCNode<CCRGBAProtocol>	*trackImage;
/** the image for the knob */
@property (nonatomic,readwrite,retain) CCNode<CCRGBAProtocol>	*knobImage;
 
/** creates a menu item with a track and knob image*/
+(id) itemFromTrackImage: (NSString*)value knobImage:(NSString*) value2;
/** creates a menu item with a track and knob image with target/selector */
+(id) itemFromTrackImage: (NSString*)value knobImage:(NSString*) value2 target:(id) t selector:(SEL) s;
/** initializes a slider menu item from two images with a target selector */
-(id) initFromTrackImage: (NSString *)trkImage knobImage: (NSString *)knbImage target: (id)target selector: (SEL)selector;
 
/** Drag the knob around */
-(void) dragToPoint: (CGPoint)aPoint;
 
@end

The actual implementation looks like this:

//
// MenuItemSlider
//
@implementation CCMenuItemSlider
 
@synthesize minValue=minValue_, maxValue=maxValue_, value=value_;
@synthesize trackImage=trackImage_, knobImage=knobImage_;
 
+(id) itemFromTrackImage: (NSString*)value knobImage:(NSString*) value2
{
	return [[[self alloc] initFromTrackImage:value knobImage:value2 target:nil selector:nil] autorelease];
}
 
+(id) itemFromTrackImage: (NSString*)value knobImage:(NSString*) value2 target:(id) t selector:(SEL) s
{
	return [[[self alloc] initFromTrackImage:value knobImage:value2 target: t selector: s] autorelease];
}
 
-(id) initFromTrackImage: (NSString *)trkImage
			   knobImage: (NSString *)knbImage
				  target: (id)target
				selector: (SEL)selector
{
	if( (self=[super initWithTarget:target selector:selector]) ) {
		self.trackImage		= [CCSprite spriteWithFile: trkImage];
		self.knobImage		= [CCSprite spriteWithFile: knbImage];
 
		// Content size of the track is our reference
		// Knob must lie within
		[self setContentSize: trackImage_.contentSize];
		[self addChild: knobImage_ z:2];
 
		isVertical	= (self.contentSize.height > self.contentSize.width);
		self.minValue	= 0.0f;
		self.maxValue	= 100.0f;
		self.value	= 50.0f;
	}
	return self;
}
 
- (void)setValue: (float)aValue
{
	float	valueRatio;
 
	if (isVertical)
		valueRatio	= (self.contentSize.height - knobImage_.contentSize.height) / (maxValue_ - minValue_);
	else
		valueRatio	= (self.contentSize.width - knobImage_.contentSize.width) / (maxValue_ - minValue_);
 
	if (aValue < minValue_)
		value_	= minValue_;
	else if (aValue > maxValue_)
		value_	= maxValue_;
	else
		value_	= aValue;
 
	if (isVertical)
		knobImage_.position	= CGPointMake(self.contentSize.width / 2,
						(value_ - minValue_) * valueRatio + knobImage_.contentSize.height / 2);
	else
		knobImage_.position	= CGPointMake((value_ - minValue_) * valueRatio + knobImage_.contentSize.width / 2,
						self.contentSize.height / 2);
}
 
- (void)draw
{
	[trackImage_ draw];
}
 
-(void) dragToPoint: (CGPoint)aPoint
{
	float	valueRatio;
	float	absValue;
 
	if (isVertical) {
		valueRatio	= (maxValue_ - minValue_) / (self.contentSize.height - knobImage_.contentSize.height);
		absValue	= aPoint.y - knobImage_.contentSize.height / 2;
	} else {
		valueRatio	= (maxValue_ - minValue_) / (self.contentSize.width - knobImage_.contentSize.width);
		absValue	= aPoint.x - knobImage_.contentSize.width / 2;
	}
 
	self.value	= minValue_ + absValue * valueRatio;
 
	[self activate];
}
 
#pragma mark CCMenuItemSlider - CCRGBAProtocol protocol
- (void) setOpacity: (GLubyte)opacity
{
	[trackImage_ setOpacity:opacity];
	[knobImage_ setOpacity:opacity];
}
 
-(void) setColor:(ccColor3B)color
{
	[trackImage_ setColor:color];
	[knobImage_ setColor:color];
}
 
-(GLubyte) opacity
{
	return [trackImage_ opacity];
}
 
-(ccColor3B) color
{
	return [trackImage_ color];
}
 
@end

Finally, the use of it is quite simple:

CCMenuItemSlider	*slider	= [CCMenuItemSlider itemFromTrackImage: @"SliderTrack.jpg"
							knobImage: @"SliderKnob.png"
							target: self
							selector: @selector(changeMaxNumber:)];
		slider.minValue		= 10;
		slider.maxValue		= 100;
		slider.value		= maxNum;

Sliders of different styles aren't hard to do, the code handles automatically if the slider is horizontal or vertical: the only care the designer should take is that the track (i.e. the fixed part) is used to calculate the actual content size, so it should include the whole area intended to be used as slider. If knob is meant to be bigger than the track, just make the exceeding content transparent.

tips/slider_widget.txt · Last modified: 2010/06/17 19:32 by pmanna
Trace: code_snippets migrate_to_v2.0 0_8_rc 0_8_rc2 1_1_0 lesson_1._install_test director_transparentview instructions multiline_label slider_widget
Dieses Dokuwiki verwendet ein von Anymorphic Webdesign erstelltes Thema.
CC Attribution-Noncommercial-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0