Rating Indicator not working

So a little while back I had a thread where you guys helped me make a custom level indicator that was basically a rating indicator that had bigger easier to see stars. (using images) I have it check for the rating of the song in iTunes and fill out appropriately. That works perfect. Now for some reason (since Leopard) I can no longer set the stars…nothing happens when I click in it. IT’s connected to my script…its named properly…its selected as editable. What am I doing wrong here? This is the short code that I have that is supposed to set the stars.

on setstars()
	set therate to ((content of control "ri" of window "main") as integer) * 20
	tell application "iTunes"
		try
			set rating of current track to therate
		on error
			display dialog "Before you rate a song you have to play one!"
		end try
	end tell
end setstars

This works fine on its own:

on setstars()
	set therate to 3 * 20
	tell application "iTunes"
		try
			set rating of current track to therate
		on error
			display dialog "Before you rate a song you have to play one!"
		end try
	end tell
end setstars

setstars()

So it’s something to do with the level indicator then…hmmm

Hendo,

are you talking of this thread?

http://bbs.applescript.net/viewtopic.php?id=22483&p=1

I’ve tried it and it seems some internal mouse tracking behaviour of the rating NSLevelIndicator has been modified for 10.5. You probably have noticed that it now has some new features (no longer limited to 5 stars etc.) - so it’s most likely that it has been partially rewritten. In my test I could set the rating only by clicking in the very left part of the custom level indicator when using large star sizes. If this is correct, it’s probably necessary to implement your custom mouse handling in the cell. A similar cell class where I used …

  • (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)flag

… isn’t broken

Dominik

Hey Dominik, I was talking about that thread

where would I place that tidbit of code? I’m still trying to learn Obj-C and find it terribly confusing :confused:

This is the indicators .m file…I finally got it to give me no errors in the file but it still didn’t do anything while clicked.

#import "CustomImageLevelIndicator.h"

@implementation CustomImageLevelIndicatorCell


- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView{

unsigned starCount = (unsigned)roundf([self floatValue]);


NSSize starSize = cellFrame.size;
starSize.width /= 5.0;

[starImg setSize];
[dotImg setSize];

NSRect starRect = NSMakeRect(0.0, 0.0, starSize.width, starSize.height);
NSRect imgRect = starRect;

if (starCount) {
unsigned starIndex;
for (starIndex = 0; starIndex < starCount; starIndex++) {
starRect.origin.x = starIndex * starSize.width;
[starImg drawInRect:starRect fromRect:imgRect operation:NSCompositeSourceOver fraction:1.0];
}
}
if ( (starCount < 5) ) {

unsigned starIndex;
for (starIndex = starCount; starIndex < 5; starIndex++) {
starRect.origin.x = starIndex * starSize.width;
[dotImg drawAtPoint:starRect.origin fromRect:imgRect operation:NSCompositeSourceOver fraction:1.0];
}
}
}

-(void)setImage:(NSImage *)image{
if (starImg != image) {
if (starImg != nil) [starImg release];
starImg = [image copy];
[starImg setScalesWhenResized:YES];
}
}

-(void)setDotImage:(NSImage *)dotImage{
if (dotImg != dotImage) {
if (dotImg != nil) [dotImg release];
dotImg = [dotImage copy];
[dotImg setScalesWhenResized:YES];
}
}

- (void) dealloc {
if (starImg != nil) [starImg release];
if (dotImg != nil) [dotImg release];
[super dealloc];
}

@end

@implementation CustomImageLevelIndicator


+ (Class)cellClass{

return [CustomImageLevelIndicatorCell class];
}

- (id) initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder];
if (self != nil) {
[self setCell:[[[CustomImageLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSRatingLevelIndicatorStyle] autorelease]];
NSRect liFrame = [self frame];
liFrame.size.width = 90.0; // new width
liFrame.size.height = 17.0; // new height
[self setFrame:liFrame];
[[self cell] setImage:[NSImage imageNamed:@"star_on.png"]];
[[self cell] setDotImage:[NSImage imageNamed:@"star_off.png"]];

}
return self;

}

- (id) initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
if (self != nil) {
[self setCell:[[[CustomImageLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSRatingLevelIndicatorStyle] autorelease]];
[[self cell] setImage:[NSImage imageNamed:@"star_on.png"]];
[[self cell] setDotImage:[NSImage imageNamed:@"star_off.png"]];

}
return self;
}
- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)flag
{
return YES;
}


@end

Hi Hendo,

the method belongs to the cell implementation part, not in the control - place it somewhere in ‘@implementation CustomImageLevelIndicatorCell’.

The mouse handling could look like this for example:

[code]- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)flag{
NSEvent *currentEvent = theEvent;
NSPoint mouseLocation;
float percentage;
const float maxLength = [controlView bounds].size.width ;
do {
mouseLocation = [controlView convertPoint: [currentEvent locationInWindow] fromView:nil];

	switch ([currentEvent type]) {
		case NSLeftMouseDown:
		case NSLeftMouseDragged:
			percentage = mouseLocation.x / maxLength;
			if (percentage < 0) percentage = 0; else if (percentage > 1.0) percentage = 1.0;
			[self setFloatValue:percentage * [self maxValue] ]; 
			break;
		default:
			return YES;
			break;
	}
} while (currentEvent =  [[controlView window] nextEventMatchingMask:NSLeftMouseUpMask|NSLeftMouseDraggedMask 
														   untilDate:[NSDate distantFuture] 
														      inMode:NSEventTrackingRunLoopMode 
															 dequeue:YES]);
															 
return YES;

}[/code]
If this solves your problem, would you please be so kind making a note in the other thread? Thx :slight_smile:

Dominik

sure thing Dom, your a life saver (as usual :slight_smile: ), I just found out that all school buses have been cancelled so I don’t have to go to school today, so im gunna get a few extra hours of sleep :smiley:

We’re getting closer, now I don’t know if this is the Obj-C or the applescript conflicting but say the current song is 4 stars. I can actually change the number of stars but it lasts for like a millisecond and then goes back to four stars…

I have tried the modified custom levelindicator and it seems to work:

http://rapidshare.com/files/74048663/CustomLITest.zip.html

it must be an applescripting conflict then. Obviosuly to set the stars i should just call the method in an on clicked handler. What about getting the stars. What handlers should I call that method from?

hmm I’m not sure if I have fully understood your problem - what method are you talking of? To set and get the rating value I would use:

set float value of control "levelindicator" of window "main" to 3.5

set currentrating to float value of control "levelindicator" of window "main"

well the float value won’t always be 3.5 right? It will be whatever they click on the level indicator.

These are the 2 sub-routines I’m using:

on getstars()
	tell application "iTunes"
		try
			set starnum to (rating of current track) div 20
		on error
			set starnum to 0
		end try
	end tell
	
	set float value of control "ri" of window "main" to starnum
end getstars

on setstars()
	set therate to (float value of control "ri" of window "main") * 20
	tell application "iTunes"
		try
			set rating of current track to therate
		on error
			display dialog "Before you rate a song you have to play one!"
		end try
	end tell
end setstars

I call the setstars in an on clicked handler and the getstars in the on idle handler

Well, I’m still what of a noob here, but what I read in Dominik’s post is:

to set the value of the levelindicator to 3.5 (or whichever value you want)

to get the value of the levelindicator at that moment and put that value into the variable ‘currentrating’ for your perusal…

Hope I’m not too off here :cool:

and I see you, hendo13 doing just that in your code. So what exactly is going wrong here?

Are you using the idle handler to check the current track? I thought you were using notifications for that…

notifications? I never used notifications…I don’t think :/. I don’t really no what they are …the rating indicator used to work fine…

hmm - probably I misunderstood. I thought you wanted to know how to set & get the rating programmatically. Now from what you wrote I assume it’s more that you need to know how to catch a user input with our custom level indicator - right?

You used a ‘custom view’ in Interface Builder?

Then this was for example possible by connecting your level indicator to an ‘on mouse up’ handler and modify the mousehandling code of the cell like this:

- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)flag{
	NSEvent *currentEvent = theEvent;
	NSPoint mouseLocation;
	float percentage;
	const float maxLength = [controlView bounds].size.width ;
	do {
		mouseLocation = [controlView convertPoint: [currentEvent locationInWindow] fromView:nil];
		
		switch ([currentEvent type]) {
			case NSLeftMouseDown:
			case NSLeftMouseDragged:
				percentage = mouseLocation.x / maxLength;
				if (percentage < 0) percentage = 0; else if (percentage > 1.0) percentage = 1.0;
				[self setFloatValue:percentage * [self maxValue] ]; 
				break;

			// new code here:
			case NSLeftMouseUp:
				[controlView mouseUp:currentEvent];
				return YES;
				break;
			// ======

				default:
				return YES;
				break;
		}
	} while (currentEvent = [[controlView window] nextEventMatchingMask:NSLeftMouseUpMask|NSLeftMouseDraggedMask 
															  untilDate:[NSDate distantFuture] 
																 inMode:NSEventTrackingRunLoopMode 
																dequeue:YES]);
	
	return YES;
} 

now you can catch the mouse events similar to an ‘on clicked’ handler of a button:

on mouse up theObject event theEvent
	log (get float value of theObject)
end mouse up

I’ll give that a try! Thanks!!

Still doesn’t work…does the same thing…should I just send you my project?