gwenhywfar 4.0.3

CocoaGridLayout.m

Go to the documentation of this file.
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