discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: SMDoubleSlider usability on GNUstep


From: Fred Kiefer
Subject: Re: SMDoubleSlider usability on GNUstep
Date: Wed, 7 Mar 2018 23:35:53 +0100

Just to keep you updated. Things are even more complicated than I thought. 
Here the extended code I have been using for my tests:

#import <Cocoa/Cocoa.h>

 @interface Proxy : NSProxy
 {
 @public
 id obj;
 }
 @end
 
 @implementation Proxy
 - (BOOL)respondsToSelector: (SEL)aSelector
 {
 return [obj respondsToSelector: aSelector];
 }

- (NSMethodSignature*)methodSignatureForSelector: (SEL)aSelector
 {
 return [obj methodSignatureForSelector: aSelector];
 }

 - (void)forwardInvocation: (NSInvocation*)anInvocation
 {
     NSLog(@"%@ sent to proxy", NSStringFromSelector([anInvocation selector]));
     [anInvocation invokeWithTarget: obj];
 }

 - (BOOL)isKindOfClass: (Class)clazz
 {
     NSLog(@"isKindOfClass: called with %@", clazz);
     return [obj isKindOfClass: clazz];
 }

 - (Proxy*) copyWithZone: (NSZone*)zone
 {
     Proxy *copy = [[self class] alloc];
     copy->obj = [self->obj copyWithZone: zone];
     return copy;
 }
 @end
 
 //@interface Test : NSActionCell @end
 @interface Test : NSSliderCell @end
 @implementation Test
 - (float)floatValue
 {
 NSLog(@"-floatValue called\n");
 return [super floatValue];
 }
- (double)doubleValue
{
    NSLog(@"-doubleValue called\n");
    return [super doubleValue];
}
 - (NSString*)stringValue
 {
 NSLog(@"-stringValue called\n");
 return [super stringValue];
 }
 - (id)objectValue
 {
 NSLog(@"-objectValue called\n");
 return [super objectValue];
 }
 - (void)setObjectValue:(id)objectValue
 {
 NSLog(@"-setObjectValue called\n");
 [super setObjectValue:objectValue];
 }
 - (void)setStringValue:(NSString *)stringValue
 {
 NSLog(@"-setStringValue called\n");
 [super setStringValue:stringValue];
 }
- (void)describe
{
    NSLog(@"type %d valid %d font %@", (int)[self type], [self 
hasValidObjectValue], [self font]);
    NSLog(@"value %lf", [self doubleValue]);
    NSLog(@"max %lf min %lf", [self maxValue], [self minValue]);
}
 @end
 
 int main(void)
 {
     @autoreleasepool
     {
         Test *t = [[Test alloc] initTextCell: @""];
         //NSImage *image = [NSImage imageNamed: NSImageNameComputer];
         //Test *t = [[Test alloc] initImageCell: image];
         //Test *t = [[Test alloc] init];
         [t describe];
         //[t setMaxValue: 100.0];
         Proxy *p = [Proxy alloc];
         p->obj = @"0.23";
         [t setObjectValue: p];
         /*
         NSLog(@"Start setFloatValue");
         [t setFloatValue: 12.4f];
          */
         NSLog(@"Start setDoubleValue");
         [t setDoubleValue: 34.5];
         NSLog(@"Querying");
         NSLog(@"%f", [t floatValue]);
         NSLog(@"%lf", [t doubleValue]);
         NSLog(@"%@", [t stringValue]);
         NSLog(@"%@", [t objectValue]);
         //NSLog(@"%d", [[t objectValue] isKindOfClass: [NSNumber class]]);
     }
 }


To me it now looks like NSSliderCell just overrides all the value methods of 
its super calls and implements them by setting a numerical value directly. Not 
the nicest code, but to be compatible we may have to do a similar rewrite.
For NSCell and specific sub classes things are different, but only if these get 
initialised as text cells. Doing this on an NSSliderCell would not set the max 
value, which prevents that cell from working.

I plan to do a full rewrite of NSSliderCell, without touching NSCell at all. 
This should be enough to get  SMDoubleSlider working under GNUstep.

Cheers,
Fred


> Am 26.02.2018 um 23:42 schrieb Fred Kiefer <fredkiefer@gmx.de>:
> 
> As usual it turns out that things are slightly more complicated. There
> is a tiny problem with David's test code, he did set "t" as its own
> object value instead of using the proxy there. When correcting this I
> noticed that the value from the proxy never gets used and extended the
> test code slightly and finally testing with different subclasses of
> NSCell, not just NSActionCell. They behave violently different. For
> NSCell and NSActionCell floatValue and doubleValue always return 0.0
> even when setting this value explicitly. NSSliderCell and
> NSTextFieldCell behave different, but also not the same way. Looks like
> we will need to investigate further and most likely will need to move
> the actual value handling code down into the specific NSCell subclasses.
> This sounds very ugly to me.
> 
> Fred
> 
> 
> Am 20.02.2018 um 15:55 schrieb David Chisnall:
>> On 20 Feb 2018, at 14:30, Yavor Doganov <yavor@gnu.org> wrote:
>>> 
>>> I think this condition is always false.  _cell.has_valid_object_value
>>> is NO and _object_value is nil.  So it jumps to NSCell.m:269 and
>>> SMDoubleSliderCell's -stringValue is called which calls -stringHiValue
>>> which in turn calls -doubleHiValue and from there the infinite
>>> recursion is in place.
>>> 
>>> At least this is what I observe in the debugger.
>> 
>> Ah, that makes sense - I’d missed that in the trace.  So now the question is 
>> what happens when you call -doubleValue on an NSCell in Cocoa when it has a 
>> string value?  Here’s a little test program that finds out:
>> 
>> #import <Cocoa/Cocoa.h>
>> 
>> @interface Proxy : NSProxy
>> {
>>      @public
>>      id obj;
>> }
>> @end
>> 
>> @implementation Proxy
>> - (BOOL)respondsToSelector: (SEL)aSelector
>> {
>>      return [obj respondsToSelector: aSelector];
>> }
>> - (NSMethodSignature*)methodSignatureForSelector: (SEL)aSelector
>> {
>>      return [obj methodSignatureForSelector: aSelector];
>> }
>> - (void)forwardInvocation: (NSInvocation*)anInvocation
>> {
>>      NSLog(@"%@ set to proxy", anInvocation);
>>      [anInvocation invokeWithTarget: obj];
>> }
>> @end
>> 
>> @interface Test : NSActionCell @end
>> @implementation Test
>> - (float)floatValue
>> {
>>      NSLog(@"-floatValue called\n");
>>      return [super floatValue];
>> }
>> - (NSString*)stringValue
>> {
>>      NSLog(@"-stringValue called\n");
>>      return [super stringValue];
>> }
>> @end
>> 
>> int main(void)
>> {
>>      @autoreleasepool
>>      {
>>              Test *t = [Test new];
>>              Proxy *p = [Proxy alloc];
>>              p->obj = @"0.23";
>>              [t setObjectValue: t];
>>              NSLog(@"Querying");
>>              NSLog(@"%f", [t floatValue]);
>>      }
>> }
>> 
>> The output is:
>> 
>> 2018-02-20 14:46:39.917 a.out[85231:11731363] Querying
>> 2018-02-20 14:46:39.917 a.out[85231:11731363] -floatValue called
>> 2018-02-20 14:46:39.917 a.out[85231:11731363] 0.000000
>> 
>> 
>> So, from this we learn that Cocoa’s NSCell implementation doesn’t call any 
>> methods on either itself or the object to find the floating point value.  
>> This is a bit odd, but at the very least we should fix GNUstep’s NSCell to 
>> query the object and not itself to find the string value.  The correct fix 
>> is probably:
>> 
>> - (float) floatValue
>> {
>>  if (_cell.has_valid_object_value == YES)
>>  {
>>    if ([_object_value respondsToSelector: @selector(floatValue)]))
>>    {
>>      return [_object_value floatValue];
>>    }
>>    if ([_object_value respondsToSelector: @selector(stringValue)]))
>>    {
>>      return [[_object_value stringValue] floatValue];
>>    }
>>  }
>>  return 0;
>> }
>> 
>> And apply similar fixes to the other *Value methods in NSCell.
>> 
>> You can hack around this brokenness by including the above method in a 
>> category on NSCell in your application (though please remember to remove it 
>> once GNUstep is fixed!).
>> 
>> David
> 
> _______________________________________________
> Discuss-gnustep mailing list
> Discuss-gnustep@gnu.org
> https://lists.gnu.org/mailman/listinfo/discuss-gnustep




reply via email to

[Prev in Thread] Current Thread [Next in Thread]