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();
299 wxSizerItemList::Node
*current
= m_children
.GetFirst();
300 while (current
!= NULL
)
302 wxSizerItem
*item
= current
->GetData();
304 wxMultiCellItemHandle
*rect
;
306 (rect
= (wxMultiCellItemHandle
*)item
->GetUserData()) != NULL
)
308 c_point
.x
= pos
.x
+ (int)(rect
->GetColumn() * cell_width
);
309 c_point
.y
= pos
.y
+ (int)(rect
->GetRow() * cell_height
);
311 c_point
.x
= pos
.x
+ Sum(m_maxWidth
, rect
->GetColumn());
312 c_point
.y
= pos
.y
+ Sum(m_maxHeight
, rect
->GetRow());
315 c_size
= rect
->GetLocalSize();
316 wxSize
minSize( item
->CalcMin() );
317 if (c_size
.GetHeight() != wxDefaultSize
.GetHeight() ||
318 c_size
.GetWidth() != wxDefaultSize
.GetWidth())
320 minSize
.SetHeight(wxMax(minSize
.GetHeight(), c_size
.GetHeight()));
321 minSize
.SetWidth(wxMax(minSize
.GetWidth(), c_size
.GetWidth()));
323 if (rect
->GetStyle() & wxHORIZONTAL_RESIZABLE
||
325 || m_minSizes
[rect
->GetColumn()]->GetWidth() < 0)
328 for (int x
= 0; x
< rect
->GetWidth(); x
++)
330 w
+= m_maxWidth
[rect
->GetColumn() + x
];
336 c_size
.SetWidth(minSize
.GetWidth() );
338 if (rect
->GetStyle() & wxVERTICAL_RESIZABLE
||
339 rect
->GetHeight() > 1 ||
340 m_minSizes
[rect
->GetRow()]->GetHeight() < 0)
343 for (int x
= 0; x
< rect
->GetHeight(); x
++)
345 h
+= m_maxHeight
[rect
->GetRow() + x
];
351 c_size
.SetHeight(minSize
.GetHeight());
353 int extraHeight
= (m_maxHeight
[rect
->GetRow()] - c_size
.GetHeight());
354 int extraWidth
= (m_maxWidth
[rect
->GetColumn()] - c_size
.GetWidth());
356 if (rect
->GetWidth() == 1 && rect
->GetAlignment() & wxALIGN_CENTER_HORIZONTAL
)
358 c_point
.x
+= extraWidth
/ 2;
360 if (rect
->GetWidth() == 1 && rect
->GetAlignment() & wxALIGN_RIGHT
)
362 c_point
.x
+= extraWidth
;
364 if (rect
->GetHeight() == 1 && rect
->GetAlignment() & wxALIGN_CENTER_VERTICAL
)
366 c_point
.y
+= extraHeight
/ 2;
368 if (rect
->GetHeight() == 1 && rect
->GetAlignment() & wxALIGN_BOTTOM
)
370 c_point
.y
+= extraHeight
;
372 item
->SetDimension(c_point
, c_size
);
374 current
= current
->GetNext();
377 //---------------------------------------------------------------------------
378 wxSize
wxMultiCellSizer::CalcMin()
380 if (m_children
.GetCount() == 0)
381 return wxSize(10,10);
384 int m_minWidth
= Sum(m_maxWidth
, m_cell_count
.GetWidth());
385 int m_minHeight
= Sum(m_maxHeight
, m_cell_count
.GetHeight());
386 return wxSize( m_minWidth
, m_minHeight
);
388 //---------------------------------------------------------------------------
389 void wxMultiCellSizer :: GetMinimums()
391 // We first initial all the arrays EXCEPT for the m_minsizes array.
393 memset(m_maxHeight
, 0, sizeof(int) * m_cell_count
.GetHeight());
394 memset(m_maxWidth
, 0, sizeof(int) * m_cell_count
.GetWidth());
395 memset(m_rowStretch
, 0, sizeof(int) * m_cell_count
.GetHeight());
396 memset(m_colStretch
, 0, sizeof(int) * m_cell_count
.GetWidth());
397 for (int x
= 0; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
399 m_weights
[x
]->SetHeight(0);
400 m_weights
[x
]->SetWidth(0);
403 wxSizerItemList::Node
*node
= m_children
.GetFirst();
406 wxSizerItem
*item
= node
->GetData();
407 wxMultiCellItemHandle
*rect
;
409 (rect
= (wxMultiCellItemHandle
*)item
->GetUserData()) != NULL
)
411 int row
= rect
->GetRow();
412 int col
= rect
->GetColumn();
414 // First make sure that the control knows about the max rows and columns
417 if (row
+ 1 > m_cell_count
.GetHeight())
420 m_maxHeight
= (int *)realloc(m_maxHeight
, (1 + row
) * sizeof(int));
421 m_rowStretch
= (int *)realloc(m_rowStretch
, (1 + row
) * sizeof(int));
422 for (int x
= m_cell_count
.GetHeight(); x
< row
+ 1; x
++)
424 m_maxHeight
[x
- 1] = 0;
425 m_rowStretch
[x
- 1] = 0;
427 m_cell_count
.SetHeight(row
+ 1);
429 if (col
+ 1 > m_cell_count
.GetWidth())
432 m_maxWidth
= (int *)realloc(m_maxWidth
, (1 + col
) * sizeof(int));
433 m_colStretch
= (int *)realloc(m_colStretch
, ( 1 + col
) * sizeof(int));
434 for (int x
= m_cell_count
.GetWidth(); x
< col
+ 1; x
++)
436 m_maxWidth
[x
- 1] = 0;
437 m_colStretch
[x
- 1] = 0;
439 m_cell_count
.SetWidth(col
+ 1);
443 m_weights
= (wxSize
**)realloc(m_weights
, (1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
444 m_minSizes
= (wxSize
**)realloc(m_minSizes
, (1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
445 for (int x
= m_maxWeights
; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
447 m_weights
[x
- 1] = new wxSize(0,0);
448 m_minSizes
[x
- 1] = new wxSize(0,0);
450 m_maxWeights
= 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth());
453 // Sum the m_weights for each row/column, but only if they are resizable
455 wxSize
minSize( item
->CalcMin() );
456 wxSize c_size
= rect
->GetLocalSize();
457 if (c_size
.GetHeight() != wxDefaultSize
.GetHeight() ||
458 c_size
.GetWidth() != wxDefaultSize
.GetWidth())
460 minSize
.SetHeight(wxMax(minSize
.GetHeight(), c_size
.GetHeight()));
461 minSize
.SetWidth(wxMax(minSize
.GetWidth(), c_size
.GetWidth()));
464 // For each row, calculate the max height for those fields which are not
465 // resizable in the vertical pane
467 if (!(rect
->GetStyle() & wxVERTICAL_RESIZABLE
|| m_minSizes
[row
]->GetHeight() < 0))
469 m_maxHeight
[row
] = wxMax(m_maxHeight
[row
], minSize
.GetHeight() / rect
->GetHeight());
473 m_rowStretch
[row
] = 1;
474 if (m_minSizes
[row
]->GetHeight())
476 m_maxHeight
[row
] = abs(m_minSizes
[row
]->GetHeight());
480 m_maxHeight
[row
] = wxMax(m_maxHeight
[row
], m_defaultCellSize
.GetHeight());
482 m_weights
[row
]->SetHeight(wxMax(m_weights
[row
]->GetHeight(), rect
->GetWeight().GetHeight()));
485 // For each column, calculate the max width for those fields which are not
486 // resizable in the horizontal pane
488 if (!(rect
->GetStyle() & wxHORIZONTAL_RESIZABLE
|| m_minSizes
[col
]->GetWidth() < 0))
490 if (m_minSizes
[col
]->GetWidth())
492 m_maxWidth
[col
] = abs(m_minSizes
[col
]->GetWidth());
496 m_maxWidth
[col
] = wxMax(m_maxWidth
[col
], minSize
.GetWidth() / rect
->GetWidth());
501 m_colStretch
[col
] = 1;
502 m_maxWidth
[col
] = wxMax(m_maxWidth
[col
], m_defaultCellSize
.GetWidth());
503 m_weights
[col
]->SetWidth(wxMax(m_weights
[col
]->GetWidth(), rect
->GetWeight().GetWidth()));
505 node
= node
->GetNext();
508 } // wxMultiCellSizer :: GetMinimums
509 //---------------------------------------------------------------------------
511 *Function Name: wxMultiCellSizer :: Sum
513 *Parameters: int * pointer to array of ints
514 * int Number of cells to sum up
516 *Description: This member function sums up all the elements of the array which
517 * preceed the specified cell.
523 int wxMultiCellSizer :: Sum(int *array
, int x
)
532 //---------------------------------------------------------------------------
534 *Function Name: wxMultiCellSizer :: DrawGridLines
536 *Parameters: wxDC Device context
538 *Description: This function draws the grid lines in the specified device context.
542 void wxMultiCellSizer :: DrawGridLines(wxDC
& dc
)
545 int maxW
= Sum(m_maxWidth
, m_cell_count
.GetWidth());
546 int maxH
= Sum(m_maxHeight
, m_cell_count
.GetHeight());
551 for (x
= 1; x
< m_cell_count
.GetWidth(); x
++)
553 int colPos
= Sum(m_maxWidth
, x
) ;
554 dc
.DrawLine(colPos
, 0, colPos
, maxH
);
558 for (x
= 1; x
< m_cell_count
.GetHeight(); x
++)
560 int rowPos
= Sum(m_maxHeight
, x
);
561 dc
.DrawLine(0, rowPos
, maxW
, rowPos
);
564 //---------------------------------------------------------------------------
565 // Define the repainting behaviour
567 *Function Name: wxMultiCellSizer::OnPaint
569 *Parameters: wxDC Device context
571 *Description: This function calls the DrawGridLines() member if a window
572 * has been previously specified. This functions MUST be called
573 * from an OnPaint member belonging to the window which the sizer
578 void wxMultiCellSizer::OnPaint(wxDC
& dc
)
587 //---------------------------------------------------------------------------
588 //---------------------------------------------------------------------------
593 #define CELL_LOC(row, col) ((row) * m_maxCols + col)
595 //---------------------------------------------------------------------------
597 //---------------------------------------------------------------------------
599 *Function Name: wxCell : wxLayoutConstraints
601 *Description: This class is used by wxMultiCellCanvas for internal storage
605 class wxCell
: public wxLayoutConstraints
608 wxCell(wxWindow
*win
)
618 //---------------------------------------------------------------------------
620 //---------------------------------------------------------------------------
621 wxMultiCellCanvas :: wxMultiCellCanvas(wxWindow
*par
, int numRows
, int numCols
)
622 : wxFlexGridSizer(numRows
, numCols
, 0, 0)
624 m_cells
= (wxCell
**)calloc(numRows
* numCols
, sizeof(wxCell
*));
629 m_minCellSize
= wxSize(5, 5);
631 //---------------------------------------------------------------------------
632 void wxMultiCellCanvas :: Add(wxWindow
*win
, unsigned int row
, unsigned int col
)
634 // thanks to unsigned data row and col are always >= 0
635 wxASSERT_MSG( /* row >= 0 && */ row
< m_maxRows
,
636 wxString::Format(_T("Row %d out of bounds (0..%d)"), row
, m_maxRows
) );
637 wxASSERT_MSG( /* col >= 0 && */ col
< m_maxCols
,
638 wxString::Format(_T("Column %d out of bounds (0..%d)"), col
, m_maxCols
) );
640 wxASSERT_MSG(m_cells
[CELL_LOC(row
, col
)] == NULL
, wxT("Cell already occupied"));
642 wxCell
*newCell
= new wxCell(win
);
643 m_cells
[CELL_LOC(row
,col
)] = newCell
;
645 //---------------------------------------------------------------------------
646 void wxMultiCellCanvas :: CalculateConstraints()
648 unsigned int row
, col
;
649 for (row
= 0; row
< m_maxRows
; row
++)
651 for (col
= 0; col
< m_maxCols
; col
++)
653 if (!m_cells
[CELL_LOC(row
, col
)])
655 // Create an empty static text field as a placeholder
656 m_cells
[CELL_LOC(row
, col
)] = new wxCell(new wxStaticText(m_parent
, -1, wxT("")));
658 wxFlexGridSizer::Add(m_cells
[CELL_LOC(row
, col
)]->m_window
);
663 /*** End of File ***/