gwenhywfar
4.3.3
|
00001 // 00002 // CocoaGridLayout.m 00003 // 00004 // 00005 // Created by Samuel Strupp on 10.08.10. 00006 // Copyright 2010 Synium Software GmbH. All rights reserved. 00007 // 00008 00009 #ifdef HAVE_CONFIG_H 00010 # include <config.h> 00011 #endif 00012 00013 #import "CocoaGridLayout.h" 00014 #import "CocoaGwenGUIProtocol.h" 00015 00016 00017 @implementation CocoaGridLayout 00018 00019 @synthesize fillX; 00020 @synthesize fillY; 00021 00022 @synthesize columns; 00023 @synthesize rows; 00024 00025 - (id)initWithFrame:(NSRect)frame { 00026 self = [super initWithFrame:frame]; 00027 if (self) { 00028 fillX = NO; 00029 fillY = NO; 00030 subviewsInOrder = [[NSMutableArray alloc] init]; 00031 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(layoutSubviews) name:NSViewFrameDidChangeNotification object:self]; 00032 } 00033 return self; 00034 } 00035 00036 -(void) dealloc { 00037 [[NSNotificationCenter defaultCenter] removeObserver:self]; 00038 [subviewsInOrder release]; 00039 [super dealloc]; 00040 } 00041 00042 /*- (void)drawRect:(NSRect)dirtyRect { 00043 //debug colors 00044 [[NSColor redColor] set]; 00045 NSRectFill(dirtyRect); 00046 }*/ 00047 00048 #define borderDistance 8.0 00049 #define cellDistance 4.0 00050 00051 -(void) layoutSubviews { 00052 NSRect bounds = [self bounds]; 00053 00054 NSUInteger numOfSubViews = [subviewsInOrder count]; 00055 00056 if (numOfSubViews > 0) { 00057 //Prepass to compute the sizes 00058 BOOL columnMode = (columns > 0); 00059 00060 NSInteger neededColumns, neededRows; 00061 00062 if (columnMode) { 00063 neededColumns = columns; 00064 neededRows = numOfSubViews/columns + numOfSubViews%columns; 00065 } 00066 else { 00067 if (rows > 0) { 00068 neededColumns = numOfSubViews/rows + numOfSubViews%rows; 00069 neededRows = rows; 00070 } 00071 else { 00072 //We choose column mode with one column 00073 neededColumns = 1; 00074 neededRows = numOfSubViews; 00075 } 00076 } 00077 00078 00079 CGFloat minWidthNeededForColumn[neededColumns]; 00080 CGFloat minHeightNeededForRow[neededRows]; 00081 char fillXFlags[neededColumns]; 00082 char fillYFlags[neededRows]; 00083 00084 NSUInteger i; 00085 for (i=0; i<neededColumns; i++) { 00086 minWidthNeededForColumn[i] = 0.0; 00087 fillXFlags[i] = 0; 00088 } 00089 for (i=0; i<neededRows; i++) { 00090 minHeightNeededForRow[i] = 0.0; 00091 fillYFlags[i] = 0; 00092 } 00093 00094 NSInteger actualRow, actualColumn; 00095 00096 for (i=0; i<numOfSubViews; i++) { 00097 if (columnMode) { 00098 actualRow = i/neededColumns; 00099 actualColumn = i%neededColumns; 00100 } 00101 else { 00102 actualRow = i%neededRows; 00103 actualColumn = i/neededRows; 00104 } 00105 00106 NSView* subview = [subviewsInOrder objectAtIndex:i]; 00107 if ([subview conformsToProtocol:@protocol(CocoaGwenGUIProtocol)]) { 00108 NSSize minSize = [(<CocoaGwenGUIProtocol>)subview minSize]; 00109 00110 if (minWidthNeededForColumn[actualColumn] < minSize.width) 00111 minWidthNeededForColumn[actualColumn] = minSize.width; 00112 00113 if (minHeightNeededForRow[actualRow] < minSize.height) 00114 minHeightNeededForRow[actualRow] = minSize.height; 00115 00116 if ([(<CocoaGwenGUIProtocol>)subview fillX]) fillXFlags[actualColumn] = 1; 00117 if ([(<CocoaGwenGUIProtocol>)subview fillY]) fillYFlags[actualRow] = 1; 00118 00119 } 00120 } 00121 00122 00123 //compute exact sizes 00124 CGFloat maxWidth = bounds.size.width-borderDistance-borderDistance-(neededColumns-1)*cellDistance; 00125 NSInteger flexibleCells = 0; 00126 for(i=0; i<neededColumns; i++) { 00127 if (fillXFlags[i] == 1) flexibleCells++; 00128 else maxWidth -= minWidthNeededForColumn[i]; 00129 } 00130 if (maxWidth > 0.0 && flexibleCells > 0) { 00131 CGFloat flexibleStdWidth = maxWidth/flexibleCells; 00132 for (i=0; i<neededColumns; i++) { 00133 if (fillXFlags[i] == 1) minWidthNeededForColumn[i] = flexibleStdWidth; 00134 } 00135 } 00136 00137 CGFloat maxHeight = bounds.size.height-borderDistance-borderDistance-(neededRows-1)*cellDistance; 00138 flexibleCells = 0; 00139 for(i=0; i<neededRows; i++) { 00140 if (fillYFlags[i] == 1) flexibleCells++; 00141 else maxHeight -= minHeightNeededForRow[i]; 00142 } 00143 if (maxHeight > 0.0 && flexibleCells > 0) { 00144 CGFloat flexibleStdHeight = maxHeight/flexibleCells; 00145 for (i=0; i<neededRows; i++) { 00146 if (fillYFlags[i] == 1) minHeightNeededForRow[i] = flexibleStdHeight; 00147 } 00148 } 00149 00150 00151 00152 00153 //Set the sizes to the view 00154 NSRect actualFrame = bounds; 00155 actualFrame.origin.x = borderDistance; 00156 actualFrame.origin.y += bounds.size.height-borderDistance; 00157 00158 00159 NSInteger oldIndex = -1; 00160 00161 for (i=0; i<numOfSubViews; i++) { 00162 if (columnMode) { 00163 actualRow = i/neededColumns; 00164 actualColumn = i%neededColumns; 00165 00166 if (oldIndex != actualRow) { 00167 actualFrame.origin.x = borderDistance; 00168 actualFrame.origin.y -= minHeightNeededForRow[actualRow]+cellDistance; 00169 oldIndex = actualRow; 00170 } 00171 } 00172 else { 00173 actualRow = i%neededRows; 00174 actualColumn = i/neededRows; 00175 00176 if (oldIndex != actualColumn) { 00177 if (oldIndex >= 0) actualFrame.origin.x += minWidthNeededForColumn[oldIndex]+cellDistance; 00178 actualFrame.origin.y = bounds.origin.y+bounds.size.height-borderDistance-minHeightNeededForRow[actualRow]; 00179 oldIndex = actualColumn; 00180 } 00181 } 00182 00183 NSView* subview = [subviewsInOrder objectAtIndex:i]; 00184 00185 actualFrame.size.height = minHeightNeededForRow[actualRow]; 00186 actualFrame.size.width = minWidthNeededForColumn[actualColumn]; 00187 NSRect realFrame = actualFrame; 00188 if ([subview conformsToProtocol:@protocol(CocoaGwenGUIProtocol)]) { 00189 BOOL flexWidth = [(<CocoaGwenGUIProtocol>)subview fillX]; 00190 BOOL flexHeight = [(<CocoaGwenGUIProtocol>)subview fillY]; 00191 if (!flexWidth || !flexHeight) { 00192 NSSize minSize = [(<CocoaGwenGUIProtocol>)subview minSize]; 00193 if (!flexWidth && minSize.width < realFrame.size.width) realFrame.size.width = minSize.width; 00194 if (!flexHeight && minSize.height < realFrame.size.height) { 00195 realFrame.origin.y += realFrame.size.height-minSize.height; 00196 realFrame.size.height = minSize.height; 00197 } 00198 } 00199 } 00200 [subview setFrame:realFrame]; 00201 //NSLog(@"frame = %@", NSStringFromRect(actualFrame)); 00202 00203 if (columnMode) actualFrame.origin.x += actualFrame.size.width+cellDistance; 00204 else if (actualRow+1 < neededRows) actualFrame.origin.y -= minHeightNeededForRow[actualRow+1]+cellDistance; 00205 } 00206 00207 /*CGFloat sizesHeight[numOfSubViews]; 00208 CGFloat sizesWidth[numOfSubViews]; 00209 CGFloat exclusiveHeight = 0.0; 00210 NSUInteger exclusiveChilds = 0; 00211 00212 NSUInteger i; 00213 for (i=0; i<numOfSubViews; i++) { 00214 NSView* subview = [subviewsInOrder objectAtIndex:i]; 00215 if ([subview conformsToProtocol:@protocol(CocoaGwenGUIProtocol)]) { 00216 if ([(<CocoaGwenGUIProtocol>)subview fillX]) sizesWidth[i] = -1.0; 00217 else { 00218 CGFloat neededWidth = [(<CocoaGwenGUIProtocol>)subview minSize].width; 00219 sizesWidth[i] = neededWidth; 00220 } 00221 if ([(<CocoaGwenGUIProtocol>)subview fillY]) sizesHeight[i] = -1.0; 00222 else { 00223 CGFloat neededHeight = [(<CocoaGwenGUIProtocol>)subview minSize].height; 00224 sizesHeight[i] = neededHeight; 00225 exclusiveHeight += neededHeight; 00226 exclusiveChilds++; 00227 } 00228 } 00229 else { 00230 sizesWidth[i] = -1.0; 00231 sizesHeight[i] = -1.0; 00232 } 00233 } 00234 00235 00236 //Compute standard Sizes for Subviews 00237 00238 CGFloat stdHeight = 0.0; 00239 if (numOfSubViews > exclusiveChilds) { 00240 CGFloat fillHeight = bounds.size.height-exclusiveHeight; 00241 stdHeight = (fillHeight-(borderDistance+borderDistance)-((numOfSubViews-1)*cellDistance))/(numOfSubViews-exclusiveChilds); 00242 } 00243 else { 00244 CGFloat fillHeight = bounds.size.height; 00245 stdHeight = (fillHeight-(borderDistance+borderDistance)-((numOfSubViews-1)*cellDistance))/(numOfSubViews); 00246 } 00247 00248 CGFloat stdWidth = bounds.size.width-(borderDistance+borderDistance); 00249 00250 00251 //change Subviews Frame 00252 NSRect actualFrame = bounds; 00253 actualFrame.origin.x = borderDistance; 00254 actualFrame.origin.y += bounds.size.height-borderDistance; 00255 for (i=0; i<numOfSubViews; i++) { 00256 00257 CGFloat usedHeight = sizesHeight[i]; 00258 if (usedHeight < 0.0) usedHeight = stdHeight; 00259 actualFrame.origin.y -= usedHeight; 00260 actualFrame.size.height = usedHeight; 00261 00262 CGFloat usedWidth = sizesWidth[i]; 00263 if (usedWidth < 0.0) usedWidth = stdWidth; 00264 NSView* subview = [subviewsInOrder objectAtIndex:i]; 00265 actualFrame.size.width = usedWidth; 00266 00267 [subview setFrame:actualFrame]; 00268 actualFrame.origin.y -= cellDistance; 00269 }*/ 00270 } 00271 00272 } 00273 00274 -(void) addLayoutSubview:(NSView*)new_subview { 00275 [subviewsInOrder addObject:new_subview]; 00276 [self addSubview:new_subview]; 00277 [self layoutSubviews]; 00278 } 00279 00280 #pragma mark Protocoll Methods 00281 00282 - (NSSize) minSize { 00283 NSUInteger numOfSubViews = [subviewsInOrder count]; 00284 00285 if (numOfSubViews > 0) { 00286 00287 NSInteger neededColumns, neededRows; 00288 BOOL columnMode = (columns > 0); 00289 if (columnMode) { 00290 neededColumns = columns; 00291 neededRows = numOfSubViews/columns + numOfSubViews%columns; 00292 } 00293 else { 00294 if (rows > 0) { 00295 neededColumns = numOfSubViews/rows + numOfSubViews%rows; 00296 neededRows = rows; 00297 } 00298 else { 00299 //We choose column mode with one column 00300 neededColumns = 1; 00301 neededRows = numOfSubViews; 00302 } 00303 } 00304 00305 00306 CGFloat minWidthNeededForColumn[neededColumns]; 00307 CGFloat minHeightNeededForRow[neededRows]; 00308 00309 NSUInteger i; 00310 for (i=0; i<neededColumns; i++) { 00311 minWidthNeededForColumn[i] = 0.0; 00312 } 00313 for (i=0; i<neededRows; i++) { 00314 minHeightNeededForRow[i] = 0.0; 00315 } 00316 00317 NSInteger actualRow, actualColumn; 00318 00319 for (i=0; i<numOfSubViews; i++) { 00320 if (columnMode) { 00321 actualRow = i/neededColumns; 00322 actualColumn = i%neededColumns; 00323 } 00324 else { 00325 actualRow = i%neededRows; 00326 actualColumn = i/neededRows; 00327 } 00328 00329 NSView* subview = [subviewsInOrder objectAtIndex:i]; 00330 if ([subview conformsToProtocol:@protocol(CocoaGwenGUIProtocol)]) { 00331 NSSize minSize = [(<CocoaGwenGUIProtocol>)subview minSize]; 00332 00333 if (minWidthNeededForColumn[actualColumn] < minSize.width) 00334 minWidthNeededForColumn[actualColumn] = minSize.width; 00335 00336 if (minHeightNeededForRow[actualRow] < minSize.height) 00337 minHeightNeededForRow[actualRow] = minSize.height; 00338 } 00339 } 00340 CGFloat minNeededWidth = borderDistance+borderDistance+(neededColumns-1)*cellDistance; 00341 for (i=0; i<neededColumns; i++) { 00342 minNeededWidth += minWidthNeededForColumn[i]; 00343 } 00344 CGFloat minNeededHeight = borderDistance+borderDistance+(neededRows-1)*cellDistance; 00345 for (i=0; i<neededRows; i++) { 00346 minNeededHeight += minHeightNeededForRow[i]; 00347 } 00348 return NSMakeSize(minNeededWidth, minNeededHeight); 00349 } 00350 return NSZeroSize; 00351 } 00352 00353 - (void)setFrame:(NSRect)frameRect { 00354 NSSize minSize = [self minSize]; 00355 if (frameRect.size.height < minSize.height) { 00356 frameRect.size.height = minSize.height; 00357 } 00358 if (frameRect.size.width < minSize.width) { 00359 frameRect.size.width = minSize.width; 00360 } 00361 [super setFrame:frameRect]; 00362 } 00363 00364 @end