gwenhywfar 5.14.1
CocoaGridLayout.m
Go to the documentation of this file.
1//
2// CocoaGridLayout.m
3//
4//
5// Created by Samuel Strupp on 10.08.10.
6// Copyright 2010 Synium Software GmbH. All rights reserved.
7//
8
9#ifdef HAVE_CONFIG_H
10# include <config.h>
11#endif
12
13#import "CocoaGridLayout.h"
15
16
17@implementation CocoaGridLayout
18
19@synthesize fillX;
20@synthesize fillY;
21
22@synthesize columns;
23@synthesize rows;
24
25- (id)initWithFrame:(NSRect)frame {
26 self = [super initWithFrame:frame];
27 if (self) {
28 fillX = NO;
29 fillY = NO;
30 subviewsInOrder = [[NSMutableArray alloc] init];
31 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(layoutSubviews) name:NSViewFrameDidChangeNotification object:self];
32 }
33 return self;
34}
35
36-(void) dealloc {
37 [[NSNotificationCenter defaultCenter] removeObserver:self];
38 [subviewsInOrder release];
39 [super dealloc];
40}
41
42/*- (void)drawRect:(NSRect)dirtyRect {
43 //debug colors
44 [[NSColor redColor] set];
45 NSRectFill(dirtyRect);
46}*/
47
48#define borderDistance 8.0
49#define cellDistance 4.0
50
51-(void) layoutSubviews {
52 NSRect bounds = [self bounds];
53
54 NSUInteger numOfSubViews = [subviewsInOrder count];
55
56 if (numOfSubViews > 0) {
57 //Prepass to compute the sizes
58 BOOL columnMode = (columns > 0);
59
60 NSInteger neededColumns, neededRows;
61
62 if (columnMode) {
63 neededColumns = columns;
64 neededRows = numOfSubViews/columns + numOfSubViews%columns;
65 }
66 else {
67 if (rows > 0) {
68 neededColumns = numOfSubViews/rows + numOfSubViews%rows;
69 neededRows = rows;
70 }
71 else {
72 //We choose column mode with one column
73 neededColumns = 1;
74 neededRows = numOfSubViews;
75 }
76 }
77
78
79 CGFloat minWidthNeededForColumn[neededColumns];
80 CGFloat minHeightNeededForRow[neededRows];
81 char fillXFlags[neededColumns];
82 char fillYFlags[neededRows];
83
84 NSUInteger i;
85 for (i=0; i<neededColumns; i++) {
86 minWidthNeededForColumn[i] = 0.0;
87 fillXFlags[i] = 0;
88 }
89 for (i=0; i<neededRows; i++) {
90 minHeightNeededForRow[i] = 0.0;
91 fillYFlags[i] = 0;
92 }
93
94 NSInteger actualRow, actualColumn;
95
96 for (i=0; i<numOfSubViews; i++) {
97 if (columnMode) {
98 actualRow = i/neededColumns;
99 actualColumn = i%neededColumns;
100 }
101 else {
102 actualRow = i%neededRows;
103 actualColumn = i/neededRows;
104 }
105
106 NSView* subview = [subviewsInOrder objectAtIndex:i];
107 if ([subview conformsToProtocol:@protocol(CocoaGwenGUIProtocol)]) {
108 NSSize minSize = [(<CocoaGwenGUIProtocol>)subview minSize];
109
110 if (minWidthNeededForColumn[actualColumn] < minSize.width)
111 minWidthNeededForColumn[actualColumn] = minSize.width;
112
113 if (minHeightNeededForRow[actualRow] < minSize.height)
114 minHeightNeededForRow[actualRow] = minSize.height;
115
116 if ([(<CocoaGwenGUIProtocol>)subview fillX]) fillXFlags[actualColumn] = 1;
117 if ([(<CocoaGwenGUIProtocol>)subview fillY]) fillYFlags[actualRow] = 1;
118
119 }
120 }
121
122
123 //compute exact sizes
124 CGFloat maxWidth = bounds.size.width-borderDistance-borderDistance-(neededColumns-1)*cellDistance;
125 NSInteger flexibleCells = 0;
126 for(i=0; i<neededColumns; i++) {
127 if (fillXFlags[i] == 1) flexibleCells++;
128 else maxWidth -= minWidthNeededForColumn[i];
129 }
130 if (maxWidth > 0.0 && flexibleCells > 0) {
131 CGFloat flexibleStdWidth = maxWidth/flexibleCells;
132 for (i=0; i<neededColumns; i++) {
133 if (fillXFlags[i] == 1) minWidthNeededForColumn[i] = flexibleStdWidth;
134 }
135 }
136
137 CGFloat maxHeight = bounds.size.height-borderDistance-borderDistance-(neededRows-1)*cellDistance;
138 flexibleCells = 0;
139 for(i=0; i<neededRows; i++) {
140 if (fillYFlags[i] == 1) flexibleCells++;
141 else maxHeight -= minHeightNeededForRow[i];
142 }
143 if (maxHeight > 0.0 && flexibleCells > 0) {
144 CGFloat flexibleStdHeight = maxHeight/flexibleCells;
145 for (i=0; i<neededRows; i++) {
146 if (fillYFlags[i] == 1) minHeightNeededForRow[i] = flexibleStdHeight;
147 }
148 }
149
150
151
152
153 //Set the sizes to the view
154 NSRect actualFrame = bounds;
155 actualFrame.origin.x = borderDistance;
156 actualFrame.origin.y += bounds.size.height-borderDistance;
157
158
159 NSInteger oldIndex = -1;
160
161 for (i=0; i<numOfSubViews; i++) {
162 if (columnMode) {
163 actualRow = i/neededColumns;
164 actualColumn = i%neededColumns;
165
166 if (oldIndex != actualRow) {
167 actualFrame.origin.x = borderDistance;
168 actualFrame.origin.y -= minHeightNeededForRow[actualRow]+cellDistance;
169 oldIndex = actualRow;
170 }
171 }
172 else {
173 actualRow = i%neededRows;
174 actualColumn = i/neededRows;
175
176 if (oldIndex != actualColumn) {
177 if (oldIndex >= 0) actualFrame.origin.x += minWidthNeededForColumn[oldIndex]+cellDistance;
178 actualFrame.origin.y = bounds.origin.y+bounds.size.height-borderDistance-minHeightNeededForRow[actualRow];
179 oldIndex = actualColumn;
180 }
181 }
182
183 NSView* subview = [subviewsInOrder objectAtIndex:i];
184
185 actualFrame.size.height = minHeightNeededForRow[actualRow];
186 actualFrame.size.width = minWidthNeededForColumn[actualColumn];
187 NSRect realFrame = actualFrame;
188 if ([subview conformsToProtocol:@protocol(CocoaGwenGUIProtocol)]) {
189 BOOL flexWidth = [(<CocoaGwenGUIProtocol>)subview fillX];
190 BOOL flexHeight = [(<CocoaGwenGUIProtocol>)subview fillY];
191 if (!flexWidth || !flexHeight) {
192 NSSize minSize = [(<CocoaGwenGUIProtocol>)subview minSize];
193 if (!flexWidth && minSize.width < realFrame.size.width) realFrame.size.width = minSize.width;
194 if (!flexHeight && minSize.height < realFrame.size.height) {
195 realFrame.origin.y += realFrame.size.height-minSize.height;
196 realFrame.size.height = minSize.height;
197 }
198 }
199 }
200 [subview setFrame:realFrame];
201 //NSLog(@"frame = %@", NSStringFromRect(actualFrame));
202
203 if (columnMode) actualFrame.origin.x += actualFrame.size.width+cellDistance;
204 else if (actualRow+1 < neededRows) actualFrame.origin.y -= minHeightNeededForRow[actualRow+1]+cellDistance;
205 }
206
207 /*CGFloat sizesHeight[numOfSubViews];
208 CGFloat sizesWidth[numOfSubViews];
209 CGFloat exclusiveHeight = 0.0;
210 NSUInteger exclusiveChilds = 0;
211
212 NSUInteger i;
213 for (i=0; i<numOfSubViews; i++) {
214 NSView* subview = [subviewsInOrder objectAtIndex:i];
215 if ([subview conformsToProtocol:@protocol(CocoaGwenGUIProtocol)]) {
216 if ([(<CocoaGwenGUIProtocol>)subview fillX]) sizesWidth[i] = -1.0;
217 else {
218 CGFloat neededWidth = [(<CocoaGwenGUIProtocol>)subview minSize].width;
219 sizesWidth[i] = neededWidth;
220 }
221 if ([(<CocoaGwenGUIProtocol>)subview fillY]) sizesHeight[i] = -1.0;
222 else {
223 CGFloat neededHeight = [(<CocoaGwenGUIProtocol>)subview minSize].height;
224 sizesHeight[i] = neededHeight;
225 exclusiveHeight += neededHeight;
226 exclusiveChilds++;
227 }
228 }
229 else {
230 sizesWidth[i] = -1.0;
231 sizesHeight[i] = -1.0;
232 }
233 }
234
235
236 //Compute standard Sizes for Subviews
237
238 CGFloat stdHeight = 0.0;
239 if (numOfSubViews > exclusiveChilds) {
240 CGFloat fillHeight = bounds.size.height-exclusiveHeight;
241 stdHeight = (fillHeight-(borderDistance+borderDistance)-((numOfSubViews-1)*cellDistance))/(numOfSubViews-exclusiveChilds);
242 }
243 else {
244 CGFloat fillHeight = bounds.size.height;
245 stdHeight = (fillHeight-(borderDistance+borderDistance)-((numOfSubViews-1)*cellDistance))/(numOfSubViews);
246 }
247
248 CGFloat stdWidth = bounds.size.width-(borderDistance+borderDistance);
249
250
251 //change Subviews Frame
252 NSRect actualFrame = bounds;
253 actualFrame.origin.x = borderDistance;
254 actualFrame.origin.y += bounds.size.height-borderDistance;
255 for (i=0; i<numOfSubViews; i++) {
256
257 CGFloat usedHeight = sizesHeight[i];
258 if (usedHeight < 0.0) usedHeight = stdHeight;
259 actualFrame.origin.y -= usedHeight;
260 actualFrame.size.height = usedHeight;
261
262 CGFloat usedWidth = sizesWidth[i];
263 if (usedWidth < 0.0) usedWidth = stdWidth;
264 NSView* subview = [subviewsInOrder objectAtIndex:i];
265 actualFrame.size.width = usedWidth;
266
267 [subview setFrame:actualFrame];
268 actualFrame.origin.y -= cellDistance;
269 }*/
270 }
271
272}
273
274-(void) addLayoutSubview:(NSView*)new_subview {
275 [subviewsInOrder addObject:new_subview];
276 [self addSubview:new_subview];
277 [self layoutSubviews];
278}
279
280#pragma mark Protocoll Methods
281
282- (NSSize) minSize {
283 NSUInteger numOfSubViews = [subviewsInOrder count];
284
285 if (numOfSubViews > 0) {
286
287 NSInteger neededColumns, neededRows;
288 BOOL columnMode = (columns > 0);
289 if (columnMode) {
290 neededColumns = columns;
291 neededRows = numOfSubViews/columns + numOfSubViews%columns;
292 }
293 else {
294 if (rows > 0) {
295 neededColumns = numOfSubViews/rows + numOfSubViews%rows;
296 neededRows = rows;
297 }
298 else {
299 //We choose column mode with one column
300 neededColumns = 1;
301 neededRows = numOfSubViews;
302 }
303 }
304
305
306 CGFloat minWidthNeededForColumn[neededColumns];
307 CGFloat minHeightNeededForRow[neededRows];
308
309 NSUInteger i;
310 for (i=0; i<neededColumns; i++) {
311 minWidthNeededForColumn[i] = 0.0;
312 }
313 for (i=0; i<neededRows; i++) {
314 minHeightNeededForRow[i] = 0.0;
315 }
316
317 NSInteger actualRow, actualColumn;
318
319 for (i=0; i<numOfSubViews; i++) {
320 if (columnMode) {
321 actualRow = i/neededColumns;
322 actualColumn = i%neededColumns;
323 }
324 else {
325 actualRow = i%neededRows;
326 actualColumn = i/neededRows;
327 }
328
329 NSView* subview = [subviewsInOrder objectAtIndex:i];
330 if ([subview conformsToProtocol:@protocol(CocoaGwenGUIProtocol)]) {
331 NSSize minSize = [(<CocoaGwenGUIProtocol>)subview minSize];
332
333 if (minWidthNeededForColumn[actualColumn] < minSize.width)
334 minWidthNeededForColumn[actualColumn] = minSize.width;
335
336 if (minHeightNeededForRow[actualRow] < minSize.height)
337 minHeightNeededForRow[actualRow] = minSize.height;
338 }
339 }
340 CGFloat minNeededWidth = borderDistance+borderDistance+(neededColumns-1)*cellDistance;
341 for (i=0; i<neededColumns; i++) {
342 minNeededWidth += minWidthNeededForColumn[i];
343 }
344 CGFloat minNeededHeight = borderDistance+borderDistance+(neededRows-1)*cellDistance;
345 for (i=0; i<neededRows; i++) {
346 minNeededHeight += minHeightNeededForRow[i];
347 }
348 return NSMakeSize(minNeededWidth, minNeededHeight);
349 }
350 return NSZeroSize;
351}
352
353- (void)setFrame:(NSRect)frameRect {
354 NSSize minSize = [self minSize];
355 if (frameRect.size.height < minSize.height) {
356 frameRect.size.height = minSize.height;
357 }
358 if (frameRect.size.width < minSize.width) {
359 frameRect.size.width = minSize.width;
360 }
361 [super setFrame:frameRect];
362}
363
364@end
#define cellDistance
#define borderDistance
NSMutableArray * subviewsInOrder