macOS: Fix VLCHUDSegmentedCell text drawing
authorMarvin Scholz <epirat07@gmail.com>
Thu, 15 Jun 2017 00:31:56 +0000 (02:31 +0200)
committerMarvin Scholz <epirat07@gmail.com>
Thu, 15 Jun 2017 18:29:42 +0000 (20:29 +0200)
The custom cell would draw the text at the wrong location, this is
fixed by this commit. Additionally a lot of cleanup and restructuring
was done.

modules/gui/macosx/VLCHUDSegmentedCell.h
modules/gui/macosx/VLCHUDSegmentedCell.m

index 5899d1c..8bddb58 100644 (file)
@@ -36,7 +36,6 @@
 
 @interface VLCHUDSegmentedCell : NSSegmentedCell
 
-@property (strong) NSShadow *dropShadow;
 @property (strong) NSColor *strokeColor;
 @property (strong) NSGradient *highlightGradient;
 @property (strong) NSGradient *normalGradient;
@@ -44,7 +43,4 @@
 @property (strong) NSColor *cellTextColor;
 @property (strong) NSColor *disabledCellTextColor;
 
--(void)drawInteriorForSegment:(NSInteger)segment withFrame:(NSRect)rect;
--(BOOL)hasText;
-
 @end
index 3051f12..4b0ead5 100644 (file)
 
 #import "VLCHUDSegmentedCell.h"
 
-@interface NSSegmentedCell (private)
--(NSRect)rectForSegment:(NSInteger)segment inFrame:(NSRect)frame;
+@interface NSSegmentedCell (Private)
+
+- (NSRect)rectForSegment:(NSInteger)segment inFrame:(NSRect)frame;
+
 @end
 
+
 @implementation VLCHUDSegmentedCell
 
 - (instancetype)initWithCoder:(NSCoder *)decoder
     self = [super initWithCoder:decoder];
 
     if (self) {
-        _dropShadow = [[NSShadow alloc] init];
-        [_dropShadow setShadowColor:[NSColor blackColor]];
-        [_dropShadow setShadowBlurRadius:2];
-        [_dropShadow setShadowOffset:NSMakeSize(0, -1)];
-
         _strokeColor = [NSColor colorWithDeviceRed:0.749f green:0.761f blue:0.788f alpha:1.0f];
         _highlightGradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithDeviceRed:0.451f green:0.451f blue:0.455f alpha:0.5f]
                                                            endingColor:[NSColor colorWithDeviceRed:0.318f green:0.318f blue:0.318f alpha:0.5f]];
     return self;
 }
 
--(NSSegmentStyle)segmentStyle {
-
-    return [super segmentStyle];
-}
-
--(void)setSegmentStyle:(NSSegmentStyle) style {
-
-    if(style == NSSegmentStyleSmallSquare || style == NSSegmentStyleRounded) {
-
-        [super setSegmentStyle: style];
-    }
-}
-
-- (void)drawWithFrame:(NSRect)frame inView:(NSView *)view {
-
-    NSBezierPath *border;
-
-    switch ([self segmentStyle]) {
-        default: // Silence uninitialized variable warnings
-        case NSSegmentStyleSmallSquare:
-
-            //Adjust frame for shadow
-            frame.origin.x += 1.5f;
-            frame.origin.y += .5f;
-            frame.size.width -= 3;
-            frame.size.height -= 3;
-
-            border = [[NSBezierPath alloc] init];
-            [border appendBezierPathWithRect: frame];
-
-            break;
-
-        case NSSegmentStyleRounded: //NSSegmentStyleTexturedRounded:
-
-            //Adjust frame for shadow
-            frame.origin.x += 1.5f;
-            frame.origin.y += .5f;
-            frame.size.width -= 3;
-            frame.size.height -= 3;
-
-            border = [[NSBezierPath alloc] init];
-
-            [border appendBezierPathWithRoundedRect: frame
-                                            xRadius: 4.0f yRadius: 4.0f];
-            break;
-    }
-
-    //Setup to Draw Border
-    [NSGraphicsContext saveGraphicsState];
-
-    //Set Shadow + Border Color
-    if([self isEnabled])
-    {
-        [_dropShadow set];
+- (void)drawWithFrame:(NSRect)frame inView:(NSView *)view
+{
+    [_strokeColor setStroke];
+    for (NSInteger segment = 0; segment < self.segmentCount; segment++) {
+        NSRect segmentRect = [self rectForSegment:segment inFrame:frame];
+        [self drawBackgroundForSegment:segment inFrame:segmentRect];
+        [self drawSegment:segment inFrame:segmentRect withView:view];
     }
-    [_strokeColor set];
-
-    //Draw Border + Shadow
-    [border stroke];
 
-    [NSGraphicsContext restoreGraphicsState];
-
-    int segCount = 0;
-
-    while (segCount <= [self segmentCount] -1) {
-
-        [self drawSegment: segCount inFrame: frame withView: view];
-        segCount++;
-    }
+    NSBezierPath* rectanglePath = [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 0.55, 0.55) xRadius:3.0 yRadius:3.0];
+    [_strokeColor setStroke];
+    [rectanglePath setLineWidth:1.0];
+    [rectanglePath stroke];
 }
 
-- (void)drawSegment:(NSInteger)segment inFrame:(NSRect)frame withView:(NSView *)view {
-
-    //Calculate rect for this segment
-    NSRect fillRect = [self rectForSegment: segment inFrame: frame];
-    NSBezierPath *fillPath;
-
-    switch ([self segmentStyle]) {
-        default: // Silence uninitialized variable warnings
-        case NSSegmentStyleSmallSquare:
-
-            if(segment == ([self segmentCount] -1)) {
-
-                if(![self hasText]) { fillRect.size.width -= 3; }
-            }
-
-            fillPath = [[NSBezierPath alloc] init];
-            [fillPath appendBezierPathWithRect: fillRect];
-
-            break;
-
-        case NSSegmentStyleRounded: //NSSegmentStyleTexturedRounded:
-
-            //If this is the first segment, draw rounded corners
-            if(segment == 0) {
-
-                fillPath = [[NSBezierPath alloc] init];
-
-                [fillPath appendBezierPathWithRoundedRect: fillRect xRadius: 3 yRadius: 3];
-
-                //Setup our joining rect
-                NSRect joinRect = fillRect;
-                joinRect.origin.x += 4;
-                joinRect.size.width -= 4;
-
-                [fillPath appendBezierPathWithRect: joinRect];
-
-                //If this is the last segment, draw rounded corners
-            } else if (segment == ([self segmentCount] -1)) {
-
-                fillPath = [[NSBezierPath alloc] init];
-
-                if(![self hasText]) { fillRect.size.width -= 3; }
-
-                [fillPath appendBezierPathWithRoundedRect: fillRect xRadius: 3 yRadius: 3];
-
-                //Setup our joining rect
-                NSRect joinRect = fillRect;
-                joinRect.size.width -= 4;
-
-                [fillPath appendBezierPathWithRect: joinRect];
-
-            } else {
-                NSAssert(segment != 0 && segment != ([self segmentCount] -1), @"should be a middle segment");
-                fillPath = [[NSBezierPath alloc] init];
-                [fillPath appendBezierPathWithRect: fillRect];
-            }
-
-            break;
-    }
-
-    //Fill our pathss
-
-    NSGradient *gradient = nil;
-
-    if([self isEnabled])
-    {
-        if([self selectedSegment] == segment) {
-
-            gradient = _highlightGradient;
-        } else {
-
-            gradient = _normalGradient;
-        }
-    }
-    else {
-        gradient = _disabledNormalGradient;
-    }
+- (void)drawSegment:(NSInteger)segment inFrame:(NSRect)frame withView:(NSView *)view
+{
+    NSString *segmentText = [self labelForSegment:segment];
 
-    [gradient drawInBezierPath: fillPath angle: 90];
+    NSSize textSize = [segmentText sizeWithAttributes:nil];
 
-    //Draw Segment dividers ONLY if they are
-    //inside segments
-    if(segment != ([self segmentCount] -1)) {
+    frame.origin.y += (frame.size.height - textSize.height) / 2;
+    frame.size.height -= (frame.size.height - textSize.height) / 2;
 
-        [_strokeColor set];
-        [NSBezierPath strokeLineFromPoint: NSMakePoint(fillRect.origin.x + fillRect.size.width , fillRect.origin.y)
-                                  toPoint: NSMakePoint(fillRect.origin.x + fillRect.size.width, fillRect.origin.y + fillRect.size.height)];
-    }
+    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc]init] ;
+    [paragraphStyle setAlignment:NSTextAlignmentCenter];
 
-    [self drawInteriorForSegment: segment withFrame: fillRect];
+    NSDictionary *attributes = @{ NSForegroundColorAttributeName : (self.isEnabled) ? _cellTextColor : _disabledCellTextColor,
+                                  NSParagraphStyleAttributeName  : paragraphStyle };
+    [segmentText drawInRect:frame withAttributes:attributes];
 }
 
--(void)drawInteriorForSegment:(NSInteger)segment withFrame:(NSRect)rect {
-
-    NSAttributedString *newTitle;
-
-    //if([self labelForSegment: segment] != nil) {
-
-    NSMutableDictionary *textAttributes = [[NSMutableDictionary alloc] initWithCapacity: 0];
-
-    [textAttributes setValue: [NSFont controlContentFontOfSize: [NSFont systemFontSizeForControlSize: [self controlSize]]] forKey: NSFontAttributeName];
-    if([self isEnabled])
-    {
-        [textAttributes setValue:_cellTextColor forKey: NSForegroundColorAttributeName];
-    }
-    else {
-        [textAttributes setValue:_disabledCellTextColor forKey: NSForegroundColorAttributeName];
-    }
-
-
-    if([self labelForSegment: segment]) {
+- (void)drawBackgroundForSegment:(NSInteger)segment inFrame:(NSRect)frame
+{
+    NSGradient *gradient;
 
-        newTitle = [[NSAttributedString alloc] initWithString: [self labelForSegment: segment] attributes: textAttributes];
+    if (self.isEnabled) {
+        gradient = (segment == self.selectedSegment) ? _highlightGradient : _normalGradient;
     } else {
-
-        newTitle = [[NSAttributedString alloc] initWithString: @"" attributes: textAttributes];
+        gradient = _disabledNormalGradient;
     }
-    //}
 
-    NSRect textRect = rect;
-    NSRect imageRect = rect;
-
-    if([super imageForSegment: segment] != nil) {
-
-        NSImage *image = [self imageForSegment: segment];
-        [image setFlipped: YES];
-
-        if([self imageScalingForSegment: segment] == NSImageScaleProportionallyDown) {
-
-            CGFloat resizeRatio = (rect.size.height - 4) / [image size].height;
-
-            [image setScalesWhenResized: YES];
-            [image setSize: NSMakeSize([image size].width * resizeRatio, rect.size.height -4)];
-        }
-
-        if([self labelForSegment: segment] != nil && ![[self labelForSegment: segment] isEqualToString: @""]) {
+    if (segment > 0 && segment < (self.segmentCount - 1)) {
+        // Middle segments
+        [gradient drawInRect:frame angle:90];
+        return;
+    }
 
-            imageRect.origin.y += (NSMidY(rect) - ([image size].height /2));
-            imageRect.origin.x += (NSMidX(rect) - (([image size].width + [newTitle size].width + 5) /2));
-            imageRect.size.height = [image size].height;
-            imageRect.size.width = [image size].width;
+    CGFloat radius = 3.0;
+    NSBezierPath* fillPath = [NSBezierPath bezierPath];
 
-            textRect.origin.y += (NSMidY(rect) - ([newTitle size].height /2));
-            textRect.origin.x += imageRect.origin.x + [image size].width + 5;
-            textRect.size.height = [newTitle size].height;
-            textRect.size.width = [newTitle size].width;
-            
-            [image drawInRect: imageRect fromRect: NSZeroRect operation: NSCompositeSourceAtop fraction: 0.5f];
-            [newTitle drawInRect: textRect];
-            
-        } else {
-            
-            //Draw Image Alone
-            imageRect.origin.y += (NSMidY(rect) - ([image size].height /2));
-            imageRect.origin.x += (NSMidX(rect) - ([image size].width /2));
-            imageRect.size.height = [image size].height;
-            imageRect.size.width = [image size].width;
-            
-            [image drawInRect: imageRect fromRect: NSZeroRect operation: NSCompositeSourceAtop fraction:0.5f];
-        }
+    if (segment == 0) {
+        // First segment
+        [fillPath appendBezierPathWithArcWithCenter: NSMakePoint(NSMinX(frame) + radius, NSMinY(frame) + radius) radius:radius startAngle:180 endAngle:270];
+        [fillPath lineToPoint: NSMakePoint(NSMaxX(frame), NSMinY(frame))];
+        [fillPath lineToPoint: NSMakePoint(NSMaxX(frame), NSMaxY(frame))];
+        [fillPath appendBezierPathWithArcWithCenter: NSMakePoint(NSMinX(frame) + radius, NSMaxY(frame) - radius) radius:radius startAngle:90 endAngle:180];
     } else {
-        
-        textRect.origin.y += (NSMidY(rect) - ([newTitle size].height /2));
-        textRect.origin.x += (NSMidX(rect) - ([newTitle size].width /2));
-        textRect.size.height = [newTitle size].height;
-        textRect.size.width = [newTitle size].width;
-        
-        if(textRect.origin.x < 3) { textRect.origin.x = 3; }
-        
-        [newTitle drawInRect: textRect];
-    }
-}
-
--(BOOL)hasText {
-    
-    int i = 0;
-    BOOL flag = NO;
-    
-    while(i <= [self segmentCount] -1) {
-        
-        if([self labelForSegment: i] != nil && ![[self labelForSegment: i] isEqualToString: @""]) {
-            
-            flag = YES;
-        }
-        i++;
+        // Last segment
+        [fillPath moveToPoint: NSMakePoint(NSMinX(frame), NSMinY(frame))];
+        [fillPath appendBezierPathWithArcWithCenter: NSMakePoint(NSMaxX(frame) - radius, NSMinY(frame) + radius) radius:radius startAngle:270 endAngle:360];
+        [fillPath appendBezierPathWithArcWithCenter: NSMakePoint(NSMaxX(frame) - radius, NSMaxY(frame) - radius) radius:radius startAngle:0 endAngle:90];
+        [fillPath lineToPoint: NSMakePoint(NSMinX(frame), NSMaxY(frame))];
     }
-    
-    return flag;
+    [fillPath closePath];
+    [gradient drawInBezierPath:fillPath angle:90];
 }
 
 - (BOOL)_canAnimate {
-    
     return NO;
 }