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);
387 m_minWidth
= Sum(m_maxWidth
, m_cell_count
.GetWidth());
388 m_minHeight
= Sum(m_maxHeight
, m_cell_count
.GetHeight());
389 return wxSize( m_minWidth
, m_minHeight
);
391 //---------------------------------------------------------------------------
392 void wxMultiCellSizer :: GetMinimums()
394 // We first initial all the arrays EXCEPT for the m_minsizes array.
396 memset(m_maxHeight
, 0, sizeof(int) * m_cell_count
.GetHeight());
397 memset(m_maxWidth
, 0, sizeof(int) * m_cell_count
.GetWidth());
398 memset(m_rowStretch
, 0, sizeof(int) * m_cell_count
.GetHeight());
399 memset(m_colStretch
, 0, sizeof(int) * m_cell_count
.GetWidth());
400 for (int x
= 0; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
402 m_weights
[x
]->SetHeight(0);
403 m_weights
[x
]->SetWidth(0);
406 wxSizerItemList::Node
*node
= m_children
.GetFirst();
409 wxSizerItem
*item
= node
->GetData();
410 wxMultiCellItemHandle
*rect
;
412 (rect
= (wxMultiCellItemHandle
*)item
->GetUserData()) != NULL
)
414 int row
= rect
->GetRow();
415 int col
= rect
->GetColumn();
417 // First make sure that the control knows about the max rows and columns
420 if (row
+ 1 > m_cell_count
.GetHeight())
423 m_maxHeight
= (int *)realloc(m_maxHeight
, (1 + row
) * sizeof(int));
424 m_rowStretch
= (int *)realloc(m_rowStretch
, (1 + row
) * sizeof(int));
425 for (int x
= m_cell_count
.GetHeight(); x
< row
+ 1; x
++)
427 m_maxHeight
[x
- 1] = 0;
428 m_rowStretch
[x
- 1] = 0;
430 m_cell_count
.SetHeight(row
+ 1);
432 if (col
+ 1 > m_cell_count
.GetWidth())
435 m_maxWidth
= (int *)realloc(m_maxWidth
, (1 + col
) * sizeof(int));
436 m_colStretch
= (int *)realloc(m_colStretch
, ( 1 + col
) * sizeof(int));
437 for (int x
= m_cell_count
.GetWidth(); x
< col
+ 1; x
++)
439 m_maxWidth
[x
- 1] = 0;
440 m_colStretch
[x
- 1] = 0;
442 m_cell_count
.SetWidth(col
+ 1);
446 m_weights
= (wxSize
**)realloc(m_weights
, (1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
447 m_minSizes
= (wxSize
**)realloc(m_minSizes
, (1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth())) * sizeof(wxSize
*));
448 for (int x
= m_maxWeights
; x
< 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth()); x
++)
450 m_weights
[x
- 1] = new wxSize(0,0);
451 m_minSizes
[x
- 1] = new wxSize(0,0);
453 m_maxWeights
= 1 + wxMax(m_cell_count
.GetHeight(), m_cell_count
.GetWidth());
456 // Sum the m_weights for each row/column, but only if they are resizable
458 wxSize
minSize( item
->CalcMin() );
459 wxSize c_size
= rect
->GetLocalSize();
460 if (c_size
.GetHeight() != wxDefaultSize
.GetHeight() ||
461 c_size
.GetWidth() != wxDefaultSize
.GetWidth())
463 minSize
.SetHeight(wxMax(minSize
.GetHeight(), c_size
.GetHeight()));
464 minSize
.SetWidth(wxMax(minSize
.GetWidth(), c_size
.GetWidth()));
467 // For each row, calculate the max height for those fields which are not
468 // resizable in the vertical pane
470 if (!(rect
->GetStyle() & wxVERTICAL_RESIZABLE
|| m_minSizes
[row
]->GetHeight() < 0))
472 m_maxHeight
[row
] = wxMax(m_maxHeight
[row
], minSize
.GetHeight() / rect
->GetHeight());
476 m_rowStretch
[row
] = 1;
477 if (m_minSizes
[row
]->GetHeight())
479 m_maxHeight
[row
] = abs(m_minSizes
[row
]->GetHeight());
483 m_maxHeight
[row
] = wxMax(m_maxHeight
[row
], m_defaultCellSize
.GetHeight());
485 m_weights
[row
]->SetHeight(wxMax(m_weights
[row
]->GetHeight(), rect
->GetWeight().GetHeight()));
488 // For each column, calculate the max width for those fields which are not
489 // resizable in the horizontal pane
491 if (!(rect
->GetStyle() & wxHORIZONTAL_RESIZABLE
|| m_minSizes
[col
]->GetWidth() < 0))
493 if (m_minSizes
[col
]->GetWidth())
495 m_maxWidth
[col
] = abs(m_minSizes
[col
]->GetWidth());
499 m_maxWidth
[col
] = wxMax(m_maxWidth
[col
], minSize
.GetWidth() / rect
->GetWidth());
504 m_colStretch
[col
] = 1;
505 m_maxWidth
[col
] = wxMax(m_maxWidth
[col
], m_defaultCellSize
.GetWidth());
506 m_weights
[col
]->SetWidth(wxMax(m_weights
[col
]->GetWidth(), rect
->GetWeight().GetWidth()));
508 node
= node
->GetNext();
511 } // wxMultiCellSizer :: GetMinimums
512 //---------------------------------------------------------------------------
514 *Function Name: wxMultiCellSizer :: Sum
516 *Parameters: int * pointer to array of ints
517 * int Number of cells to sum up
519 *Description: This member function sums up all the elements of the array which
520 * preceed the specified cell.
526 int wxMultiCellSizer :: Sum(int *array
, int x
)
535 //---------------------------------------------------------------------------
537 *Function Name: wxMultiCellSizer :: DrawGridLines
539 *Parameters: wxDC Device context
541 *Description: This function draws the grid lines in the specified device context.
545 void wxMultiCellSizer :: DrawGridLines(wxDC
& dc
)
548 int maxW
= Sum(m_maxWidth
, m_cell_count
.GetWidth());
549 int maxH
= Sum(m_maxHeight
, m_cell_count
.GetHeight());
554 for (x
= 1; x
< m_cell_count
.GetWidth(); x
++)
556 int colPos
= Sum(m_maxWidth
, x
) ;
557 dc
.DrawLine(colPos
, 0, colPos
, maxH
);
561 for (x
= 1; x
< m_cell_count
.GetHeight(); x
++)
563 int rowPos
= Sum(m_maxHeight
, x
);
564 dc
.DrawLine(0, rowPos
, maxW
, rowPos
);
567 //---------------------------------------------------------------------------
568 // Define the repainting behaviour
570 *Function Name: wxMultiCellSizer::OnPaint
572 *Parameters: wxDC Device context
574 *Description: This function calls the DrawGridLines() member if a window
575 * has been previously specified. This functions MUST be called
576 * from an OnPaint member belonging to the window which the sizer
581 void wxMultiCellSizer::OnPaint(wxDC
& dc
)
590 //---------------------------------------------------------------------------
591 //---------------------------------------------------------------------------
596 #define CELL_LOC(row, col) ((row) * m_maxCols + col)
598 //---------------------------------------------------------------------------
600 //---------------------------------------------------------------------------
602 *Function Name: wxCell : wxLayoutConstraints
604 *Description: This class is used by wxMultiCellCanvas for internal storage
608 class wxCell
: public wxLayoutConstraints
611 wxCell(wxWindow
*win
)
621 //---------------------------------------------------------------------------
623 //---------------------------------------------------------------------------
624 wxMultiCellCanvas :: wxMultiCellCanvas(wxWindow
*par
, int numRows
, int numCols
)
625 : wxFlexGridSizer(numRows
, numCols
, 0, 0)
627 m_cells
= (wxCell
**)calloc(numRows
* numCols
, sizeof(wxCell
*));
632 m_minCellSize
= wxSize(5, 5);
634 //---------------------------------------------------------------------------
635 void wxMultiCellCanvas :: Add(wxWindow
*win
, unsigned int row
, unsigned int col
)
637 wxASSERT_MSG(row
>= 0 && row
< m_maxRows
,
638 wxString::Format(_T("Row %d out of bounds (0..%d)"), row
, m_maxRows
) );
639 wxASSERT_MSG(col
>= 0 && col
< m_maxCols
,
640 wxString::Format(_T("Column %d out of bounds (0..%d)"), col
, m_maxCols
) );
642 wxASSERT_MSG(m_cells
[CELL_LOC(row
, col
)] == NULL
, wxT("Cell already occupied"));
644 wxCell
*newCell
= new wxCell(win
);
645 m_cells
[CELL_LOC(row
,col
)] = newCell
;
647 //---------------------------------------------------------------------------
648 void wxMultiCellCanvas :: CalculateConstraints()
650 unsigned int row
, col
;
651 for (row
= 0; row
< m_maxRows
; row
++)
653 for (col
= 0; col
< m_maxCols
; col
++)
655 if (!m_cells
[CELL_LOC(row
, col
)])
657 // Create an empty static text field as a placeholder
658 m_cells
[CELL_LOC(row
, col
)] = new wxCell(new wxStaticText(m_parent
, -1, wxT("")));
660 wxFlexGridSizer::Add(m_cells
[CELL_LOC(row
, col
)]->m_window
);
665 /*** End of File ***/