]> git.sesse.net Git - vlc/blob - modules/gui/macosx/VLCUIWidgets.m
Useless #includes
[vlc] / modules / gui / macosx / VLCUIWidgets.m
1 /*****************************************************************************
2  * VLCUIWidgets.m: Widgets for VLC's extensions dialogs for Mac OS X
3  *****************************************************************************
4  * Copyright (C) 2009-2012 the VideoLAN team and authors
5  * $Id$
6  *
7  * Authors: Pierre d'Herbemont <pdherbemont # videolan dot>,
8  *          Brendon Justin <brendonjustin@gmail.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #import "VLCUIWidgets.h"
26
27 #import <stdlib.h>
28
29 @implementation VLCDialogButton
30 @synthesize widget;
31 @end
32
33
34 @implementation VLCDialogPopUpButton
35 @synthesize widget;
36 @end
37
38
39 @implementation VLCDialogTextField
40 @synthesize widget;
41 @end
42
43
44 @implementation VLCDialogWindow
45 @synthesize dialog;
46 @synthesize has_lock;
47 @end
48
49
50 @implementation VLCDialogList
51 @synthesize widget;
52 @synthesize contentArray;
53
54 - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
55 {
56     return [contentArray count];
57 }
58
59 - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
60 {
61     return [[contentArray objectAtIndex:rowIndex] objectForKey:@"text"];
62 }
63 @end
64
65
66 @implementation VLCDialogGridView
67
68 - (NSUInteger)numViews
69 {
70     return [_griddedViews count];
71 }
72
73 - (id)init
74 {
75     if ((self = [super init])) {
76         _colCount = 0;
77         _rowCount = 0;
78         _griddedViews = [[NSMutableArray alloc] init];
79     }
80
81     return self;
82 }
83 - (void)dealloc
84 {
85     [_griddedViews release];
86     [super dealloc];
87 }
88
89 - (void)recomputeCount
90 {
91     _colCount = 0;
92     _rowCount = 0;
93     for (NSDictionary *obj in _griddedViews) {
94         NSUInteger row = [[obj objectForKey:@"row"] intValue];
95         NSUInteger col = [[obj objectForKey:@"col"] intValue];
96         if (col + 1 > _colCount)
97             _colCount = col + 1;
98         if (row + 1 > _rowCount)
99             _rowCount = row + 1;
100     }
101 }
102
103 - (void)recomputeWindowSize
104 {
105     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(recomputeWindowSize) object:nil];
106
107     NSWindow *window = [self window];
108     NSRect frame = [window frame];
109     NSRect contentRect = [window contentRectForFrameRect:frame];
110     contentRect.size = [self flexSize:frame.size];
111     NSRect newFrame = [window frameRectForContentRect:contentRect];
112     newFrame.origin.y -= newFrame.size.height - frame.size.height;
113     newFrame.origin.x -= (newFrame.size.width - frame.size.width) / 2;
114     [window setFrame:newFrame display:YES animate:YES];
115 }
116
117 - (NSSize)objectSizeToFit:(NSView *)view
118 {
119     if ([view isKindOfClass:[NSControl class]]) {
120         NSControl *control = (NSControl *)view;
121         return [[control cell] cellSize];
122     }
123     return [view frame].size;
124 }
125
126 - (CGFloat)marginX
127 {
128     return 16;
129 }
130 - (CGFloat)marginY
131 {
132     return 8;
133 }
134
135 - (CGFloat)constrainedHeightOfRow:(NSUInteger)targetRow
136 {
137     CGFloat height = 0;
138     for(NSDictionary *obj in _griddedViews) {
139         NSUInteger row = [[obj objectForKey:@"row"] intValue];
140         if (row != targetRow)
141             continue;
142         NSUInteger rowSpan = [[obj objectForKey:@"rowSpan"] intValue];
143         if (rowSpan != 1)
144             continue;
145         NSView *view = [obj objectForKey:@"view"];
146         if ([view autoresizingMask] & NSViewHeightSizable)
147             continue;
148         NSSize sizeToFit = [self objectSizeToFit:view];
149         if (height < sizeToFit.height)
150             height = sizeToFit.height;
151     }
152     return height;
153 }
154
155 - (CGFloat)remainingRowsHeight
156 {
157     NSUInteger height = [self marginY];
158     if (!_rowCount)
159         return 0;
160     NSUInteger autosizedRows = 0;
161     for (NSUInteger i = 0; i < _rowCount; i++) {
162         CGFloat constrainedHeight = [self constrainedHeightOfRow:i];
163         if (!constrainedHeight)
164             autosizedRows++;
165         height += constrainedHeight + [self marginY];
166     }
167     CGFloat remaining = 0;
168     if (height < self.bounds.size.height && autosizedRows)
169         remaining = (self.bounds.size.height - height) / autosizedRows;
170     if (remaining < 0)
171         remaining = 0;
172
173     return remaining;
174 }
175
176 - (CGFloat)heightOfRow:(NSUInteger)targetRow
177 {
178     NSAssert(targetRow < _rowCount, @"accessing a non existing row");
179     CGFloat height = [self constrainedHeightOfRow:targetRow];
180     if (!height)
181         height = [self remainingRowsHeight];
182     return height;
183 }
184
185
186 - (CGFloat)topOfRow:(NSUInteger)targetRow
187 {
188     CGFloat top = [self marginY];
189     for (NSUInteger i = 1; i < _rowCount - targetRow; i++)
190         top += [self heightOfRow:_rowCount - i] + [self marginY];
191
192     return top;
193 }
194
195 - (CGFloat)constrainedWidthOfColumn:(NSUInteger)targetColumn
196 {
197     CGFloat width = 0;
198     for(NSDictionary *obj in _griddedViews) {
199         NSUInteger col = [[obj objectForKey:@"col"] intValue];
200         if (col != targetColumn)
201             continue;
202         NSUInteger colSpan = [[obj objectForKey:@"colSpan"] intValue];
203         if (colSpan != 1)
204             continue;
205         NSView *view = [obj objectForKey:@"view"];
206         if ([view autoresizingMask] & NSViewWidthSizable)
207             return 0;
208         NSSize sizeToFit = [self objectSizeToFit:view];
209         if (width < sizeToFit.width)
210             width = sizeToFit.width;
211     }
212     return width;
213 }
214
215 - (CGFloat)remainingColumnWidth
216 {
217     NSUInteger width = [self marginX];
218     if (!_colCount)
219         return 0;
220     NSUInteger autosizedCol = 0;
221     for (NSUInteger i = 0; i < _colCount; i++) {
222         CGFloat constrainedWidth = [self constrainedWidthOfColumn:i];
223         if (!constrainedWidth)
224             autosizedCol++;
225         width += constrainedWidth + [self marginX];
226     }
227     CGFloat remaining = 0;
228     if (width < self.bounds.size.width && autosizedCol)
229         remaining = (self.bounds.size.width - width) / autosizedCol;
230     if (remaining < 0)
231         remaining = 0;
232     return remaining;
233 }
234
235 - (CGFloat)widthOfColumn:(NSUInteger)targetColumn
236 {
237     CGFloat width = [self constrainedWidthOfColumn:targetColumn];
238     if (!width)
239         width = [self remainingColumnWidth];
240     return width;
241 }
242
243
244 - (CGFloat)leftOfColumn:(NSUInteger)targetColumn
245 {
246     CGFloat left = [self marginX];
247     for (NSUInteger i = 0; i < targetColumn; i++) {
248         left += [self widthOfColumn:i] + [self marginX];
249     }
250     return left;
251 }
252
253 - (void)relayout
254 {
255     for(NSDictionary *obj in _griddedViews) {
256         NSUInteger row = [[obj objectForKey:@"row"] intValue];
257         NSUInteger col = [[obj objectForKey:@"col"] intValue];
258         NSUInteger rowSpan = [[obj objectForKey:@"rowSpan"] intValue];
259         NSUInteger colSpan = [[obj objectForKey:@"colSpan"] intValue];
260         NSView *view = [obj objectForKey:@"view"];
261         NSRect rect;
262
263         // Get the height
264         if ([view autoresizingMask] & NSViewHeightSizable || rowSpan > 1) {
265             CGFloat height = 0;
266             for (NSUInteger r = 0; r < rowSpan; r++) {
267                 if (row + r >= _rowCount)
268                     break;
269                 height += [self heightOfRow:row + r] + [self marginY];
270             }
271             rect.size.height = height - [self marginY];
272         }
273         else
274             rect.size.height = [self objectSizeToFit:view].height;
275
276         // Get the width
277         if ([view autoresizingMask] & NSViewWidthSizable) {
278             CGFloat width = 0;
279             for (NSUInteger c = 0; c < colSpan; c++)
280                 width += [self widthOfColumn:col + c] + [self marginX];
281             rect.size.width = width - [self marginX];
282         }
283         else
284             rect.size.width = [self objectSizeToFit:view].width;
285
286         // Top corner
287         rect.origin.y = [self topOfRow:row] + ([self heightOfRow:row] - rect.size.height) / 2;
288         rect.origin.x = [self leftOfColumn:col];
289
290         [view setFrame:rect];
291         [view setNeedsDisplay:YES];
292     }
293 }
294
295 - (NSMutableDictionary *)objectForView:(NSView *)view
296 {
297     for (NSMutableDictionary *dict in _griddedViews)
298     {
299         if ([dict objectForKey:@"view"] == view)
300             return dict;
301     }
302     return nil;
303 }
304
305 - (void)addSubview:(NSView *)view atRow:(NSUInteger)row column:(NSUInteger)column
306                                                        rowSpan:(NSUInteger)rowSpan
307                                                        colSpan:(NSUInteger)colSpan
308 {
309     if (row + 1 > _rowCount)
310         _rowCount = row + 1;
311     if (column + 1 > _colCount)
312         _colCount = column + 1;
313
314     NSMutableDictionary *dict = [self objectForView:view];
315     if (!dict) {
316         dict = [NSMutableDictionary dictionary];
317         [dict setObject:view forKey:@"view"];
318         [_griddedViews addObject:dict];
319     }
320     [dict setObject:[NSNumber numberWithInt:rowSpan] forKey:@"rowSpan"];
321     [dict setObject:[NSNumber numberWithInt:colSpan] forKey:@"colSpan"];
322     [dict setObject:[NSNumber numberWithInt:row] forKey:@"row"];
323     [dict setObject:[NSNumber numberWithInt:column] forKey:@"col"];
324
325     [self addSubview:view];
326     [self relayout];
327
328     // Recompute the size of the window after making sure we won't see anymore update
329     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(recomputeWindowSize) object:nil];
330     [self performSelector:@selector(recomputeWindowSize) withObject:nil afterDelay:0.1];
331 }
332
333 - (void)removeSubview:(NSView *)view
334 {
335     NSDictionary *dict = [self objectForView:view];
336     if (dict)
337         [_griddedViews removeObject:dict];
338     [view removeFromSuperview];
339
340     [self recomputeCount];
341     [self recomputeWindowSize];
342
343     [self relayout];
344     [self setNeedsDisplay:YES];
345 }
346
347 - (void)setFrame:(NSRect)frameRect
348 {
349     [super setFrame:frameRect];
350     [self relayout];
351 }
352
353 - (NSSize)flexSize:(NSSize)size
354 {
355     if (!_rowCount || !_colCount)
356         return size;
357
358     CGFloat minHeight = [self marginY];
359     BOOL canFlexHeight = NO;
360     for (NSUInteger i = 0; i < _rowCount; i++) {
361         CGFloat constrained = [self constrainedHeightOfRow:i];
362         if (!constrained) {
363             canFlexHeight = YES;
364             constrained = 128;
365         }
366         minHeight += constrained + [self marginY];
367     }
368
369     CGFloat minWidth = [self marginX];
370     BOOL canFlexWidth = NO;
371     for (NSUInteger i = 0; i < _colCount; i++) {
372         CGFloat constrained = [self constrainedWidthOfColumn:i];
373         if (!constrained) {
374             canFlexWidth = YES;
375             constrained = 128;
376         }
377         minWidth += constrained + [self marginX];
378     }
379     if (size.width < minWidth)
380         size.width = minWidth;
381     if (size.height < minHeight)
382         size.height = minHeight;
383     if (!canFlexHeight)
384         size.height = minHeight;
385     if (!canFlexWidth)
386         size.width = minWidth;
387     return size;
388 }
389
390 @end