gwenhywfar  4.7.0beta
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"
14 #import "CocoaGwenGUIProtocol.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