macOS: Fix drawing of VLCHUDTextFieldCell
[vlc.git] / modules / gui / macosx / VLCHUDTextFieldCell.m
1 //
2 //  VLCHUDTextFieldCell.m
3 //  BGHUDAppKit
4 //
5 //  Created by BinaryGod on 6/2/08.
6 //
7 //              Copyright (c) 2008, Tim Davis (BinaryMethod.com, binary.god@gmail.com)
8 //  All rights reserved.
9 //
10 //              Redistribution and use in source and binary forms, with or without modification,
11 //  are permitted provided that the following conditions are met:
12 //
13 //              Redistributions of source code must retain the above copyright notice, this
14 //      list of conditions and the following disclaimer.
15 //
16 //              Redistributions in binary form must reproduce the above copyright notice,
17 //      this list of conditions and the following disclaimer in the documentation and/or
18 //      other materials provided with the distribution.
19 //
20 //              Neither the name of the BinaryMethod.com nor the names of its contributors
21 //      may be used to endorse or promote products derived from this software without
22 //      specific prior written permission.
23 //
24 //      THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND
25 //      ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 //      WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 //      IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 //      INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 //      BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
30 //      OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 //      WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 //      ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 //      POSSIBILITY OF SUCH DAMAGE.
34 //
35 //  History
36 //
37 //              8/30/2010 - Fixed placeholder alignment not rendering while in design view,
38 //                                      provided by [tylerb](GitHub).
39
40 #import "VLCHUDTextFieldCell.h"
41
42 @interface VLCHUDTextFieldCell () {
43     bool fillsBackground;
44 }
45
46 @end
47
48 @implementation VLCHUDTextFieldCell
49
50 #pragma mark Drawing Functions
51
52 - (instancetype)initTextCell:(NSString *)aString
53 {
54     self = [super initTextCell: aString];
55
56     if (self) {
57         [self commonInit];
58     }
59
60     return self;
61 }
62
63 - (instancetype)initWithCoder:(NSCoder *)decoder
64 {
65     self = [super initWithCoder:decoder];
66
67     if (self) {
68         [self commonInit];
69     }
70
71     return self;
72 }
73
74 - (void)commonInit
75 {
76     // Init colors
77     _focusRing = [[NSShadow alloc] init];
78     [_focusRing setShadowColor:NSColor.whiteColor];
79     [_focusRing setShadowBlurRadius:3];
80     [_focusRing setShadowOffset:NSMakeSize(0, 0)];
81
82     _strokeColor = [NSColor colorWithDeviceRed:0.749f green:0.761f blue:0.788f alpha:1.0f];
83     _disabledStrokeColor = [NSColor colorWithDeviceRed:0.749f green:0.761f blue:0.788f alpha:0.2f];
84     _selectionHighlightActiveColor = [NSColor darkGrayColor];
85     _selectionTextActiveColor = [NSColor whiteColor];
86     _selectionHighlightInActiveColor = [NSColor darkGrayColor];
87     _selectionTextInActiveColor = [NSColor whiteColor];
88     _placeholderTextColor = [NSColor grayColor];
89     _cellTextColor = [NSColor whiteColor];
90     _disabledStrokeColor = [NSColor colorWithDeviceRed:1 green:1 blue:1 alpha:0.2f];
91     _textFillColor = [NSColor colorWithDeviceRed:.224f green:.224f blue:.224f alpha:.95f];
92
93     // Init some properties
94     [self setTextColor:_cellTextColor];
95
96     if ([self drawsBackground]) {
97         fillsBackground = YES;
98     }
99
100     [self setDrawsBackground: NO];
101 }
102
103 - (NSText *)setUpFieldEditorAttributes:(NSText *)textObj
104 {
105     NSText *newText = [super setUpFieldEditorAttributes:textObj];
106     NSColor *textColor = _cellTextColor;
107     [(NSTextView *)newText setInsertionPointColor:textColor];
108     return newText;
109 }
110
111 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
112 {
113     // Adjust Rect
114     cellFrame = NSInsetRect(cellFrame, 0.5f, 0.5f);
115
116     // Create Path
117     NSBezierPath *path = [NSBezierPath bezierPath];
118
119     if ([self bezelStyle] == NSTextFieldRoundedBezel) {
120
121         [path appendBezierPathWithArcWithCenter:NSMakePoint(cellFrame.origin.x + (cellFrame.size.height /2), cellFrame.origin.y + (cellFrame.size.height /2))
122                                          radius:cellFrame.size.height /2
123                                      startAngle:90
124                                        endAngle:270];
125
126         [path appendBezierPathWithArcWithCenter:NSMakePoint(cellFrame.origin.x + (cellFrame.size.width - (cellFrame.size.height /2)), cellFrame.origin.y + (cellFrame.size.height /2))
127                                          radius:cellFrame.size.height /2
128                                      startAngle:270
129                                        endAngle:90];
130
131         [path closePath];
132
133     } else {
134         [path appendBezierPathWithRoundedRect: cellFrame xRadius: 3.0f yRadius: 3.0f];
135     }
136
137     // Draw Background
138     if (fillsBackground) {
139         [_textFillColor set];
140         [path fill];
141     }
142
143     if ([self isBezeled] || [self isBordered]) {
144
145         [NSGraphicsContext saveGraphicsState];
146
147         if ([super showsFirstResponder] && [[[self controlView] window] isKeyWindow] &&
148            ([self focusRingType] == NSFocusRingTypeDefault ||
149             [self focusRingType] == NSFocusRingTypeExterior)) {
150                [_focusRing set];
151            }
152
153         // Check State
154         if ([self isEnabled]) {
155             [_strokeColor set];
156         } else {
157             [_disabledStrokeColor set];
158         }
159
160         [path setLineWidth:1.0f];
161         [path stroke];
162
163         [NSGraphicsContext restoreGraphicsState];
164     }
165
166     // Get TextView for this editor
167     NSTextView* view = (NSTextView*)[[controlView window] fieldEditor: NO forObject: controlView];
168
169     // If window/app is active draw the highlight/text in active colors
170     if (![self isHighlighted]) {
171
172         if ([view selectedRange].length > 0) {
173
174             // Get Attributes of the selected text
175             NSMutableDictionary *dict = [[view selectedTextAttributes] mutableCopy];
176
177             if ([[[self controlView] window] isKeyWindow]) {
178                 [dict setObject:_selectionHighlightActiveColor
179                          forKey:NSBackgroundColorAttributeName];
180
181                 [view setTextColor:_selectionTextActiveColor
182                              range:[view selectedRange]];
183             } else {
184                 [dict setObject:_selectionHighlightInActiveColor
185                          forKey:NSBackgroundColorAttributeName];
186
187                 [view setTextColor:_selectionTextInActiveColor
188                              range:[view selectedRange]];
189             }
190
191             [view setSelectedTextAttributes:dict];
192         } else {
193             // Only change color (marks view as dirty) if it had a selection at some point,
194             // thus changing the colors.
195             if ([view textColor] != _cellTextColor) {
196                 [self setTextColor:_cellTextColor];
197                 [view setTextColor:_cellTextColor];
198             }
199         }
200     } else {
201
202         if ([self isEnabled]) {
203             if ([self isHighlighted]) {
204                 if ([[[self controlView] window] isKeyWindow]){
205                     [self setTextColor:_selectionTextActiveColor];
206                 } else {
207                     [self setTextColor:_selectionTextInActiveColor];
208                 }
209             } else {
210                 [self setTextColor:_cellTextColor];
211             }
212         } else {
213             [self setTextColor:_disabledCellTextColor];
214         }
215     }
216
217     // Check to see if the attributed placeholder has been set or not
218     if (![self placeholderAttributedString] && [self placeholderString]) {
219
220         NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
221
222         // Set the paragraph style
223         [style setAlignment: [self alignment]];
224
225         // Attributed string doesn't exist lets create it
226         NSDictionary *attributes = @{
227                                      NSForegroundColorAttributeName : _placeholderTextColor,
228                                      NSParagraphStyleAttributeName  : style
229                                      };
230         NSAttributedString *attributedPlaceholder = [[NSAttributedString alloc] initWithString:self.placeholderString attributes:attributes];
231         [self setPlaceholderAttributedString:attributedPlaceholder];
232     } else if ([self placeholderAttributedString] && [[self placeholderAttributedString] length] > 0) {
233
234         // Check to see if the proper styles have been applied
235         if ([[[self placeholderAttributedString] attribute:NSParagraphStyleAttributeName atIndex:1 effectiveRange:nil] alignment] != [self alignment]) {
236
237             NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
238
239             // Set the paragraph style
240             [style setAlignment:[self alignment]];
241             
242             // Get current attr string
243             NSMutableAttributedString *adjPlaceholder = [[NSMutableAttributedString alloc] initWithAttributedString:[self placeholderAttributedString]];
244             
245             // Add style attr
246             [adjPlaceholder addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, [adjPlaceholder length])];
247             
248             // Reset Placeholder to correct placeholder
249             [self setPlaceholderAttributedString:adjPlaceholder];
250         }
251     }
252     
253     // Adjust Frame so Text Draws correctly
254     switch (self.controlSize) {
255         case NSRegularControlSize:
256             cellFrame.origin.y += (self.bezelStyle != NSTextFieldRoundedBezel) ? 1 : 0;
257             break;
258             
259         case NSSmallControlSize:
260             cellFrame.origin.y += (self.bezelStyle == NSTextFieldRoundedBezel) ? 1 : 0;
261             break;
262             
263         case NSMiniControlSize:
264             cellFrame.origin.x += (self.bezelStyle == NSTextFieldRoundedBezel) ? 1 : 0;
265             break;
266             
267         default:
268             break;
269     }
270
271     [self drawInteriorWithFrame: cellFrame inView: controlView];
272 }
273
274 - (void)_drawKeyboardFocusRingWithFrame:(NSRect)rect inView:(NSView*)view
275 {
276     // Do nothing
277 }
278
279 @end