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
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
21 // ----------------------------------------------------------------------------
23 // ----------------------------------------------------------------------------
29 #include "wx/gizmos/multicell.h"
34 //---------------------------------------------------------------------------
36 IMPLEMENT_ABSTRACT_CLASS(wxMultiCellSizer
, wxSizer
);
37 IMPLEMENT_ABSTRACT_CLASS(wxMultiCellItemHandle
, wxObject
);
39 //---------------------------------------------------------------------------
40 // wxMultiCellItemHandle
41 //---------------------------------------------------------------------------
43 *Function Name: wxMultiCellItemHandle :: wxMultiCellItemHandle
54 *Description: This is the constructor for the class.
58 void wxMultiCellItemHandle :: Initialize( int row
, int column
, int height
, int width
, wxSize size
, wxResizable Style
, wxSize weight
, int align
)
70 //---------------------------------------------------------------------------
71 wxMultiCellItemHandle :: wxMultiCellItemHandle( int row
, int column
, int height
, int width
, wxSize size
, wxResizable Style
, wxSize weight
, int align
)
73 Initialize(row
, column
,height
, width
, size
, Style
, weight
, align
);
75 //---------------------------------------------------------------------------
76 wxMultiCellItemHandle :: wxMultiCellItemHandle( int row
, int column
, wxSize size
, wxResizable style
, wxSize weight
, int align
)
78 Initialize(row
, column
,1, 1, size
, style
, weight
, align
);
80 //---------------------------------------------------------------------------
81 wxMultiCellItemHandle :: wxMultiCellItemHandle( int row
, int column
, wxResizable style
, wxSize weight
, int align
)
83 Initialize(row
, column
, 1, 1, wxSize(1, 1), style
, weight
, align
);
85 //---------------------------------------------------------------------------
86 int wxMultiCellItemHandle::GetColumn()
90 //---------------------------------------------------------------------------
91 int wxMultiCellItemHandle::GetRow()
95 //---------------------------------------------------------------------------
96 int wxMultiCellItemHandle::GetWidth()
100 //---------------------------------------------------------------------------
101 int wxMultiCellItemHandle::GetHeight()
105 //---------------------------------------------------------------------------
106 wxResizable
wxMultiCellItemHandle :: GetStyle()
110 //---------------------------------------------------------------------------
111 wxSize
wxMultiCellItemHandle :: GetLocalSize()
115 //---------------------------------------------------------------------------
116 int wxMultiCellItemHandle :: GetAlignment()
120 //---------------------------------------------------------------------------
121 wxSize
wxMultiCellItemHandle :: GetWeight()
128 //---------------------------------------------------------------------------
130 //---------------------------------------------------------------------------
132 //---------------------------------------------------------------------------
135 *Function Name: wxMultiCellSizer::Initialize
137 *Parameters: wxsize Initial size of sizer
139 *Description: This is a common function to initialize all the members of
140 * this class. It is only called from the constructors
144 void wxMultiCellSizer::Initialize( wxSize size
)
147 m_maxHeight
= (int *)malloc((1 + m_cell_count
.GetHeight()) * sizeof(int));
148 m_maxWidth
= (int *)malloc( (1 + m_cell_count
.GetWidth()) * sizeof(int));
149 m_rowStretch
= (int *)malloc( (1 + m_cell_count
.GetHeight()) * sizeof(int));
150 m_colStretch
= (int *)malloc((1 + m_cell_count
.GetWidth()) * sizeof(int));
152 m_weights
= (wxSize
**)malloc((1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
153 m_minSizes
= (wxSize
**)malloc((1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
154 for (int x
= 0; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
156 m_weights
[x
] = new wxSize(0,0);
157 m_minSizes
[x
] = new wxSize(0,0);
160 m_maxWeights
= 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth());
161 m_defaultCellSize
= wxSize(5, 5);
165 //---------------------------------------------------------------------------
166 wxMultiCellSizer::wxMultiCellSizer( wxSize
& size
)
170 //---------------------------------------------------------------------------
171 wxMultiCellSizer::wxMultiCellSizer( int rows
, int cols
)
173 wxSize
size(cols
, rows
);
176 //---------------------------------------------------------------------------
177 wxMultiCellSizer::~wxMultiCellSizer()
179 WX_CLEAR_LIST(wxSizerItemList
, m_children
);
186 for (int x
= 0; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
189 delete m_minSizes
[x
];
194 //---------------------------------------------------------------------------
195 bool wxMultiCellSizer::EnableGridLines(wxWindow
*win
)
200 //---------------------------------------------------------------------------
201 bool wxMultiCellSizer::SetGridPen(wxPen
*pen
)
207 //---------------------------------------------------------------------------
208 bool wxMultiCellSizer::SetDefaultCellSize(wxSize size
)
210 m_defaultCellSize
= size
;
213 //---------------------------------------------------------------------------
214 bool wxMultiCellSizer::SetColumnWidth(int column
, int colSize
, bool expandable
)
218 m_minSizes
[column
]->SetWidth(-colSize
);
222 m_minSizes
[column
]->SetWidth(colSize
);
226 //---------------------------------------------------------------------------
227 bool wxMultiCellSizer::SetRowHeight(int row
, int rowSize
, bool expandable
)
231 m_minSizes
[row
]->SetHeight(-rowSize
);
235 m_minSizes
[row
]->SetHeight(rowSize
);
239 //---------------------------------------------------------------------------
240 void wxMultiCellSizer::RecalcSizes()
242 if (m_children
.GetCount() == 0)
244 wxSize size
= GetSize();
245 wxPoint pos
= GetPosition();
249 // We need to take the unused space and equally give it out to all the rows/columns
250 // which are stretchable
252 int unUsedWidth
= size
.GetWidth() - Sum(m_maxWidth
, m_cell_count
.GetWidth());
253 int unUsedHeight
= size
.GetHeight() - Sum(m_maxHeight
, m_cell_count
.GetHeight());
254 int totalWidthWeight
= 0;
255 int totalHeightWeight
= 0;
258 for (x
= 0; x
< wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
262 totalHeightWeight
+= m_weights
[x
]->GetHeight();
264 if (x
< m_cell_count
.GetWidth() && m_colStretch
[x
])
266 totalWidthWeight
+= m_weights
[x
]->GetWidth();
269 for (x
= 0; x
< wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
271 if (x
< m_cell_count
.GetHeight() && m_rowStretch
[x
])
273 m_maxHeight
[x
] += unUsedHeight
* m_weights
[x
]->GetHeight() / totalHeightWeight
;
275 if (x
< m_cell_count
.GetWidth() && m_colStretch
[x
])
277 m_maxWidth
[x
] += unUsedWidth
* m_weights
[x
]->GetWidth() / totalWidthWeight
;
280 // We now have everything we need to figure each cell position and size
281 // The arrays m_maxHeight and m_maxWidth now contain the final widths and height of
282 // each row and column.
284 double cell_width
= (double)size
.GetWidth() / (double)m_cell_count
.GetWidth();
285 double cell_height
= (double)size
.GetHeight() / (double)m_cell_count
.GetHeight();
289 wxSizerItemList::compatibility_iterator current
= m_children
.GetFirst();
292 wxSizerItem
*item
= current
->GetData();
294 wxMultiCellItemHandle
*rect
;
296 (rect
= (wxMultiCellItemHandle
*)item
->GetUserData()) != NULL
)
298 c_point
.x
= pos
.x
+ (int)(rect
->GetColumn() * cell_width
);
299 c_point
.y
= pos
.y
+ (int)(rect
->GetRow() * cell_height
);
301 c_point
.x
= pos
.x
+ Sum(m_maxWidth
, rect
->GetColumn());
302 c_point
.y
= pos
.y
+ Sum(m_maxHeight
, rect
->GetRow());
305 c_size
= rect
->GetLocalSize();
306 wxSize
minSize( item
->CalcMin() );
307 if (c_size
.GetHeight() != wxDefaultCoord
||
308 c_size
.GetWidth() != wxDefaultCoord
)
310 minSize
.SetHeight(wxMax(minSize
.GetHeight(), c_size
.GetHeight()));
311 minSize
.SetWidth(wxMax(minSize
.GetWidth(), c_size
.GetWidth()));
313 if (rect
->GetStyle() & wxHORIZONTAL_RESIZABLE
||
315 || m_minSizes
[rect
->GetColumn()]->GetWidth() < 0)
318 for (int x
= 0; x
< rect
->GetWidth(); x
++)
320 w
+= m_maxWidth
[rect
->GetColumn() + x
];
326 c_size
.SetWidth(minSize
.GetWidth() );
328 if (rect
->GetStyle() & wxVERTICAL_RESIZABLE
||
329 rect
->GetHeight() > 1 ||
330 m_minSizes
[rect
->GetRow()]->GetHeight() < 0)
333 for (int x
= 0; x
< rect
->GetHeight(); x
++)
335 h
+= m_maxHeight
[rect
->GetRow() + x
];
341 c_size
.SetHeight(minSize
.GetHeight());
343 int extraHeight
= (m_maxHeight
[rect
->GetRow()] - c_size
.GetHeight());
344 int extraWidth
= (m_maxWidth
[rect
->GetColumn()] - c_size
.GetWidth());
346 if (rect
->GetWidth() == 1 && rect
->GetAlignment() & wxALIGN_CENTER_HORIZONTAL
)
348 c_point
.x
+= extraWidth
/ 2;
350 if (rect
->GetWidth() == 1 && rect
->GetAlignment() & wxALIGN_RIGHT
)
352 c_point
.x
+= extraWidth
;
354 if (rect
->GetHeight() == 1 && rect
->GetAlignment() & wxALIGN_CENTER_VERTICAL
)
356 c_point
.y
+= extraHeight
/ 2;
358 if (rect
->GetHeight() == 1 && rect
->GetAlignment() & wxALIGN_BOTTOM
)
360 c_point
.y
+= extraHeight
;
362 item
->SetDimension(c_point
, c_size
);
364 current
= current
->GetNext();
367 //---------------------------------------------------------------------------
368 wxSize
wxMultiCellSizer::CalcMin()
370 if (m_children
.GetCount() == 0)
371 return wxSize(10,10);
374 int m_minWidth
= Sum(m_maxWidth
, m_cell_count
.GetWidth());
375 int m_minHeight
= Sum(m_maxHeight
, m_cell_count
.GetHeight());
376 return wxSize( m_minWidth
, m_minHeight
);
378 //---------------------------------------------------------------------------
379 void wxMultiCellSizer :: GetMinimums()
381 // We first initial all the arrays EXCEPT for the m_minsizes array.
383 memset(m_maxHeight
, 0, sizeof(int) * m_cell_count
.GetHeight());
384 memset(m_maxWidth
, 0, sizeof(int) * m_cell_count
.GetWidth());
385 memset(m_rowStretch
, 0, sizeof(int) * m_cell_count
.GetHeight());
386 memset(m_colStretch
, 0, sizeof(int) * m_cell_count
.GetWidth());
387 for (int x
= 0; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
389 m_weights
[x
]->SetHeight(0);
390 m_weights
[x
]->SetWidth(0);
393 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
396 wxSizerItem
*item
= node
->GetData();
397 wxMultiCellItemHandle
*rect
;
399 (rect
= (wxMultiCellItemHandle
*)item
->GetUserData()) != NULL
)
401 int row
= rect
->GetRow();
402 int col
= rect
->GetColumn();
404 // First make sure that the control knows about the max rows and columns
407 if (row
+ 1 > m_cell_count
.GetHeight())
410 m_maxHeight
= (int *)realloc(m_maxHeight
, (1 + row
) * sizeof(int));
411 m_rowStretch
= (int *)realloc(m_rowStretch
, (1 + row
) * sizeof(int));
412 for (int x
= m_cell_count
.GetHeight(); x
< row
+ 1; x
++)
414 m_maxHeight
[x
- 1] = 0;
415 m_rowStretch
[x
- 1] = 0;
417 m_cell_count
.SetHeight(row
+ 1);
419 if (col
+ 1 > m_cell_count
.GetWidth())
422 m_maxWidth
= (int *)realloc(m_maxWidth
, (1 + col
) * sizeof(int));
423 m_colStretch
= (int *)realloc(m_colStretch
, ( 1 + col
) * sizeof(int));
424 for (int x
= m_cell_count
.GetWidth(); x
< col
+ 1; x
++)
426 m_maxWidth
[x
- 1] = 0;
427 m_colStretch
[x
- 1] = 0;
429 m_cell_count
.SetWidth(col
+ 1);
433 m_weights
= (wxSize
**)realloc(m_weights
, (1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
434 m_minSizes
= (wxSize
**)realloc(m_minSizes
, (1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
435 for (int x
= m_maxWeights
; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
437 m_weights
[x
- 1] = new wxSize(0,0);
438 m_minSizes
[x
- 1] = new wxSize(0,0);
440 m_maxWeights
= 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth());
443 // Sum the m_weights for each row/column, but only if they are resizable
445 wxSize
minSize( item
->CalcMin() );
446 wxSize c_size
= rect
->GetLocalSize();
447 if (c_size
.GetHeight() != wxDefaultCoord
||
448 c_size
.GetWidth() != wxDefaultCoord
)
450 minSize
.SetHeight(wxMax(minSize
.GetHeight(), c_size
.GetHeight()));
451 minSize
.SetWidth(wxMax(minSize
.GetWidth(), c_size
.GetWidth()));
454 // For each row, calculate the max height for those fields which are not
455 // resizable in the vertical pane
457 if (!(rect
->GetStyle() & wxVERTICAL_RESIZABLE
|| m_minSizes
[row
]->GetHeight() < 0))
459 m_maxHeight
[row
] = wxMax(m_maxHeight
[row
], minSize
.GetHeight() / rect
->GetHeight());
463 m_rowStretch
[row
] = 1;
464 if (m_minSizes
[row
]->GetHeight())
466 m_maxHeight
[row
] = abs(m_minSizes
[row
]->GetHeight());
470 m_maxHeight
[row
] = wxMax(m_maxHeight
[row
], m_defaultCellSize
.GetHeight());
472 m_weights
[row
]->SetHeight(wxMax(m_weights
[row
]->GetHeight(), rect
->GetWeight().GetHeight()));
475 // For each column, calculate the max width for those fields which are not
476 // resizable in the horizontal pane
478 if (!(rect
->GetStyle() & wxHORIZONTAL_RESIZABLE
|| m_minSizes
[col
]->GetWidth() < 0))
480 if (m_minSizes
[col
]->GetWidth())
482 m_maxWidth
[col
] = abs(m_minSizes
[col
]->GetWidth());
486 m_maxWidth
[col
] = wxMax(m_maxWidth
[col
], minSize
.GetWidth() / rect
->GetWidth());
491 m_colStretch
[col
] = 1;
492 m_maxWidth
[col
] = wxMax(m_maxWidth
[col
], m_defaultCellSize
.GetWidth());
493 m_weights
[col
]->SetWidth(wxMax(m_weights
[col
]->GetWidth(), rect
->GetWeight().GetWidth()));
495 node
= node
->GetNext();
498 } // wxMultiCellSizer :: GetMinimums
499 //---------------------------------------------------------------------------
501 *Function Name: wxMultiCellSizer :: Sum
503 *Parameters: int* pointer to array of ints
504 * int Number of cells to sum up
506 *Description: This member function sums up all the elements of the array which
507 * preceed the specified cell.
513 int wxMultiCellSizer :: Sum(int *array
, int x
)
522 //---------------------------------------------------------------------------
524 *Function Name: wxMultiCellSizer :: DrawGridLines
526 *Parameters: wxDC Device context
528 *Description: This function draws the grid lines in the specified device context.
532 void wxMultiCellSizer :: DrawGridLines(wxDC
& dc
)
535 int maxW
= Sum(m_maxWidth
, m_cell_count
.GetWidth());
536 int maxH
= Sum(m_maxHeight
, m_cell_count
.GetHeight());
541 for (x
= 1; x
< m_cell_count
.GetWidth(); x
++)
543 int colPos
= Sum(m_maxWidth
, x
) ;
544 dc
.DrawLine(colPos
, 0, colPos
, maxH
);
548 for (x
= 1; x
< m_cell_count
.GetHeight(); x
++)
550 int rowPos
= Sum(m_maxHeight
, x
);
551 dc
.DrawLine(0, rowPos
, maxW
, rowPos
);
554 //---------------------------------------------------------------------------
555 // Define the repainting behaviour
557 *Function Name: wxMultiCellSizer::OnPaint
559 *Parameters: wxDC Device context
561 *Description: This function calls the DrawGridLines() member if a window
562 * has been previously specified. This functions MUST be called
563 * from an OnPaint member belonging to the window which the sizer
568 void wxMultiCellSizer::OnPaint(wxDC
& dc
)
577 //---------------------------------------------------------------------------
578 //---------------------------------------------------------------------------
583 #define CELL_LOC(row, col) ((row) * m_maxCols + col)
585 //---------------------------------------------------------------------------
587 //---------------------------------------------------------------------------
589 *Function Name: wxCell : wxLayoutConstraints
591 *Description: This class is used by wxMultiCellCanvas for internal storage
595 class wxCell
: public wxLayoutConstraints
598 wxCell(wxWindow
*win
)
608 //---------------------------------------------------------------------------
610 //---------------------------------------------------------------------------
611 wxMultiCellCanvas :: wxMultiCellCanvas(wxWindow
*par
, int numRows
, int numCols
)
612 : wxFlexGridSizer(numRows
, numCols
, 0, 0)
614 m_cells
= (wxCell
**)calloc(numRows
* numCols
, sizeof(wxCell
*));
619 m_minCellSize
= wxSize(5, 5);
621 //---------------------------------------------------------------------------
622 void wxMultiCellCanvas :: Add(wxWindow
*win
, unsigned int row
, unsigned int col
)
624 // thanks to unsigned data row and col are always >= 0
625 wxASSERT_MSG( /* row >= 0 && */ row
< m_maxRows
,
626 wxString::Format(_T("Row %d out of bounds (0..%d)"), row
, m_maxRows
) );
627 wxASSERT_MSG( /* col >= 0 && */ col
< m_maxCols
,
628 wxString::Format(_T("Column %d out of bounds (0..%d)"), col
, m_maxCols
) );
630 wxASSERT_MSG(m_cells
[CELL_LOC(row
, col
)] == NULL
, wxT("Cell already occupied"));
632 wxCell
*newCell
= new wxCell(win
);
633 m_cells
[CELL_LOC(row
,col
)] = newCell
;
635 //---------------------------------------------------------------------------
636 void wxMultiCellCanvas :: CalculateConstraints()
638 unsigned int row
, col
;
639 for (row
= 0; row
< m_maxRows
; row
++)
641 for (col
= 0; col
< m_maxCols
; col
++)
643 if (!m_cells
[CELL_LOC(row
, col
)])
645 // Create an empty static text field as a placeholder
646 m_cells
[CELL_LOC(row
, col
)] = new wxCell(new wxStaticText(m_parent
, wxID_ANY
, wxEmptyString
));
648 wxFlexGridSizer::Add(m_cells
[CELL_LOC(row
, col
)]->m_window
);
653 /*** End of File ***/