]> git.sesse.net Git - vlc/blob - modules/gui/macosx/VLCUIWidgets.m
macosx: Update file headers on extensions
[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  at implementation VLCDialogButton
30  at synthesize widget;
31  at end
32
33
34  at implementation VLCDialogPopUpButton
35  at synthesize widget;
36  at end
37
38
39  at implementation VLCDialogTextField
40  at synthesize widget;
41  at end
42
43
44  at implementation VLCDialogWindow
45  at synthesize dialog;
46  at synthesize has_lock;
47  at end
48
49
50  at implementation VLCDialogList
51  at synthesize widget;
52  at 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  at end
64
65
66  at implementation VLCDialogGridView
67
68 - (NSUInteger)numViews
69 {
70     return [_griddedViews count];
71 }
72
73 - (id)init
74 {
75     if ((self = [super init]))
76     {
77         _colCount = 0;
78         _rowCount = 0;
79         _griddedViews = [[NSMutableArray alloc] init];
80     }
81
82     return self;
83 }
84 - (void)dealloc
85 {
86     [_griddedViews release];
87     [super dealloc];
88 }
89
90 - (void)recomputeCount
91 {
92     _colCount = 0;
93     _rowCount = 0;
94     for (NSDictionary *obj in _griddedViews)
95     {
96         NSUInteger row = [[obj objectForKey:@"row"] intValue];
97         NSUInteger col = [[obj objectForKey:@"col"] intValue];
98         if (col + 1 > _colCount)
99             _colCount = col + 1;
100         if (row + 1 > _rowCount)
101             _rowCount = row + 1;
102     }
103 }
104
105 - (void)recomputeWindowSize
106 {
107     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(recomputeWindowSize) object:nil];
108
109     NSWindow *window = [self window];
110     NSRect frame = [window frame];
111     NSRect contentRect = [window contentRectForFrameRect:frame];
112     contentRect.size = [self flexSize:frame.size];
113     NSRect newFrame = [window frameRectForContentRect:contentRect];
114     newFrame.origin.y -= newFrame.size.height - frame.size.height;
115     newFrame.origin.x -= (newFrame.size.width - frame.size.width) / 2;
116     [window setFrame:newFrame display:YES animate:YES];
117 }
118
119 - (NSSize)objectSizeToFit:(NSView *)view
120 {
121     if ([view isKindOfClass:[NSControl class]]) {
122         NSControl *control = (NSControl *)view;
123         return [[control cell] cellSize];
124     }
125     return [view frame].size;
126 }
127
128 - (CGFloat)marginX
129 {
130     return 16;
131 }
132 - (CGFloat)marginY
133 {
134     return 8;
135 }
136
137 - (CGFloat)constrainedHeightOfRow:(NSUInteger)targetRow
138 {
139     CGFloat height = 0;
140     for(NSDictionary *obj in _griddedViews) {
141         NSUInteger row = [[obj objectForKey:@"row"] intValue];
142         if (row != targetRow)
143             continue;
144         NSUInteger rowSpan = [[obj objectForKey:@"rowSpan"] intValue];
145         if (rowSpan != 1)
146             continue;
147         NSView *view = [obj objectForKey:@"view"];
148         if ([view autoresizingMask] & NSViewHeightSizable)
149             continue;
150         NSSize sizeToFit = [self objectSizeToFit:view];
151         if (height < sizeToFit.height)
152             height = sizeToFit.height;
153     }
154     return height;
155 }
156
157 - (CGFloat)remainingRowsHeight
158 {
159     NSUInteger height = [self marginY];
160     if (!_rowCount)
161         return 0;
162     NSUInteger autosizedRows = 0;
163     for (NSUInteger i = 0; i < _rowCount; i++) {
164         CGFloat constrainedHeight = [self constrainedHeightOfRow:i];
165         if (!constrainedHeight)
166             autosizedRows++;
167         height += constrainedHeight + [self marginY];
168     }
169     CGFloat remaining = 0;
170     if (height < self.bounds.size.height && autosizedRows)
171         remaining = (self.bounds.size.height - height) / autosizedRows;
172     if (remaining < 0)
173         remaining = 0;
174
175     return remaining;
176 }
177
178 - (CGFloat)heightOfRow:(NSUInteger)targetRow
179 {
180     NSAssert(targetRow < _rowCount, @"accessing a non existing row");
181     CGFloat height = [self constrainedHeightOfRow:targetRow];
182     if (!height)
183         height = [self remainingRowsHeight];
184     return height;
185 }
186
187
188 - (CGFloat)topOfRow:(NSUInteger)targetRow
189 {
190     CGFloat top = [self marginY];
191     for (NSUInteger i = 1; i < _rowCount - targetRow; i++)
192     {
193         top += [self heightOfRow:_rowCount - i] + [self marginY];
194     }
195     return top;
196 }
197
198 - (CGFloat)constrainedWidthOfColumn:(NSUInteger)targetColumn
199 {
200     CGFloat width = 0;
201     for(NSDictionary *obj in _griddedViews) {
202         NSUInteger col = [[obj objectForKey:@"col"] intValue];
203         if (col != targetColumn)
204             continue;
205         NSUInteger colSpan = [[obj objectForKey:@"colSpan"] intValue];
206         if (colSpan != 1)
207             continue;
208         NSView *view = [obj objectForKey:@"view"];
209         if ([view autoresizingMask] & NSViewWidthSizable)
210             return 0;
211         NSSize sizeToFit = [self objectSizeToFit:view];
212         if (width < sizeToFit.width)
213             width = sizeToFit.width;
214     }
215     return width;
216 }
217
218 - (CGFloat)remainingColumnWidth
219 {
220     NSUInteger width = [self marginX];
221     if (!_colCount)
222         return 0;
223     NSUInteger autosizedCol = 0;
224     for (NSUInteger i = 0; i < _colCount; i++) {
225         CGFloat constrainedWidth = [self constrainedWidthOfColumn:i];
226         if (!constrainedWidth)
227             autosizedCol++;
228         width += constrainedWidth + [self marginX];
229     }
230     CGFloat remaining = 0;
231     if (width < self.bounds.size.width && autosizedCol)
232         remaining = (self.bounds.size.width - width) / autosizedCol;
233     if (remaining < 0)
234         remaining = 0;
235     return remaining;
236 }
237
238 - (CGFloat)widthOfColumn:(NSUInteger)targetColumn
239 {
240     CGFloat width = [self constrainedWidthOfColumn:targetColumn];
241     if (!width)
242         width = [self remainingColumnWidth];
243     return width;
244 }
245
246
247 - (CGFloat)leftOfColumn:(NSUInteger)targetColumn
248 {
249     CGFloat left = [self marginX];
250     for (NSUInteger i = 0; i < targetColumn; i++)
251     {
252         left += [self widthOfColumn:i] + [self marginX];
253     }
254     return left;
255 }
256
257 - (void)relayout
258 {
259     for(NSDictionary *obj in _griddedViews) {
260         NSUInteger row = [[obj objectForKey:@"row"] intValue];
261         NSUInteger col = [[obj objectForKey:@"col"] intValue];
262         NSUInteger rowSpan = [[obj objectForKey:@"rowSpan"] intValue];
263         NSUInteger colSpan = [[obj objectForKey:@"colSpan"] intValue];
264         NSView *view = [obj objectForKey:@"view"];
265         NSRect rect;
266
267         // Get the height
268         if ([view autoresizingMask] & NSViewHeightSizable || rowSpan > 1) {
269             CGFloat height = 0;
270             for (NSUInteger r = 0; r < rowSpan; r++) {
271                 if (row + r >= _rowCount)
272                     break;
273                 height += [self heightOfRow:row + r] + [self marginY];
274             }
275             rect.size.height = height - [self marginY];
276         }
277         else
278             rect.size.height = [self objectSizeToFit:view].height;
279
280         // Get the width
281         if ([view autoresizingMask] & NSViewWidthSizable) {
282             CGFloat width = 0;
283             for (NSUInteger c = 0; c < colSpan; c++)
284                 width += [self widthOfColumn:col + c] + [self marginX];
285             rect.size.width = width - [self marginX];
286         }
287         else
288             rect.size.width = [self objectSizeToFit:view].width;
289
290         // Top corner
291         rect.origin.y = [self topOfRow:row] + ([self heightOfRow:row] - rect.size.height) / 2;
292         rect.origin.x = [self leftOfColumn:col];
293
294         [view setFrame:rect];
295         [view setNeedsDisplay:YES];
296     }
297 }
298
299 - (NSMutableDictionary *)objectForView:(NSView *)view
300 {
301     for (NSMutableDictionary *dict in _griddedViews)
302     {
303         if ([dict objectForKey:@"view"] == view)
304             return dict;
305     }
306     return nil;
307 }
308
309 - (void)addSubview:(NSView *)view atRow:(NSUInteger)row column:(NSUInteger)column
310                                                        rowSpan:(NSUInteger)rowSpan
311                                                        colSpan:(NSUInteger)colSpan
312 {
313     if (row + 1 > _rowCount)
314         _rowCount = row + 1;
315     if (column + 1 > _colCount)
316         _colCount = column + 1;
317
318     NSMutableDictionary *dict = [self objectForView:view];
319     if (!dict) {
320         dict = [NSMutableDictionary dictionary];
321         [dict setObject:view forKey:@"view"];
322         [_griddedViews addObject:dict];
323     }
324     [dict setObject:[NSNumber numberWithInt:rowSpan] forKey:@"rowSpan"];
325     [dict setObject:[NSNumber numberWithInt:colSpan] forKey:@"colSpan"];
326     [dict setObject:[NSNumber numberWithInt:row] forKey:@"row"];
327     [dict setObject:[NSNumber numberWithInt:column] forKey:@"col"];
328
329     [self addSubview:view];
330     [self relayout];
331
332     // Recompute the size of the window after making sure we won't see anymore update
333     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(recomputeWindowSize) object:nil];
334     [self performSelector:@selector(recomputeWindowSize) withObject:nil afterDelay:0.1];
335 }
336
337 - (void)removeSubview:(NSView *)view
338 {
339     NSDictionary *dict = [self objectForView:view];
340     if (dict)
341         [_griddedViews removeObject:dict];
342     [view removeFromSuperview];
343
344     [self recomputeCount];
345     [self recomputeWindowSize];
346
347     [self relayout];
348     [self setNeedsDisplay:YES];
349 }
350
351 - (void)setFrame:(NSRect)frameRect
352 {
353     [super setFrame:frameRect];
354     [self relayout];
355 }
356
357 - (NSSize)flexSize:(NSSize)size
358 {
359     if (!_rowCount || !_colCount)
360         return size;
361
362     CGFloat minHeight = [self marginY];
363     BOOL canFlexHeight = NO;
364     for (NSUInteger i = 0; i < _rowCount; i++) {
365         CGFloat constrained = [self constrainedHeightOfRow:i];
366         if (!constrained) {
367             canFlexHeight = YES;
368             constrained = 128;
369         }
370         minHeight += constrained + [self marginY];
371     }
372
373     CGFloat minWidth = [self marginX];
374     BOOL canFlexWidth = NO;
375     for (NSUInteger i = 0; i < _colCount; i++) {
376         CGFloat constrained = [self constrainedWidthOfColumn:i];
377         if (!constrained) {
378             canFlexWidth = YES;
379             constrained = 128;
380         }
381         minWidth += constrained + [self marginX];
382     }
383     if (size.width < minWidth)
384         size.width = minWidth;
385     if (size.height < minHeight)
386         size.height = minHeight;
387     if (!canFlexHeight)
388         size.height = minHeight;
389     if (!canFlexWidth)
390         size.width = minWidth;
391     return size;
392 }
393
394  at end