]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/gizmos/multicell.cpp
The mmedia contrib requires sys/soundcard.h on unix, so disable it on unix
[wxWidgets.git] / contrib / src / gizmos / multicell.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: multicell.cpp
3 // Purpose: provide two new classes for layout, wxMultiCellSizer and wxMultiCellCanvas
4 // Author: Jonathan Bayer
5 // Modified by:
6 // Created:
7 // RCS-ID: $Id:
8 // Copyright: (c) Jonathan Bayer
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // This was inspired by the gbsizer class written by Alex Andruschak
13
14 #ifdef __GNUG__
15 #pragma implementation "multicell.h"
16 #endif
17
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24
25 // ----------------------------------------------------------------------------
26 // headers
27 // ----------------------------------------------------------------------------
28
29 #ifndef WX_PRECOMP
30 #include "wx/wx.h"
31 #endif
32
33 #include "wx/gizmos/multicell.h"
34
35
36
37
38 //---------------------------------------------------------------------------
39
40 IMPLEMENT_ABSTRACT_CLASS(wxMultiCellSizer, wxSizer);
41 IMPLEMENT_ABSTRACT_CLASS(wxMultiCellItemHandle, wxObject);
42
43 //---------------------------------------------------------------------------
44 // wxMultiCellItemHandle
45 //---------------------------------------------------------------------------
46 /*
47 *Function Name: wxMultiCellItemHandle :: wxMultiCellItemHandle
48 *
49 *Parameters: int row
50 * int column
51 * int height
52 * int width
53 * wxSize size
54 * wxResizable Style
55 * wxSize weight
56 * int align
57 *
58 *Description: This is the constructor for the class.
59 *
60 */
61
62 void wxMultiCellItemHandle :: Initialize( int row, int column, int height, int width, wxSize size, wxResizable Style, wxSize weight, int align)
63 {
64 m_column = column;
65 m_row = row;
66 m_width = width;
67 m_height = height;
68
69 m_style = Style;
70 m_fixedSize = size;
71 m_alignment = align;
72 m_weight = weight;
73 }
74 //---------------------------------------------------------------------------
75 wxMultiCellItemHandle :: wxMultiCellItemHandle( int row, int column, int height, int width, wxSize size, wxResizable Style, wxSize weight, int align)
76 {
77 Initialize(row, column,height, width, size, Style, weight, align);
78 }
79 //---------------------------------------------------------------------------
80 wxMultiCellItemHandle :: wxMultiCellItemHandle( int row, int column, wxSize size, wxResizable style, wxSize weight, int align)
81 {
82 Initialize(row, column,1, 1, size, style, weight, align);
83 }
84 //---------------------------------------------------------------------------
85 wxMultiCellItemHandle :: wxMultiCellItemHandle( int row, int column, wxResizable style, wxSize weight, int align)
86 {
87 Initialize(row, column, 1, 1, wxSize(1, 1), style, weight, align);
88 }
89 //---------------------------------------------------------------------------
90 int wxMultiCellItemHandle::GetColumn()
91 {
92 return m_column;
93 }
94 //---------------------------------------------------------------------------
95 int wxMultiCellItemHandle::GetRow()
96 {
97 return m_row;
98 }
99 //---------------------------------------------------------------------------
100 int wxMultiCellItemHandle::GetWidth()
101 {
102 return m_width;
103 }
104 //---------------------------------------------------------------------------
105 int wxMultiCellItemHandle::GetHeight()
106 {
107 return m_height;
108 }
109 //---------------------------------------------------------------------------
110 wxResizable wxMultiCellItemHandle :: GetStyle()
111 {
112 return m_style;
113 };
114 //---------------------------------------------------------------------------
115 wxSize wxMultiCellItemHandle :: GetLocalSize()
116 {
117 return m_fixedSize;
118 };
119 //---------------------------------------------------------------------------
120 int wxMultiCellItemHandle :: GetAlignment()
121 {
122 return m_alignment;
123 };
124 //---------------------------------------------------------------------------
125 wxSize wxMultiCellItemHandle :: GetWeight()
126 {
127 return m_weight;
128 };
129
130
131
132 //---------------------------------------------------------------------------
133
134 //---------------------------------------------------------------------------
135 // wxMultiCellSizer
136 //---------------------------------------------------------------------------
137
138 /*
139 *Function Name: wxMultiCellSizer::Initialize
140 *
141 *Parameters: wxsize Initial size of sizer
142 *
143 *Description: This is a common function to initialize all the members of
144 * this class. It is only called from the constructors
145 *
146 */
147
148 void wxMultiCellSizer::Initialize( wxSize size )
149 {
150 m_cell_count = 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));
155
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++)
159 {
160 m_weights[x] = new wxSize(0,0);
161 m_minSizes[x] = new wxSize(0,0);
162 }
163
164 m_maxWeights = 1 + wxMax(m_cell_count.GetHeight(), m_cell_count.GetWidth());
165 m_defaultCellSize = wxSize(5, 5);
166 m_win = NULL;
167 m_pen = wxRED_PEN;
168 }
169 //---------------------------------------------------------------------------
170 wxMultiCellSizer::wxMultiCellSizer( wxSize & size )
171 {
172 Initialize(size);
173 }
174 //---------------------------------------------------------------------------
175 wxMultiCellSizer::wxMultiCellSizer( int rows, int cols)
176 {
177 wxSize size(cols, rows);
178 Initialize(size);
179 }
180 //---------------------------------------------------------------------------
181 wxMultiCellSizer::~wxMultiCellSizer()
182 {
183 WX_CLEAR_LIST(wxSizerItemList, m_children);
184
185 free(m_maxHeight);
186 free(m_maxWidth);
187 free(m_rowStretch);
188 free(m_colStretch);
189
190 for (int x = 0; x < 1 + wxMax(m_cell_count.GetHeight(), m_cell_count.GetWidth()); x++)
191 {
192 delete m_weights[x];
193 delete m_minSizes[x];
194 }
195 free(m_weights);
196 free(m_minSizes);
197 }
198 //---------------------------------------------------------------------------
199 bool wxMultiCellSizer::EnableGridLines(wxWindow *win)
200 {
201 m_win = win;
202 return true;
203 }
204 //---------------------------------------------------------------------------
205 bool wxMultiCellSizer::SetGridPen(wxPen *pen)
206 {
207 m_pen = pen;
208 return true;
209 }
210
211 //---------------------------------------------------------------------------
212 bool wxMultiCellSizer::SetDefaultCellSize(wxSize size)
213 {
214 m_defaultCellSize = size;
215 return true;
216 }
217 //---------------------------------------------------------------------------
218 bool wxMultiCellSizer::SetColumnWidth(int column, int colSize, bool expandable)
219 {
220 if (expandable)
221 {
222 m_minSizes[column]->SetWidth(-colSize);
223 }
224 else
225 {
226 m_minSizes[column]->SetWidth(colSize);
227 }
228 return true;
229 }
230 //---------------------------------------------------------------------------
231 bool wxMultiCellSizer::SetRowHeight(int row, int rowSize, bool expandable)
232 {
233 if (expandable)
234 {
235 m_minSizes[row]->SetHeight(-rowSize);
236 }
237 else
238 {
239 m_minSizes[row]->SetHeight(rowSize);
240 }
241 return true;
242 }
243 //---------------------------------------------------------------------------
244 void wxMultiCellSizer::RecalcSizes()
245 {
246 if (m_children.GetCount() == 0)
247 return;
248 wxSize size = GetSize();
249 wxPoint pos = GetPosition();
250
251 GetMinimums();
252
253 // We need to take the unused space and equally give it out to all the rows/columns
254 // which are stretchable
255
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;
260 int x;
261
262 for (x = 0; x < wxMax(m_cell_count.GetHeight(), m_cell_count.GetWidth()); x++)
263 {
264 if (m_rowStretch[x])
265 {
266 totalHeightWeight += m_weights[x]->GetHeight();
267 }
268 if (x < m_cell_count.GetWidth() && m_colStretch[x])
269 {
270 totalWidthWeight += m_weights[x]->GetWidth();
271 }
272 }
273 for (x = 0; x < wxMax(m_cell_count.GetHeight(), m_cell_count.GetWidth()); x++)
274 {
275 if (x < m_cell_count.GetHeight() && m_rowStretch[x])
276 {
277 m_maxHeight[x] += unUsedHeight * m_weights[x]->GetHeight() / totalHeightWeight;
278 }
279 if (x < m_cell_count.GetWidth() && m_colStretch[x])
280 {
281 m_maxWidth[x] += unUsedWidth * m_weights[x]->GetWidth() / totalWidthWeight;
282 }
283 }
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.
287
288 double cell_width = (double)size.GetWidth() / (double)m_cell_count.GetWidth();
289 double cell_height = (double)size.GetHeight() / (double)m_cell_count.GetHeight();
290 wxPoint c_point;
291 wxSize c_size;
292
293 wxSizerItemList::compatibility_iterator current = m_children.GetFirst();
294 while (current)
295 {
296 wxSizerItem *item = current->GetData();
297
298 wxMultiCellItemHandle *rect;
299 if (item != NULL &&
300 (rect = (wxMultiCellItemHandle *)item->GetUserData()) != NULL)
301 {
302 c_point.x = pos.x + (int)(rect->GetColumn() * cell_width);
303 c_point.y = pos.y + (int)(rect->GetRow() * cell_height);
304
305 c_point.x = pos.x + Sum(m_maxWidth, rect->GetColumn());
306 c_point.y = pos.y + Sum(m_maxHeight, rect->GetRow());
307
308
309 c_size = rect->GetLocalSize();
310 wxSize minSize( item->CalcMin() );
311 if (c_size.GetHeight() != wxDefaultCoord ||
312 c_size.GetWidth() != wxDefaultCoord)
313 {
314 minSize.SetHeight(wxMax(minSize.GetHeight(), c_size.GetHeight()));
315 minSize.SetWidth(wxMax(minSize.GetWidth(), c_size.GetWidth()));
316 }
317 if (rect->GetStyle() & wxHORIZONTAL_RESIZABLE ||
318 rect->GetWidth() > 1
319 || m_minSizes[rect->GetColumn()]->GetWidth() < 0)
320 {
321 int w = 0;
322 for (int x = 0; x < rect->GetWidth(); x++)
323 {
324 w += m_maxWidth[rect->GetColumn() + x];
325 }
326 c_size.SetWidth(w);
327 }
328 else
329 {
330 c_size.SetWidth(minSize.GetWidth() );
331 }
332 if (rect->GetStyle() & wxVERTICAL_RESIZABLE ||
333 rect->GetHeight() > 1 ||
334 m_minSizes[rect->GetRow()]->GetHeight() < 0)
335 {
336 int h = 0;
337 for (int x = 0; x < rect->GetHeight(); x++)
338 {
339 h += m_maxHeight[rect->GetRow() + x];
340 }
341 c_size.SetHeight(h);
342 }
343 else
344 {
345 c_size.SetHeight(minSize.GetHeight());
346 }
347 int extraHeight = (m_maxHeight[rect->GetRow()] - c_size.GetHeight());
348 int extraWidth = (m_maxWidth[rect->GetColumn()] - c_size.GetWidth());
349
350 if (rect->GetWidth() == 1 && rect->GetAlignment() & wxALIGN_CENTER_HORIZONTAL)
351 {
352 c_point.x += extraWidth / 2;
353 }
354 if (rect->GetWidth() == 1 && rect->GetAlignment() & wxALIGN_RIGHT)
355 {
356 c_point.x += extraWidth;
357 }
358 if (rect->GetHeight() == 1 && rect->GetAlignment() & wxALIGN_CENTER_VERTICAL)
359 {
360 c_point.y += extraHeight / 2;
361 }
362 if (rect->GetHeight() == 1 && rect->GetAlignment() & wxALIGN_BOTTOM)
363 {
364 c_point.y += extraHeight;
365 }
366 item->SetDimension(c_point, c_size);
367 }
368 current = current->GetNext();
369 }
370 }
371 //---------------------------------------------------------------------------
372 wxSize wxMultiCellSizer::CalcMin()
373 {
374 if (m_children.GetCount() == 0)
375 return wxSize(10,10);
376
377 GetMinimums();
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 );
381 }
382 //---------------------------------------------------------------------------
383 void wxMultiCellSizer :: GetMinimums()
384 {
385 // We first initial all the arrays EXCEPT for the m_minsizes array.
386
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++)
392 {
393 m_weights[x]->SetHeight(0);
394 m_weights[x]->SetWidth(0);
395 }
396
397 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
398 while (node)
399 {
400 wxSizerItem *item = node->GetData();
401 wxMultiCellItemHandle *rect;
402 if (item != NULL &&
403 (rect = (wxMultiCellItemHandle *)item->GetUserData()) != NULL)
404 {
405 int row = rect->GetRow();
406 int col = rect->GetColumn();
407
408 // First make sure that the control knows about the max rows and columns
409
410 int changed = false;
411 if (row + 1 > m_cell_count.GetHeight())
412 {
413 changed++;
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++)
417 {
418 m_maxHeight[x - 1] = 0;
419 m_rowStretch[x - 1] = 0;
420 }
421 m_cell_count.SetHeight(row + 1);
422 }
423 if (col + 1 > m_cell_count.GetWidth())
424 {
425 changed++;
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++)
429 {
430 m_maxWidth[x - 1] = 0;
431 m_colStretch[x - 1] = 0;
432 }
433 m_cell_count.SetWidth(col + 1);
434 }
435 if (changed)
436 {
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++)
440 {
441 m_weights[x - 1] = new wxSize(0,0);
442 m_minSizes[x - 1] = new wxSize(0,0);
443 }
444 m_maxWeights = 1 + wxMax(m_cell_count.GetHeight(), m_cell_count.GetWidth());
445 }
446
447 // Sum the m_weights for each row/column, but only if they are resizable
448
449 wxSize minSize( item->CalcMin() );
450 wxSize c_size = rect->GetLocalSize();
451 if (c_size.GetHeight() != wxDefaultCoord ||
452 c_size.GetWidth() != wxDefaultCoord)
453 {
454 minSize.SetHeight(wxMax(minSize.GetHeight(), c_size.GetHeight()));
455 minSize.SetWidth(wxMax(minSize.GetWidth(), c_size.GetWidth()));
456 }
457
458 // For each row, calculate the max height for those fields which are not
459 // resizable in the vertical pane
460
461 if (!(rect->GetStyle() & wxVERTICAL_RESIZABLE || m_minSizes[row]->GetHeight() < 0))
462 {
463 m_maxHeight[row] = wxMax(m_maxHeight[row], minSize.GetHeight() / rect->GetHeight());
464 }
465 else
466 {
467 m_rowStretch[row] = 1;
468 if (m_minSizes[row]->GetHeight())
469 {
470 m_maxHeight[row] = abs(m_minSizes[row]->GetHeight());
471 }
472 else
473 {
474 m_maxHeight[row] = wxMax(m_maxHeight[row], m_defaultCellSize.GetHeight());
475 }
476 m_weights[row]->SetHeight(wxMax(m_weights[row]->GetHeight(), rect->GetWeight().GetHeight()));
477 }
478
479 // For each column, calculate the max width for those fields which are not
480 // resizable in the horizontal pane
481
482 if (!(rect->GetStyle() & wxHORIZONTAL_RESIZABLE || m_minSizes[col]->GetWidth() < 0))
483 {
484 if (m_minSizes[col]->GetWidth())
485 {
486 m_maxWidth[col] = abs(m_minSizes[col]->GetWidth());
487 }
488 else
489 {
490 m_maxWidth[col] = wxMax(m_maxWidth[col], minSize.GetWidth() / rect->GetWidth());
491 }
492 }
493 else
494 {
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()));
498 }
499 node = node->GetNext();
500 }
501 }
502 } // wxMultiCellSizer :: GetMinimums
503 //---------------------------------------------------------------------------
504 /*
505 *Function Name: wxMultiCellSizer :: Sum
506 *
507 *Parameters: int* pointer to array of ints
508 * int Number of cells to sum up
509 *
510 *Description: This member function sums up all the elements of the array which
511 * preceed the specified cell.
512 *
513 *Returns: int Sum
514 *
515 */
516
517 int wxMultiCellSizer :: Sum(int *array, int x)
518 {
519 int sum = 0;
520 while (x--)
521 {
522 sum += array[x];
523 }
524 return sum;
525 }
526 //---------------------------------------------------------------------------
527 /*
528 *Function Name: wxMultiCellSizer :: DrawGridLines
529 *
530 *Parameters: wxDC Device context
531 *
532 *Description: This function draws the grid lines in the specified device context.
533 *
534 */
535
536 void wxMultiCellSizer :: DrawGridLines(wxDC& dc)
537 {
538 RecalcSizes();
539 int maxW = Sum(m_maxWidth, m_cell_count.GetWidth());
540 int maxH = Sum(m_maxHeight, m_cell_count.GetHeight());
541 int x;
542
543 // Draw the columns
544 dc.SetPen(* m_pen);
545 for (x = 1; x < m_cell_count.GetWidth(); x++)
546 {
547 int colPos = Sum(m_maxWidth, x) ;
548 dc.DrawLine(colPos, 0, colPos, maxH);
549 }
550
551 // Draw the rows
552 for (x = 1; x < m_cell_count.GetHeight(); x++)
553 {
554 int rowPos = Sum(m_maxHeight, x);
555 dc.DrawLine(0, rowPos, maxW, rowPos);
556 }
557 }
558 //---------------------------------------------------------------------------
559 // Define the repainting behaviour
560 /*
561 *Function Name: wxMultiCellSizer::OnPaint
562 *
563 *Parameters: wxDC Device context
564 *
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
568 * is attached to.
569 *
570 */
571
572 void wxMultiCellSizer::OnPaint(wxDC& dc )
573 {
574 if (m_win)
575 {
576 DrawGridLines(dc);
577 }
578 }
579
580
581 //---------------------------------------------------------------------------
582 //---------------------------------------------------------------------------
583
584
585
586
587 #define CELL_LOC(row, col) ((row) * m_maxCols + col)
588
589 //---------------------------------------------------------------------------
590 // wxCell
591 //---------------------------------------------------------------------------
592 /*
593 *Function Name: wxCell : wxLayoutConstraints
594 *
595 *Description: This class is used by wxMultiCellCanvas for internal storage
596 *
597 */
598
599 class wxCell : public wxLayoutConstraints
600 {
601 public:
602 wxCell(wxWindow *win)
603 {
604 m_window = win;
605 };
606
607 wxWindow *m_window;
608 };
609
610
611
612 //---------------------------------------------------------------------------
613 // wxMultiCellCanvas
614 //---------------------------------------------------------------------------
615 wxMultiCellCanvas :: wxMultiCellCanvas(wxWindow *par, int numRows, int numCols)
616 : wxFlexGridSizer(numRows, numCols, 0, 0)
617 {
618 m_cells = (wxCell **)calloc(numRows * numCols, sizeof(wxCell *));
619
620 m_parent = par;
621 m_maxRows = numRows;
622 m_maxCols = numCols;
623 m_minCellSize = wxSize(5, 5);
624 }
625 //---------------------------------------------------------------------------
626 void wxMultiCellCanvas :: Add(wxWindow *win, unsigned int row, unsigned int col)
627 {
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) );
633
634 wxASSERT_MSG(m_cells[CELL_LOC(row, col)] == NULL, wxT("Cell already occupied"));
635
636 wxCell *newCell = new wxCell(win);
637 m_cells[CELL_LOC(row,col)] = newCell;
638 }
639 //---------------------------------------------------------------------------
640 void wxMultiCellCanvas :: CalculateConstraints()
641 {
642 unsigned int row, col;
643 for (row = 0; row < m_maxRows; row++)
644 {
645 for (col = 0; col < m_maxCols; col++)
646 {
647 if (!m_cells[CELL_LOC(row, col)])
648 {
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));
651 }
652 wxFlexGridSizer::Add(m_cells[CELL_LOC(row, col)]->m_window);
653 }
654 }
655 }
656
657 /*** End of File ***/
658