1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: provide two new classes for layout, wxMultiCellSizer and wxMultiCellCanvas
4 // Author: Jonathan Bayer
8 // Copyright: (c) Jonathan Bayer
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // This was inspired by the gbsizer class written by Alex Andruschak
15 #pragma implementation "multicell.h"
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
25 // ----------------------------------------------------------------------------
27 // ----------------------------------------------------------------------------
33 #include "wx/gizmos/multicell.h"
38 //---------------------------------------------------------------------------
40 IMPLEMENT_ABSTRACT_CLASS(wxMultiCellSizer
, wxSizer
);
41 IMPLEMENT_ABSTRACT_CLASS(wxMultiCellItemHandle
, wxObject
);
43 //---------------------------------------------------------------------------
44 // wxMultiCellItemHandle
45 //---------------------------------------------------------------------------
47 *Function Name: wxMultiCellItemHandle :: wxMultiCellItemHandle
58 *Description: This is the constructor for the class.
62 void wxMultiCellItemHandle :: Initialize( int row
, int column
, int height
, int width
, wxSize size
, wxResizable Style
, wxSize weight
, int align
)
74 //---------------------------------------------------------------------------
75 wxMultiCellItemHandle :: wxMultiCellItemHandle( int row
, int column
, int height
, int width
, wxSize size
, wxResizable Style
, wxSize weight
, int align
)
77 Initialize(row
, column
,height
, width
, size
, Style
, weight
, align
);
79 //---------------------------------------------------------------------------
80 wxMultiCellItemHandle :: wxMultiCellItemHandle( int row
, int column
, wxSize size
, wxResizable style
, wxSize weight
, int align
)
82 Initialize(row
, column
,1, 1, size
, style
, weight
, align
);
84 //---------------------------------------------------------------------------
85 wxMultiCellItemHandle :: wxMultiCellItemHandle( int row
, int column
, wxResizable style
, wxSize weight
, int align
)
87 Initialize(row
, column
, 1, 1, wxSize(1, 1), style
, weight
, align
);
89 //---------------------------------------------------------------------------
90 wxMultiCellItemHandle :: wxMultiCellItemHandle( int row
, int column
, int align
)
92 Initialize(row
, column
, 1, 1, wxSize(1,1), wxNOT_RESIZABLE
, wxSize(1, 1), align
);
95 //---------------------------------------------------------------------------
96 int wxMultiCellItemHandle::GetColumn()
100 //---------------------------------------------------------------------------
101 int wxMultiCellItemHandle::GetRow()
105 //---------------------------------------------------------------------------
106 int wxMultiCellItemHandle::GetWidth()
110 //---------------------------------------------------------------------------
111 int wxMultiCellItemHandle::GetHeight()
115 //---------------------------------------------------------------------------
116 wxResizable
wxMultiCellItemHandle :: GetStyle()
120 //---------------------------------------------------------------------------
121 wxSize
wxMultiCellItemHandle :: GetLocalSize()
125 //---------------------------------------------------------------------------
126 int wxMultiCellItemHandle :: GetAlignment()
130 //---------------------------------------------------------------------------
131 wxSize
wxMultiCellItemHandle :: GetWeight()
138 //---------------------------------------------------------------------------
140 //---------------------------------------------------------------------------
142 //---------------------------------------------------------------------------
145 *Function Name: wxMultiCellSizer::Initialize
147 *Parameters: wxsize Initial size of sizer
149 *Description: This is a common function to initialize all the members of
150 * this class. It is only called from the constructors
154 void wxMultiCellSizer::Initialize( wxSize size
)
157 m_maxHeight
= (int *)malloc((1 + m_cell_count
.GetHeight()) * sizeof(int));
158 m_maxWidth
= (int *)malloc( (1 + m_cell_count
.GetWidth()) * sizeof(int));
159 m_rowStretch
= (int *)malloc( (1 + m_cell_count
.GetHeight()) * sizeof(int));
160 m_colStretch
= (int *)malloc((1 + m_cell_count
.GetWidth()) * sizeof(int));
162 m_weights
= (wxSize
**)malloc((1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
163 m_minSizes
= (wxSize
**)malloc((1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
164 for (int x
= 0; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
166 m_weights
[x
] = new wxSize(0,0);
167 m_minSizes
[x
] = new wxSize(0,0);
170 m_maxWeights
= 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth());
171 m_defaultCellSize
= wxSize(5, 5);
175 //---------------------------------------------------------------------------
176 wxMultiCellSizer::wxMultiCellSizer( wxSize
& size
)
180 //---------------------------------------------------------------------------
181 wxMultiCellSizer::wxMultiCellSizer( int rows
, int cols
)
183 wxSize
size(cols
, rows
);
186 //---------------------------------------------------------------------------
187 wxMultiCellSizer::~wxMultiCellSizer()
189 m_children
.DeleteContents(TRUE
);
196 for (int x
= 0; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
199 delete m_minSizes
[x
];
204 //---------------------------------------------------------------------------
205 bool wxMultiCellSizer::EnableGridLines(wxWindow
*win
)
210 //---------------------------------------------------------------------------
211 bool wxMultiCellSizer::SetGridPen(wxPen
*pen
)
217 //---------------------------------------------------------------------------
218 bool wxMultiCellSizer::SetDefaultCellSize(wxSize size
)
220 m_defaultCellSize
= size
;
223 //---------------------------------------------------------------------------
224 bool wxMultiCellSizer::SetColumnWidth(int column
, int colSize
, bool expandable
)
228 m_minSizes
[column
]->SetWidth(-colSize
);
232 m_minSizes
[column
]->SetWidth(colSize
);
236 //---------------------------------------------------------------------------
237 bool wxMultiCellSizer::SetRowHeight(int row
, int rowSize
, bool expandable
)
241 m_minSizes
[row
]->SetHeight(-rowSize
);
245 m_minSizes
[row
]->SetHeight(rowSize
);
249 //---------------------------------------------------------------------------
250 void wxMultiCellSizer::RecalcSizes()
252 if (m_children
.GetCount() == 0)
254 wxSize size
= GetSize();
255 wxPoint pos
= GetPosition();
259 // We need to take the unused space and equally give it out to all the rows/columns
260 // which are stretchable
262 int unUsedWidth
= size
.GetWidth() - Sum(m_maxWidth
, m_cell_count
.GetWidth());
263 int unUsedHeight
= size
.GetHeight() - Sum(m_maxHeight
, m_cell_count
.GetHeight());
264 int totalWidthWeight
= 0;
265 int totalHeightWeight
= 0;
268 for (x
= 0; x
< wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
272 totalHeightWeight
+= m_weights
[x
]->GetHeight();
274 if (x
< m_cell_count
.GetWidth() && m_colStretch
[x
])
276 totalWidthWeight
+= m_weights
[x
]->GetWidth();
279 for (x
= 0; x
< wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
281 if (x
< m_cell_count
.GetHeight() && m_rowStretch
[x
])
283 m_maxHeight
[x
] += unUsedHeight
* m_weights
[x
]->GetHeight() / totalHeightWeight
;
285 if (x
< m_cell_count
.GetWidth() && m_colStretch
[x
])
287 m_maxWidth
[x
] += unUsedWidth
* m_weights
[x
]->GetWidth() / totalWidthWeight
;
290 // We now have everything we need to figure each cell position and size
291 // The arrays m_maxHeight and m_maxWidth now contain the final widths and height of
292 // each row and column.
294 double cell_width
= (double)size
.GetWidth() / (double)m_cell_count
.GetWidth();
295 double cell_height
= (double)size
.GetHeight() / (double)m_cell_count
.GetHeight();
300 current
= m_children
.GetFirst();
301 while (current
!= NULL
)
303 wxSizerItem
*item
= (wxSizerItem
*) current
->Data();
305 wxMultiCellItemHandle
*rect
;
307 (rect
= (wxMultiCellItemHandle
*)item
->GetUserData()) != NULL
)
309 c_point
.x
= pos
.x
+ (int)(rect
->GetColumn() * cell_width
);
310 c_point
.y
= pos
.y
+ (int)(rect
->GetRow() * cell_height
);
312 c_point
.x
= pos
.x
+ Sum(m_maxWidth
, rect
->GetColumn());
313 c_point
.y
= pos
.y
+ Sum(m_maxHeight
, rect
->GetRow());
316 c_size
= rect
->GetLocalSize();
317 wxSize
minSize( item
->CalcMin() );
318 if (c_size
.GetHeight() != wxDefaultSize
.GetHeight() ||
319 c_size
.GetWidth() != wxDefaultSize
.GetWidth())
321 minSize
.SetHeight(wxMax(minSize
.GetHeight(), c_size
.GetHeight()));
322 minSize
.SetWidth(wxMax(minSize
.GetWidth(), c_size
.GetWidth()));
324 if (rect
->GetStyle() & wxHORIZONTAL_RESIZABLE
||
326 || m_minSizes
[rect
->GetColumn()]->GetWidth() < 0)
329 for (int x
= 0; x
< rect
->GetWidth(); x
++)
331 w
+= m_maxWidth
[rect
->GetColumn() + x
];
337 c_size
.SetWidth(minSize
.GetWidth() );
339 if (rect
->GetStyle() & wxVERTICAL_RESIZABLE
||
340 rect
->GetHeight() > 1 ||
341 m_minSizes
[rect
->GetRow()]->GetHeight() < 0)
344 for (int x
= 0; x
< rect
->GetHeight(); x
++)
346 h
+= m_maxHeight
[rect
->GetRow() + x
];
352 c_size
.SetHeight(minSize
.GetHeight());
354 int extraHeight
= (m_maxHeight
[rect
->GetRow()] - c_size
.GetHeight());
355 int extraWidth
= (m_maxWidth
[rect
->GetColumn()] - c_size
.GetWidth());
357 if (rect
->GetWidth() == 1 && rect
->GetAlignment() & wxALIGN_CENTER_HORIZONTAL
)
359 c_point
.x
+= extraWidth
/ 2;
361 if (rect
->GetWidth() == 1 && rect
->GetAlignment() & wxALIGN_RIGHT
)
363 c_point
.x
+= extraWidth
;
365 if (rect
->GetHeight() == 1 && rect
->GetAlignment() & wxALIGN_CENTER_VERTICAL
)
367 c_point
.y
+= extraHeight
/ 2;
369 if (rect
->GetHeight() == 1 && rect
->GetAlignment() & wxALIGN_BOTTOM
)
371 c_point
.y
+= extraHeight
;
373 item
->SetDimension(c_point
, c_size
);
375 current
= current
->Next();
378 //---------------------------------------------------------------------------
379 wxSize
wxMultiCellSizer::CalcMin()
381 if (m_children
.GetCount() == 0)
382 return wxSize(10,10);
388 m_minWidth
= Sum(m_maxWidth
, m_cell_count
.GetWidth());
389 m_minHeight
= Sum(m_maxHeight
, m_cell_count
.GetHeight());
390 return wxSize( m_minWidth
, m_minHeight
);
392 //---------------------------------------------------------------------------
393 void wxMultiCellSizer :: GetMinimums()
395 // We first initial all the arrays EXCEPT for the m_minsizes array.
397 memset(m_maxHeight
, 0, sizeof(int) * m_cell_count
.GetHeight());
398 memset(m_maxWidth
, 0, sizeof(int) * m_cell_count
.GetWidth());
399 memset(m_rowStretch
, 0, sizeof(int) * m_cell_count
.GetHeight());
400 memset(m_colStretch
, 0, sizeof(int) * m_cell_count
.GetWidth());
401 for (int x
= 0; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
403 m_weights
[x
]->SetHeight(0);
404 m_weights
[x
]->SetWidth(0);
407 wxNode
*node
= m_children
.GetFirst();
410 wxSizerItem
*item
= (wxSizerItem
*) node
->Data();
411 wxMultiCellItemHandle
*rect
;
413 (rect
= (wxMultiCellItemHandle
*)item
->GetUserData()) != NULL
)
415 int row
= rect
->GetRow();
416 int col
= rect
->GetColumn();
418 // First make sure that the control knows about the max rows and columns
421 if (row
+ 1 > m_cell_count
.GetHeight())
424 m_maxHeight
= (int *)realloc(m_maxHeight
, (1 + row
) * sizeof(int));
425 m_rowStretch
= (int *)realloc(m_rowStretch
, (1 + row
) * sizeof(int));
426 for (int x
= m_cell_count
.GetHeight(); x
< row
+ 1; x
++)
428 m_maxHeight
[x
- 1] = 0;
429 m_rowStretch
[x
- 1] = 0;
431 m_cell_count
.SetHeight(row
+ 1);
433 if (col
+ 1 > m_cell_count
.GetWidth())
436 m_maxWidth
= (int *)realloc(m_maxWidth
, (1 + col
) * sizeof(int));
437 m_colStretch
= (int *)realloc(m_colStretch
, ( 1 + col
) * sizeof(int));
438 for (int x
= m_cell_count
.GetWidth(); x
< col
+ 1; x
++)
440 m_maxWidth
[x
- 1] = 0;
441 m_colStretch
[x
- 1] = 0;
443 m_cell_count
.SetWidth(col
+ 1);
447 m_weights
= (wxSize
**)realloc(m_weights
, (1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
448 m_minSizes
= (wxSize
**)realloc(m_minSizes
, (1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
449 for (int x
= m_maxWeights
; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
451 m_weights
[x
- 1] = new wxSize(0,0);
452 m_minSizes
[x
- 1] = new wxSize(0,0);
454 m_maxWeights
= 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth());
457 // Sum the m_weights for each row/column, but only if they are resizable
459 wxSize
minSize( item
->CalcMin() );
460 wxSize c_size
= rect
->GetLocalSize();
461 if (c_size
.GetHeight() != wxDefaultSize
.GetHeight() ||
462 c_size
.GetWidth() != wxDefaultSize
.GetWidth())
464 minSize
.SetHeight(wxMax(minSize
.GetHeight(), c_size
.GetHeight()));
465 minSize
.SetWidth(wxMax(minSize
.GetWidth(), c_size
.GetWidth()));
468 // For each row, calculate the max height for those fields which are not
469 // resizable in the vertical pane
471 if (!(rect
->GetStyle() & wxVERTICAL_RESIZABLE
|| m_minSizes
[row
]->GetHeight() < 0))
473 m_maxHeight
[row
] = wxMax(m_maxHeight
[row
], minSize
.GetHeight() / rect
->GetHeight());
477 m_rowStretch
[row
] = 1;
478 if (m_minSizes
[row
]->GetHeight())
480 m_maxHeight
[row
] = abs(m_minSizes
[row
]->GetHeight());
484 m_maxHeight
[row
] = wxMax(m_maxHeight
[row
], m_defaultCellSize
.GetHeight());
486 m_weights
[row
]->SetHeight(wxMax(m_weights
[row
]->GetHeight(), rect
->GetWeight().GetHeight()));
489 // For each column, calculate the max width for those fields which are not
490 // resizable in the horizontal pane
492 if (!(rect
->GetStyle() & wxHORIZONTAL_RESIZABLE
|| m_minSizes
[col
]->GetWidth() < 0))
494 if (m_minSizes
[col
]->GetWidth())
496 m_maxWidth
[col
] = abs(m_minSizes
[col
]->GetWidth());
500 m_maxWidth
[col
] = wxMax(m_maxWidth
[col
], minSize
.GetWidth() / rect
->GetWidth());
505 m_colStretch
[col
] = 1;
506 m_maxWidth
[col
] = wxMax(m_maxWidth
[col
], m_defaultCellSize
.GetWidth());
507 m_weights
[col
]->SetWidth(wxMax(m_weights
[col
]->GetWidth(), rect
->GetWeight().GetWidth()));
512 } // wxMultiCellSizer :: GetMinimums
513 //---------------------------------------------------------------------------
515 *Function Name: wxMultiCellSizer :: Sum
517 *Parameters: int * pointer to array of ints
518 * int Number of cells to sum up
520 *Description: This member function sums up all the elements of the array which
521 * preceed the specified cell.
527 int wxMultiCellSizer :: Sum(int *array
, int x
)
536 //---------------------------------------------------------------------------
538 *Function Name: wxMultiCellSizer :: DrawGridLines
540 *Parameters: wxDC Device context
542 *Description: This function draws the grid lines in the specified device context.
546 void wxMultiCellSizer :: DrawGridLines(wxDC
& dc
)
549 int maxW
= Sum(m_maxWidth
, m_cell_count
.GetWidth());
550 int maxH
= Sum(m_maxHeight
, m_cell_count
.GetHeight());
555 for (x
= 1; x
< m_cell_count
.GetWidth(); x
++)
557 int colPos
= Sum(m_maxWidth
, x
) ;
558 dc
.DrawLine(colPos
, 0, colPos
, maxH
);
562 for (x
= 1; x
< m_cell_count
.GetHeight(); x
++)
564 int rowPos
= Sum(m_maxHeight
, x
);
565 dc
.DrawLine(0, rowPos
, maxW
, rowPos
);
568 //---------------------------------------------------------------------------
569 // Define the repainting behaviour
571 *Function Name: wxMultiCellSizer::OnPaint
573 *Parameters: wxDC Device context
575 *Description: This function calls the DrawGridLines() member if a window
576 * has been previously specified. This functions MUST be called
577 * from an OnPaint member belonging to the window which the sizer
582 void wxMultiCellSizer::OnPaint(wxDC
& dc
)
591 //---------------------------------------------------------------------------
592 //---------------------------------------------------------------------------
597 #define CELL_LOC(row, col) ((row) * m_maxCols + col)
599 //---------------------------------------------------------------------------
601 //---------------------------------------------------------------------------
603 *Function Name: wxCell : wxLayoutConstraints
605 *Description: This class is used by wxMultiCellCanvas for internal storage
609 class wxCell
: public wxLayoutConstraints
612 wxCell(wxWindow
*win
)
622 //---------------------------------------------------------------------------
624 //---------------------------------------------------------------------------
625 wxMultiCellCanvas :: wxMultiCellCanvas(wxWindow
*par
, int numRows
, int numCols
)
626 : wxFlexGridSizer(numRows
, numCols
, 0, 0)
628 m_cells
= (wxCell
**)calloc(numRows
* numCols
, sizeof(wxCell
*));
633 m_minCellSize
= wxSize(5, 5);
635 //---------------------------------------------------------------------------
639 sprintf(bfr
, "%d", x
);
642 //---------------------------------------------------------------------------
643 void wxMultiCellCanvas :: Add(wxWindow
*win
, unsigned int row
, unsigned int col
)
645 wxASSERT_MSG(row
>= 0 && row
< m_maxRows
, wxString("Row ") + itoa(row
) + " out of bounds (" + itoa(m_maxRows
) + ")");
646 wxASSERT_MSG(col
>= 0 && col
< m_maxCols
, wxString("Column ") + itoa(col
) + " out of bounds (" + itoa(m_maxCols
) + ")");
647 wxASSERT_MSG(m_cells
[CELL_LOC(row
, col
)] == NULL
, wxT("Cell already occupied"));
649 wxCell
*newCell
= new wxCell(win
);
650 m_cells
[CELL_LOC(row
,col
)] = newCell
;
652 //---------------------------------------------------------------------------
653 void wxMultiCellCanvas :: CalculateConstraints()
655 unsigned int row
, col
;
656 for (row
= 0; row
< m_maxRows
; row
++)
658 for (col
= 0; col
< m_maxCols
; col
++)
660 if (!m_cells
[CELL_LOC(row
, col
)])
662 // Create an empty static text field as a placeholder
663 m_cells
[CELL_LOC(row
, col
)] = new wxCell(new wxStaticText(m_parent
, -1, ""));
665 wxFlexGridSizer::Add(m_cells
[CELL_LOC(row
, col
)]->m_window
);
670 /*** End of File ***/