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 int wxMultiCellItemHandle::GetColumn()
94 //---------------------------------------------------------------------------
95 int wxMultiCellItemHandle::GetRow()
99 //---------------------------------------------------------------------------
100 int wxMultiCellItemHandle::GetWidth()
104 //---------------------------------------------------------------------------
105 int wxMultiCellItemHandle::GetHeight()
109 //---------------------------------------------------------------------------
110 wxResizable
wxMultiCellItemHandle :: GetStyle()
114 //---------------------------------------------------------------------------
115 wxSize
wxMultiCellItemHandle :: GetLocalSize()
119 //---------------------------------------------------------------------------
120 int wxMultiCellItemHandle :: GetAlignment()
124 //---------------------------------------------------------------------------
125 wxSize
wxMultiCellItemHandle :: GetWeight()
132 //---------------------------------------------------------------------------
134 //---------------------------------------------------------------------------
136 //---------------------------------------------------------------------------
139 *Function Name: wxMultiCellSizer::Initialize
141 *Parameters: wxsize Initial size of sizer
143 *Description: This is a common function to initialize all the members of
144 * this class. It is only called from the constructors
148 void wxMultiCellSizer::Initialize( wxSize size
)
151 m_maxHeight
= (int *)malloc((1 + m_cell_count
.GetHeight()) * sizeof(int));
152 m_maxWidth
= (int *)malloc( (1 + m_cell_count
.GetWidth()) * sizeof(int));
153 m_rowStretch
= (int *)malloc( (1 + m_cell_count
.GetHeight()) * sizeof(int));
154 m_colStretch
= (int *)malloc((1 + m_cell_count
.GetWidth()) * sizeof(int));
156 m_weights
= (wxSize
**)malloc((1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
157 m_minSizes
= (wxSize
**)malloc((1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
158 for (int x
= 0; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
160 m_weights
[x
] = new wxSize(0,0);
161 m_minSizes
[x
] = new wxSize(0,0);
164 m_maxWeights
= 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth());
165 m_defaultCellSize
= wxSize(5, 5);
169 //---------------------------------------------------------------------------
170 wxMultiCellSizer::wxMultiCellSizer( wxSize
& size
)
174 //---------------------------------------------------------------------------
175 wxMultiCellSizer::wxMultiCellSizer( int rows
, int cols
)
177 wxSize
size(cols
, rows
);
180 //---------------------------------------------------------------------------
181 wxMultiCellSizer::~wxMultiCellSizer()
183 WX_CLEAR_LIST(wxSizerItemList
, m_children
);
190 for (int x
= 0; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
193 delete m_minSizes
[x
];
198 //---------------------------------------------------------------------------
199 bool wxMultiCellSizer::EnableGridLines(wxWindow
*win
)
204 //---------------------------------------------------------------------------
205 bool wxMultiCellSizer::SetGridPen(wxPen
*pen
)
211 //---------------------------------------------------------------------------
212 bool wxMultiCellSizer::SetDefaultCellSize(wxSize size
)
214 m_defaultCellSize
= size
;
217 //---------------------------------------------------------------------------
218 bool wxMultiCellSizer::SetColumnWidth(int column
, int colSize
, bool expandable
)
222 m_minSizes
[column
]->SetWidth(-colSize
);
226 m_minSizes
[column
]->SetWidth(colSize
);
230 //---------------------------------------------------------------------------
231 bool wxMultiCellSizer::SetRowHeight(int row
, int rowSize
, bool expandable
)
235 m_minSizes
[row
]->SetHeight(-rowSize
);
239 m_minSizes
[row
]->SetHeight(rowSize
);
243 //---------------------------------------------------------------------------
244 void wxMultiCellSizer::RecalcSizes()
246 if (m_children
.GetCount() == 0)
248 wxSize size
= GetSize();
249 wxPoint pos
= GetPosition();
253 // We need to take the unused space and equally give it out to all the rows/columns
254 // which are stretchable
256 int unUsedWidth
= size
.GetWidth() - Sum(m_maxWidth
, m_cell_count
.GetWidth());
257 int unUsedHeight
= size
.GetHeight() - Sum(m_maxHeight
, m_cell_count
.GetHeight());
258 int totalWidthWeight
= 0;
259 int totalHeightWeight
= 0;
262 for (x
= 0; x
< wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
266 totalHeightWeight
+= m_weights
[x
]->GetHeight();
268 if (x
< m_cell_count
.GetWidth() && m_colStretch
[x
])
270 totalWidthWeight
+= m_weights
[x
]->GetWidth();
273 for (x
= 0; x
< wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
275 if (x
< m_cell_count
.GetHeight() && m_rowStretch
[x
])
277 m_maxHeight
[x
] += unUsedHeight
* m_weights
[x
]->GetHeight() / totalHeightWeight
;
279 if (x
< m_cell_count
.GetWidth() && m_colStretch
[x
])
281 m_maxWidth
[x
] += unUsedWidth
* m_weights
[x
]->GetWidth() / totalWidthWeight
;
284 // We now have everything we need to figure each cell position and size
285 // The arrays m_maxHeight and m_maxWidth now contain the final widths and height of
286 // each row and column.
288 double cell_width
= (double)size
.GetWidth() / (double)m_cell_count
.GetWidth();
289 double cell_height
= (double)size
.GetHeight() / (double)m_cell_count
.GetHeight();
293 wxSizerItemList::compatibility_iterator current
= m_children
.GetFirst();
296 wxSizerItem
*item
= current
->GetData();
298 wxMultiCellItemHandle
*rect
;
300 (rect
= (wxMultiCellItemHandle
*)item
->GetUserData()) != NULL
)
302 c_point
.x
= pos
.x
+ (int)(rect
->GetColumn() * cell_width
);
303 c_point
.y
= pos
.y
+ (int)(rect
->GetRow() * cell_height
);
305 c_point
.x
= pos
.x
+ Sum(m_maxWidth
, rect
->GetColumn());
306 c_point
.y
= pos
.y
+ Sum(m_maxHeight
, rect
->GetRow());
309 c_size
= rect
->GetLocalSize();
310 wxSize
minSize( item
->CalcMin() );
311 if (c_size
.GetHeight() != wxDefaultCoord
||
312 c_size
.GetWidth() != wxDefaultCoord
)
314 minSize
.SetHeight(wxMax(minSize
.GetHeight(), c_size
.GetHeight()));
315 minSize
.SetWidth(wxMax(minSize
.GetWidth(), c_size
.GetWidth()));
317 if (rect
->GetStyle() & wxHORIZONTAL_RESIZABLE
||
319 || m_minSizes
[rect
->GetColumn()]->GetWidth() < 0)
322 for (int x
= 0; x
< rect
->GetWidth(); x
++)
324 w
+= m_maxWidth
[rect
->GetColumn() + x
];
330 c_size
.SetWidth(minSize
.GetWidth() );
332 if (rect
->GetStyle() & wxVERTICAL_RESIZABLE
||
333 rect
->GetHeight() > 1 ||
334 m_minSizes
[rect
->GetRow()]->GetHeight() < 0)
337 for (int x
= 0; x
< rect
->GetHeight(); x
++)
339 h
+= m_maxHeight
[rect
->GetRow() + x
];
345 c_size
.SetHeight(minSize
.GetHeight());
347 int extraHeight
= (m_maxHeight
[rect
->GetRow()] - c_size
.GetHeight());
348 int extraWidth
= (m_maxWidth
[rect
->GetColumn()] - c_size
.GetWidth());
350 if (rect
->GetWidth() == 1 && rect
->GetAlignment() & wxALIGN_CENTER_HORIZONTAL
)
352 c_point
.x
+= extraWidth
/ 2;
354 if (rect
->GetWidth() == 1 && rect
->GetAlignment() & wxALIGN_RIGHT
)
356 c_point
.x
+= extraWidth
;
358 if (rect
->GetHeight() == 1 && rect
->GetAlignment() & wxALIGN_CENTER_VERTICAL
)
360 c_point
.y
+= extraHeight
/ 2;
362 if (rect
->GetHeight() == 1 && rect
->GetAlignment() & wxALIGN_BOTTOM
)
364 c_point
.y
+= extraHeight
;
366 item
->SetDimension(c_point
, c_size
);
368 current
= current
->GetNext();
371 //---------------------------------------------------------------------------
372 wxSize
wxMultiCellSizer::CalcMin()
374 if (m_children
.GetCount() == 0)
375 return wxSize(10,10);
378 int m_minWidth
= Sum(m_maxWidth
, m_cell_count
.GetWidth());
379 int m_minHeight
= Sum(m_maxHeight
, m_cell_count
.GetHeight());
380 return wxSize( m_minWidth
, m_minHeight
);
382 //---------------------------------------------------------------------------
383 void wxMultiCellSizer :: GetMinimums()
385 // We first initial all the arrays EXCEPT for the m_minsizes array.
387 memset(m_maxHeight
, 0, sizeof(int) * m_cell_count
.GetHeight());
388 memset(m_maxWidth
, 0, sizeof(int) * m_cell_count
.GetWidth());
389 memset(m_rowStretch
, 0, sizeof(int) * m_cell_count
.GetHeight());
390 memset(m_colStretch
, 0, sizeof(int) * m_cell_count
.GetWidth());
391 for (int x
= 0; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
393 m_weights
[x
]->SetHeight(0);
394 m_weights
[x
]->SetWidth(0);
397 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
400 wxSizerItem
*item
= node
->GetData();
401 wxMultiCellItemHandle
*rect
;
403 (rect
= (wxMultiCellItemHandle
*)item
->GetUserData()) != NULL
)
405 int row
= rect
->GetRow();
406 int col
= rect
->GetColumn();
408 // First make sure that the control knows about the max rows and columns
411 if (row
+ 1 > m_cell_count
.GetHeight())
414 m_maxHeight
= (int *)realloc(m_maxHeight
, (1 + row
) * sizeof(int));
415 m_rowStretch
= (int *)realloc(m_rowStretch
, (1 + row
) * sizeof(int));
416 for (int x
= m_cell_count
.GetHeight(); x
< row
+ 1; x
++)
418 m_maxHeight
[x
- 1] = 0;
419 m_rowStretch
[x
- 1] = 0;
421 m_cell_count
.SetHeight(row
+ 1);
423 if (col
+ 1 > m_cell_count
.GetWidth())
426 m_maxWidth
= (int *)realloc(m_maxWidth
, (1 + col
) * sizeof(int));
427 m_colStretch
= (int *)realloc(m_colStretch
, ( 1 + col
) * sizeof(int));
428 for (int x
= m_cell_count
.GetWidth(); x
< col
+ 1; x
++)
430 m_maxWidth
[x
- 1] = 0;
431 m_colStretch
[x
- 1] = 0;
433 m_cell_count
.SetWidth(col
+ 1);
437 m_weights
= (wxSize
**)realloc(m_weights
, (1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
438 m_minSizes
= (wxSize
**)realloc(m_minSizes
, (1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
439 for (int x
= m_maxWeights
; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
441 m_weights
[x
- 1] = new wxSize(0,0);
442 m_minSizes
[x
- 1] = new wxSize(0,0);
444 m_maxWeights
= 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth());
447 // Sum the m_weights for each row/column, but only if they are resizable
449 wxSize
minSize( item
->CalcMin() );
450 wxSize c_size
= rect
->GetLocalSize();
451 if (c_size
.GetHeight() != wxDefaultCoord
||
452 c_size
.GetWidth() != wxDefaultCoord
)
454 minSize
.SetHeight(wxMax(minSize
.GetHeight(), c_size
.GetHeight()));
455 minSize
.SetWidth(wxMax(minSize
.GetWidth(), c_size
.GetWidth()));
458 // For each row, calculate the max height for those fields which are not
459 // resizable in the vertical pane
461 if (!(rect
->GetStyle() & wxVERTICAL_RESIZABLE
|| m_minSizes
[row
]->GetHeight() < 0))
463 m_maxHeight
[row
] = wxMax(m_maxHeight
[row
], minSize
.GetHeight() / rect
->GetHeight());
467 m_rowStretch
[row
] = 1;
468 if (m_minSizes
[row
]->GetHeight())
470 m_maxHeight
[row
] = abs(m_minSizes
[row
]->GetHeight());
474 m_maxHeight
[row
] = wxMax(m_maxHeight
[row
], m_defaultCellSize
.GetHeight());
476 m_weights
[row
]->SetHeight(wxMax(m_weights
[row
]->GetHeight(), rect
->GetWeight().GetHeight()));
479 // For each column, calculate the max width for those fields which are not
480 // resizable in the horizontal pane
482 if (!(rect
->GetStyle() & wxHORIZONTAL_RESIZABLE
|| m_minSizes
[col
]->GetWidth() < 0))
484 if (m_minSizes
[col
]->GetWidth())
486 m_maxWidth
[col
] = abs(m_minSizes
[col
]->GetWidth());
490 m_maxWidth
[col
] = wxMax(m_maxWidth
[col
], minSize
.GetWidth() / rect
->GetWidth());
495 m_colStretch
[col
] = 1;
496 m_maxWidth
[col
] = wxMax(m_maxWidth
[col
], m_defaultCellSize
.GetWidth());
497 m_weights
[col
]->SetWidth(wxMax(m_weights
[col
]->GetWidth(), rect
->GetWeight().GetWidth()));
499 node
= node
->GetNext();
502 } // wxMultiCellSizer :: GetMinimums
503 //---------------------------------------------------------------------------
505 *Function Name: wxMultiCellSizer :: Sum
507 *Parameters: int* pointer to array of ints
508 * int Number of cells to sum up
510 *Description: This member function sums up all the elements of the array which
511 * preceed the specified cell.
517 int wxMultiCellSizer :: Sum(int *array
, int x
)
526 //---------------------------------------------------------------------------
528 *Function Name: wxMultiCellSizer :: DrawGridLines
530 *Parameters: wxDC Device context
532 *Description: This function draws the grid lines in the specified device context.
536 void wxMultiCellSizer :: DrawGridLines(wxDC
& dc
)
539 int maxW
= Sum(m_maxWidth
, m_cell_count
.GetWidth());
540 int maxH
= Sum(m_maxHeight
, m_cell_count
.GetHeight());
545 for (x
= 1; x
< m_cell_count
.GetWidth(); x
++)
547 int colPos
= Sum(m_maxWidth
, x
) ;
548 dc
.DrawLine(colPos
, 0, colPos
, maxH
);
552 for (x
= 1; x
< m_cell_count
.GetHeight(); x
++)
554 int rowPos
= Sum(m_maxHeight
, x
);
555 dc
.DrawLine(0, rowPos
, maxW
, rowPos
);
558 //---------------------------------------------------------------------------
559 // Define the repainting behaviour
561 *Function Name: wxMultiCellSizer::OnPaint
563 *Parameters: wxDC Device context
565 *Description: This function calls the DrawGridLines() member if a window
566 * has been previously specified. This functions MUST be called
567 * from an OnPaint member belonging to the window which the sizer
572 void wxMultiCellSizer::OnPaint(wxDC
& dc
)
581 //---------------------------------------------------------------------------
582 //---------------------------------------------------------------------------
587 #define CELL_LOC(row, col) ((row) * m_maxCols + col)
589 //---------------------------------------------------------------------------
591 //---------------------------------------------------------------------------
593 *Function Name: wxCell : wxLayoutConstraints
595 *Description: This class is used by wxMultiCellCanvas for internal storage
599 class wxCell
: public wxLayoutConstraints
602 wxCell(wxWindow
*win
)
612 //---------------------------------------------------------------------------
614 //---------------------------------------------------------------------------
615 wxMultiCellCanvas :: wxMultiCellCanvas(wxWindow
*par
, int numRows
, int numCols
)
616 : wxFlexGridSizer(numRows
, numCols
, 0, 0)
618 m_cells
= (wxCell
**)calloc(numRows
* numCols
, sizeof(wxCell
*));
623 m_minCellSize
= wxSize(5, 5);
625 //---------------------------------------------------------------------------
626 void wxMultiCellCanvas :: Add(wxWindow
*win
, unsigned int row
, unsigned int col
)
628 // thanks to unsigned data row and col are always >= 0
629 wxASSERT_MSG( /* row >= 0 && */ row
< m_maxRows
,
630 wxString::Format(_T("Row %d out of bounds (0..%d)"), row
, m_maxRows
) );
631 wxASSERT_MSG( /* col >= 0 && */ col
< m_maxCols
,
632 wxString::Format(_T("Column %d out of bounds (0..%d)"), col
, m_maxCols
) );
634 wxASSERT_MSG(m_cells
[CELL_LOC(row
, col
)] == NULL
, wxT("Cell already occupied"));
636 wxCell
*newCell
= new wxCell(win
);
637 m_cells
[CELL_LOC(row
,col
)] = newCell
;
639 //---------------------------------------------------------------------------
640 void wxMultiCellCanvas :: CalculateConstraints()
642 unsigned int row
, col
;
643 for (row
= 0; row
< m_maxRows
; row
++)
645 for (col
= 0; col
< m_maxCols
; col
++)
647 if (!m_cells
[CELL_LOC(row
, col
)])
649 // Create an empty static text field as a placeholder
650 m_cells
[CELL_LOC(row
, col
)] = new wxCell(new wxStaticText(m_parent
, wxID_ANY
, wxEmptyString
));
652 wxFlexGridSizer::Add(m_cells
[CELL_LOC(row
, col
)]->m_window
);
657 /*** End of File ***/