Don't crash in wxGridCellAutoWrapStringRenderer when the column is hidden.
[wxWidgets.git] / src / generic / gridctrl.cpp
1 ///////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/gridctrl.cpp
3 // Purpose: wxGrid controls
4 // Author: Paul Gammans, Roger Gammans
5 // Modified by:
6 // Created: 11/04/2001
7 // Copyright: (c) The Computer Surgery (paul@compsurg.co.uk)
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 #include "wx/wxprec.h"
12
13 #ifdef __BORLANDC__
14 #pragma hdrstop
15 #endif
16
17 #if wxUSE_GRID
18
19 #include "wx/generic/gridctrl.h"
20 #include "wx/generic/grideditors.h"
21
22 #ifndef WX_PRECOMP
23 #include "wx/textctrl.h"
24 #include "wx/dc.h"
25 #include "wx/combobox.h"
26 #include "wx/settings.h"
27 #include "wx/log.h"
28 #include "wx/checkbox.h"
29 #endif // WX_PRECOMP
30
31 #include "wx/tokenzr.h"
32 #include "wx/renderer.h"
33
34
35 // ----------------------------------------------------------------------------
36 // wxGridCellRenderer
37 // ----------------------------------------------------------------------------
38
39 void wxGridCellRenderer::Draw(wxGrid& grid,
40 wxGridCellAttr& attr,
41 wxDC& dc,
42 const wxRect& rect,
43 int WXUNUSED(row), int WXUNUSED(col),
44 bool isSelected)
45 {
46 dc.SetBackgroundMode( wxBRUSHSTYLE_SOLID );
47
48 wxColour clr;
49 if ( grid.IsThisEnabled() )
50 {
51 if ( isSelected )
52 {
53 if ( grid.HasFocus() )
54 clr = grid.GetSelectionBackground();
55 else
56 clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
57 }
58 else
59 {
60 clr = attr.GetBackgroundColour();
61 }
62 }
63 else // grey out fields if the grid is disabled
64 {
65 clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
66 }
67
68 dc.SetBrush(clr);
69 dc.SetPen( *wxTRANSPARENT_PEN );
70 dc.DrawRectangle(rect);
71 }
72
73
74 // ----------------------------------------------------------------------------
75 // wxGridCellDateTimeRenderer
76 // ----------------------------------------------------------------------------
77
78 #if wxUSE_DATETIME
79
80 // Enables a grid cell to display a formatted date and or time
81
82 wxGridCellDateTimeRenderer::wxGridCellDateTimeRenderer(const wxString& outformat, const wxString& informat)
83 {
84 m_iformat = informat;
85 m_oformat = outformat;
86 m_tz = wxDateTime::Local;
87 m_dateDef = wxDefaultDateTime;
88 }
89
90 wxGridCellRenderer *wxGridCellDateTimeRenderer::Clone() const
91 {
92 wxGridCellDateTimeRenderer *renderer = new wxGridCellDateTimeRenderer;
93 renderer->m_iformat = m_iformat;
94 renderer->m_oformat = m_oformat;
95 renderer->m_dateDef = m_dateDef;
96 renderer->m_tz = m_tz;
97
98 return renderer;
99 }
100
101 wxString wxGridCellDateTimeRenderer::GetString(const wxGrid& grid, int row, int col)
102 {
103 wxGridTableBase *table = grid.GetTable();
104
105 bool hasDatetime = false;
106 wxDateTime val;
107 wxString text;
108 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_DATETIME) )
109 {
110 void * tempval = table->GetValueAsCustom(row, col,wxGRID_VALUE_DATETIME);
111
112 if (tempval)
113 {
114 val = *((wxDateTime *)tempval);
115 hasDatetime = true;
116 delete (wxDateTime *)tempval;
117 }
118
119 }
120
121 if (!hasDatetime )
122 {
123 text = table->GetValue(row, col);
124 const char * const end = val.ParseFormat(text, m_iformat, m_dateDef);
125 hasDatetime = end && !*end;
126 }
127
128 if ( hasDatetime )
129 text = val.Format(m_oformat, m_tz );
130
131 // If we failed to parse string just show what we where given?
132 return text;
133 }
134
135 void wxGridCellDateTimeRenderer::Draw(wxGrid& grid,
136 wxGridCellAttr& attr,
137 wxDC& dc,
138 const wxRect& rectCell,
139 int row, int col,
140 bool isSelected)
141 {
142 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
143
144 SetTextColoursAndFont(grid, attr, dc, isSelected);
145
146 // draw the text right aligned by default
147 int hAlign = wxALIGN_RIGHT,
148 vAlign = wxALIGN_INVALID;
149 attr.GetNonDefaultAlignment(&hAlign, &vAlign);
150
151 wxRect rect = rectCell;
152 rect.Inflate(-1);
153
154 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
155 }
156
157 wxSize wxGridCellDateTimeRenderer::GetBestSize(wxGrid& grid,
158 wxGridCellAttr& attr,
159 wxDC& dc,
160 int row, int col)
161 {
162 return DoGetBestSize(attr, dc, GetString(grid, row, col));
163 }
164
165 void wxGridCellDateTimeRenderer::SetParameters(const wxString& params)
166 {
167 if (!params.empty())
168 m_oformat=params;
169 }
170
171 #endif // wxUSE_DATETIME
172
173 // ----------------------------------------------------------------------------
174 // wxGridCellEnumRenderer
175 // ----------------------------------------------------------------------------
176 // Renders a number as a textual equivalent.
177 // eg data in cell is 0,1,2 ... n the cell could be rendered as "John","Fred"..."Bob"
178
179
180 wxGridCellEnumRenderer::wxGridCellEnumRenderer(const wxString& choices)
181 {
182 if (!choices.empty())
183 SetParameters(choices);
184 }
185
186 wxGridCellRenderer *wxGridCellEnumRenderer::Clone() const
187 {
188 wxGridCellEnumRenderer *renderer = new wxGridCellEnumRenderer;
189 renderer->m_choices = m_choices;
190 return renderer;
191 }
192
193 wxString wxGridCellEnumRenderer::GetString(const wxGrid& grid, int row, int col)
194 {
195 wxGridTableBase *table = grid.GetTable();
196 wxString text;
197 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
198 {
199 int choiceno = table->GetValueAsLong(row, col);
200 text.Printf(wxT("%s"), m_choices[ choiceno ].c_str() );
201 }
202 else
203 {
204 text = table->GetValue(row, col);
205 }
206
207
208 //If we faild to parse string just show what we where given?
209 return text;
210 }
211
212 void wxGridCellEnumRenderer::Draw(wxGrid& grid,
213 wxGridCellAttr& attr,
214 wxDC& dc,
215 const wxRect& rectCell,
216 int row, int col,
217 bool isSelected)
218 {
219 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
220
221 SetTextColoursAndFont(grid, attr, dc, isSelected);
222
223 // draw the text right aligned by default
224 int hAlign = wxALIGN_RIGHT,
225 vAlign = wxALIGN_INVALID;
226 attr.GetNonDefaultAlignment(&hAlign, &vAlign);
227
228 wxRect rect = rectCell;
229 rect.Inflate(-1);
230
231 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
232 }
233
234 wxSize wxGridCellEnumRenderer::GetBestSize(wxGrid& grid,
235 wxGridCellAttr& attr,
236 wxDC& dc,
237 int row, int col)
238 {
239 return DoGetBestSize(attr, dc, GetString(grid, row, col));
240 }
241
242 void wxGridCellEnumRenderer::SetParameters(const wxString& params)
243 {
244 if ( !params )
245 {
246 // what can we do?
247 return;
248 }
249
250 m_choices.Empty();
251
252 wxStringTokenizer tk(params, wxT(','));
253 while ( tk.HasMoreTokens() )
254 {
255 m_choices.Add(tk.GetNextToken());
256 }
257 }
258
259
260 // ----------------------------------------------------------------------------
261 // wxGridCellAutoWrapStringRenderer
262 // ----------------------------------------------------------------------------
263
264
265 void
266 wxGridCellAutoWrapStringRenderer::Draw(wxGrid& grid,
267 wxGridCellAttr& attr,
268 wxDC& dc,
269 const wxRect& rectCell,
270 int row, int col,
271 bool isSelected) {
272
273
274 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
275
276 // now we only have to draw the text
277 SetTextColoursAndFont(grid, attr, dc, isSelected);
278
279 int horizAlign, vertAlign;
280 attr.GetAlignment(&horizAlign, &vertAlign);
281
282 wxRect rect = rectCell;
283 rect.Inflate(-1);
284
285 grid.DrawTextRectangle(dc, GetTextLines(grid,dc,attr,rect,row,col),
286 rect, horizAlign, vertAlign);
287 }
288
289
290 wxArrayString
291 wxGridCellAutoWrapStringRenderer::GetTextLines(wxGrid& grid,
292 wxDC& dc,
293 const wxGridCellAttr& attr,
294 const wxRect& rect,
295 int row, int col)
296 {
297 dc.SetFont(attr.GetFont());
298 const wxCoord maxWidth = rect.GetWidth();
299
300 // Transform logical lines into physical ones, wrapping the longer ones.
301 const wxArrayString
302 logicalLines = wxSplit(grid.GetCellValue(row, col), '\n', '\0');
303
304 // Trying to do anything if the column is hidden anyhow doesn't make sense
305 // and we run into problems in BreakLine() in this case.
306 if ( maxWidth <= 0 )
307 return logicalLines;
308
309 wxArrayString physicalLines;
310 for ( wxArrayString::const_iterator it = logicalLines.begin();
311 it != logicalLines.end();
312 ++it )
313 {
314 const wxString& line = *it;
315
316 if ( dc.GetTextExtent(line).x > maxWidth )
317 {
318 // Line does not fit, break it up.
319 BreakLine(dc, line, maxWidth, physicalLines);
320 }
321 else // The entire line fits as is
322 {
323 physicalLines.push_back(line);
324 }
325 }
326
327 return physicalLines;
328 }
329
330 void
331 wxGridCellAutoWrapStringRenderer::BreakLine(wxDC& dc,
332 const wxString& logicalLine,
333 wxCoord maxWidth,
334 wxArrayString& lines)
335 {
336 wxCoord lineWidth = 0;
337 wxString line;
338
339 // For each word
340 wxStringTokenizer wordTokenizer(logicalLine, wxS(" \t"), wxTOKEN_RET_DELIMS);
341 while ( wordTokenizer.HasMoreTokens() )
342 {
343 const wxString word = wordTokenizer.GetNextToken();
344 const wxCoord wordWidth = dc.GetTextExtent(word).x;
345 if ( lineWidth + wordWidth < maxWidth )
346 {
347 // Word fits, just add it to this line.
348 line += word;
349 lineWidth += wordWidth;
350 }
351 else
352 {
353 // Word does not fit, check whether the word is itself wider that
354 // available width
355 if ( wordWidth < maxWidth )
356 {
357 // Word can fit in a new line, put it at the beginning
358 // of the new line.
359 lines.push_back(line);
360 line = word;
361 lineWidth = wordWidth;
362 }
363 else // Word cannot fit in available width at all.
364 {
365 if ( !line.empty() )
366 {
367 lines.push_back(line);
368 line.clear();
369 lineWidth = 0;
370 }
371
372 // Break it up in several lines.
373 lineWidth = BreakWord(dc, word, maxWidth, lines, line);
374 }
375 }
376 }
377
378 if ( !line.empty() )
379 lines.push_back(line);
380 }
381
382
383 wxCoord
384 wxGridCellAutoWrapStringRenderer::BreakWord(wxDC& dc,
385 const wxString& word,
386 wxCoord maxWidth,
387 wxArrayString& lines,
388 wxString& line)
389 {
390 wxArrayInt widths;
391 dc.GetPartialTextExtents(word, widths);
392
393 // TODO: Use binary search to find the first element > maxWidth.
394 const unsigned count = widths.size();
395 unsigned n;
396 for ( n = 0; n < count; n++ )
397 {
398 if ( widths[n] > maxWidth )
399 break;
400 }
401
402 if ( n == 0 )
403 {
404 // This is a degenerate case: the first character of the word is
405 // already wider than the available space, so we just can't show it
406 // completely and have to put the first character in this line.
407 n = 1;
408 }
409
410 lines.push_back(word.substr(0, n));
411
412 // Check if the remainder of the string fits in one line.
413 //
414 // Unfortunately we can't use the existing partial text extents as the
415 // extent of the remainder may be different when it's rendered in a
416 // separate line instead of as part of the same one, so we have to
417 // recompute it.
418 const wxString rest = word.substr(n);
419 const wxCoord restWidth = dc.GetTextExtent(rest).x;
420 if ( restWidth <= maxWidth )
421 {
422 line = rest;
423 return restWidth;
424 }
425
426 // Break the rest of the word into lines.
427 //
428 // TODO: Perhaps avoid recursion? The code is simpler like this but using a
429 // loop in this function would probably be more efficient.
430 return BreakWord(dc, rest, maxWidth, lines, line);
431 }
432
433 wxSize
434 wxGridCellAutoWrapStringRenderer::GetBestSize(wxGrid& grid,
435 wxGridCellAttr& attr,
436 wxDC& dc,
437 int row, int col)
438 {
439 wxCoord x,y, height , width = grid.GetColSize(col) -20;
440 // for width, subtract 20 because ColSize includes a magin of 10 pixels
441 // that we do not want here and because we always start with an increment
442 // by 10 in the loop below.
443 int count = 250; //Limit iterations..
444
445 wxRect rect(0,0,width,10);
446
447 // M is a nice large character 'y' gives descender!.
448 dc.GetTextExtent(wxT("My"), &x, &y);
449
450 do
451 {
452 width+=10;
453 rect.SetWidth(width);
454 height = y * (wx_truncate_cast(wxCoord, GetTextLines(grid,dc,attr,rect,row,col).GetCount()));
455 count--;
456 // Search for a shape no taller than the golden ratio.
457 } while (count && (width < (height*1.68)) );
458
459
460 return wxSize(width,height);
461 }
462
463
464 // ----------------------------------------------------------------------------
465 // wxGridCellStringRenderer
466 // ----------------------------------------------------------------------------
467
468 void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid& grid,
469 const wxGridCellAttr& attr,
470 wxDC& dc,
471 bool isSelected)
472 {
473 dc.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT );
474
475 // TODO some special colours for attr.IsReadOnly() case?
476
477 // different coloured text when the grid is disabled
478 if ( grid.IsThisEnabled() )
479 {
480 if ( isSelected )
481 {
482 wxColour clr;
483 if ( grid.HasFocus() )
484 clr = grid.GetSelectionBackground();
485 else
486 clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
487 dc.SetTextBackground( clr );
488 dc.SetTextForeground( grid.GetSelectionForeground() );
489 }
490 else
491 {
492 dc.SetTextBackground( attr.GetBackgroundColour() );
493 dc.SetTextForeground( attr.GetTextColour() );
494 }
495 }
496 else
497 {
498 dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
499 dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
500 }
501
502 dc.SetFont( attr.GetFont() );
503 }
504
505 wxSize wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr& attr,
506 wxDC& dc,
507 const wxString& text)
508 {
509 wxCoord x = 0, y = 0, max_x = 0;
510 dc.SetFont(attr.GetFont());
511 wxStringTokenizer tk(text, wxT('\n'));
512 while ( tk.HasMoreTokens() )
513 {
514 dc.GetTextExtent(tk.GetNextToken(), &x, &y);
515 max_x = wxMax(max_x, x);
516 }
517
518 y *= 1 + text.Freq(wxT('\n')); // multiply by the number of lines.
519
520 return wxSize(max_x, y);
521 }
522
523 wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
524 wxGridCellAttr& attr,
525 wxDC& dc,
526 int row, int col)
527 {
528 return DoGetBestSize(attr, dc, grid.GetCellValue(row, col));
529 }
530
531 void wxGridCellStringRenderer::Draw(wxGrid& grid,
532 wxGridCellAttr& attr,
533 wxDC& dc,
534 const wxRect& rectCell,
535 int row, int col,
536 bool isSelected)
537 {
538 wxRect rect = rectCell;
539 rect.Inflate(-1);
540
541 // erase only this cells background, overflow cells should have been erased
542 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
543
544 int hAlign, vAlign;
545 attr.GetAlignment(&hAlign, &vAlign);
546
547 int overflowCols = 0;
548
549 if (attr.GetOverflow())
550 {
551 int cols = grid.GetNumberCols();
552 int best_width = GetBestSize(grid,attr,dc,row,col).GetWidth();
553 int cell_rows, cell_cols;
554 attr.GetSize( &cell_rows, &cell_cols ); // shouldn't get here if <= 0
555 if ((best_width > rectCell.width) && (col < cols) && grid.GetTable())
556 {
557 int i, c_cols, c_rows;
558 for (i = col+cell_cols; i < cols; i++)
559 {
560 bool is_empty = true;
561 for (int j=row; j < row + cell_rows; j++)
562 {
563 // check w/ anchor cell for multicell block
564 grid.GetCellSize(j, i, &c_rows, &c_cols);
565 if (c_rows > 0)
566 c_rows = 0;
567 if (!grid.GetTable()->IsEmptyCell(j + c_rows, i))
568 {
569 is_empty = false;
570 break;
571 }
572 }
573
574 if (is_empty)
575 {
576 rect.width += grid.GetColSize(i);
577 }
578 else
579 {
580 i--;
581 break;
582 }
583
584 if (rect.width >= best_width)
585 break;
586 }
587
588 overflowCols = i - col - cell_cols + 1;
589 if (overflowCols >= cols)
590 overflowCols = cols - 1;
591 }
592
593 if (overflowCols > 0) // redraw overflow cells w/ proper hilight
594 {
595 hAlign = wxALIGN_LEFT; // if oveflowed then it's left aligned
596 wxRect clip = rect;
597 clip.x += rectCell.width;
598 // draw each overflow cell individually
599 int col_end = col + cell_cols + overflowCols;
600 if (col_end >= grid.GetNumberCols())
601 col_end = grid.GetNumberCols() - 1;
602 for (int i = col + cell_cols; i <= col_end; i++)
603 {
604 clip.width = grid.GetColSize(i) - 1;
605 dc.DestroyClippingRegion();
606 dc.SetClippingRegion(clip);
607
608 SetTextColoursAndFont(grid, attr, dc,
609 grid.IsInSelection(row,i));
610
611 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
612 rect, hAlign, vAlign);
613 clip.x += grid.GetColSize(i) - 1;
614 }
615
616 rect = rectCell;
617 rect.Inflate(-1);
618 rect.width++;
619 dc.DestroyClippingRegion();
620 }
621 }
622
623 // now we only have to draw the text
624 SetTextColoursAndFont(grid, attr, dc, isSelected);
625
626 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
627 rect, hAlign, vAlign);
628 }
629
630 // ----------------------------------------------------------------------------
631 // wxGridCellNumberRenderer
632 // ----------------------------------------------------------------------------
633
634 wxString wxGridCellNumberRenderer::GetString(const wxGrid& grid, int row, int col)
635 {
636 wxGridTableBase *table = grid.GetTable();
637 wxString text;
638 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
639 {
640 text.Printf(wxT("%ld"), table->GetValueAsLong(row, col));
641 }
642 else
643 {
644 text = table->GetValue(row, col);
645 }
646
647 return text;
648 }
649
650 void wxGridCellNumberRenderer::Draw(wxGrid& grid,
651 wxGridCellAttr& attr,
652 wxDC& dc,
653 const wxRect& rectCell,
654 int row, int col,
655 bool isSelected)
656 {
657 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
658
659 SetTextColoursAndFont(grid, attr, dc, isSelected);
660
661 // draw the text right aligned by default
662 int hAlign = wxALIGN_RIGHT,
663 vAlign = wxALIGN_INVALID;
664 attr.GetNonDefaultAlignment(&hAlign, &vAlign);
665
666 wxRect rect = rectCell;
667 rect.Inflate(-1);
668
669 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
670 }
671
672 wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
673 wxGridCellAttr& attr,
674 wxDC& dc,
675 int row, int col)
676 {
677 return DoGetBestSize(attr, dc, GetString(grid, row, col));
678 }
679
680 // ----------------------------------------------------------------------------
681 // wxGridCellFloatRenderer
682 // ----------------------------------------------------------------------------
683
684 wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width,
685 int precision,
686 int format)
687 {
688 SetWidth(width);
689 SetPrecision(precision);
690 SetFormat(format);
691 }
692
693 wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
694 {
695 wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
696 renderer->m_width = m_width;
697 renderer->m_precision = m_precision;
698 renderer->m_style = m_style;
699 renderer->m_format = m_format;
700
701 return renderer;
702 }
703
704 wxString wxGridCellFloatRenderer::GetString(const wxGrid& grid, int row, int col)
705 {
706 wxGridTableBase *table = grid.GetTable();
707
708 bool hasDouble;
709 double val;
710 wxString text;
711 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
712 {
713 val = table->GetValueAsDouble(row, col);
714 hasDouble = true;
715 }
716 else
717 {
718 text = table->GetValue(row, col);
719 hasDouble = text.ToDouble(&val);
720 }
721
722 if ( hasDouble )
723 {
724 if ( !m_format )
725 {
726 if ( m_width == -1 )
727 {
728 if ( m_precision == -1 )
729 {
730 // default width/precision
731 m_format = wxT("%");
732 }
733 else
734 {
735 m_format.Printf(wxT("%%.%d"), m_precision);
736 }
737 }
738 else if ( m_precision == -1 )
739 {
740 // default precision
741 m_format.Printf(wxT("%%%d."), m_width);
742 }
743 else
744 {
745 m_format.Printf(wxT("%%%d.%d"), m_width, m_precision);
746 }
747
748 bool isUpper = ( ( m_style & wxGRID_FLOAT_FORMAT_UPPER ) == wxGRID_FLOAT_FORMAT_UPPER);
749 if ( ( m_style & wxGRID_FLOAT_FORMAT_SCIENTIFIC ) == wxGRID_FLOAT_FORMAT_SCIENTIFIC)
750 m_format += isUpper ? wxT('E') : wxT('e');
751 else if ( ( m_style & wxGRID_FLOAT_FORMAT_COMPACT ) == wxGRID_FLOAT_FORMAT_COMPACT)
752 m_format += isUpper ? wxT('G') : wxT('g');
753 else
754 m_format += wxT('f');
755 }
756
757 text.Printf(m_format, val);
758
759 }
760 //else: text already contains the string
761
762 return text;
763 }
764
765 void wxGridCellFloatRenderer::Draw(wxGrid& grid,
766 wxGridCellAttr& attr,
767 wxDC& dc,
768 const wxRect& rectCell,
769 int row, int col,
770 bool isSelected)
771 {
772 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
773
774 SetTextColoursAndFont(grid, attr, dc, isSelected);
775
776 // draw the text right aligned by default
777 int hAlign = wxALIGN_RIGHT,
778 vAlign = wxALIGN_INVALID;
779 attr.GetNonDefaultAlignment(&hAlign, &vAlign);
780
781 wxRect rect = rectCell;
782 rect.Inflate(-1);
783
784 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
785 }
786
787 wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid,
788 wxGridCellAttr& attr,
789 wxDC& dc,
790 int row, int col)
791 {
792 return DoGetBestSize(attr, dc, GetString(grid, row, col));
793 }
794
795 void wxGridCellFloatRenderer::SetParameters(const wxString& params)
796 {
797 if ( !params )
798 {
799 // reset to defaults
800 SetWidth(-1);
801 SetPrecision(-1);
802 SetFormat(wxGRID_FLOAT_FORMAT_DEFAULT);
803 }
804 else
805 {
806 wxString rest;
807 wxString tmp = params.BeforeFirst(wxT(','), &rest);
808 if ( !tmp.empty() )
809 {
810 long width;
811 if ( tmp.ToLong(&width) )
812 {
813 SetWidth((int)width);
814 }
815 else
816 {
817 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str());
818 }
819 }
820
821 tmp = rest.BeforeFirst(wxT(','));
822 if ( !tmp.empty() )
823 {
824 long precision;
825 if ( tmp.ToLong(&precision) )
826 {
827 SetPrecision((int)precision);
828 }
829 else
830 {
831 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str());
832 }
833 }
834
835 tmp = rest.AfterFirst(wxT(','));
836 if ( !tmp.empty() )
837 {
838 if ( tmp[0] == wxT('f') )
839 {
840 SetFormat(wxGRID_FLOAT_FORMAT_FIXED);
841 }
842 else if ( tmp[0] == wxT('e') )
843 {
844 SetFormat(wxGRID_FLOAT_FORMAT_SCIENTIFIC);
845 }
846 else if ( tmp[0] == wxT('g') )
847 {
848 SetFormat(wxGRID_FLOAT_FORMAT_COMPACT);
849 }
850 else if ( tmp[0] == wxT('E') )
851 {
852 SetFormat(wxGRID_FLOAT_FORMAT_SCIENTIFIC |
853 wxGRID_FLOAT_FORMAT_UPPER);
854 }
855 else if ( tmp[0] == wxT('F') )
856 {
857 SetFormat(wxGRID_FLOAT_FORMAT_FIXED |
858 wxGRID_FLOAT_FORMAT_UPPER);
859 }
860 else if ( tmp[0] == wxT('G') )
861 {
862 SetFormat(wxGRID_FLOAT_FORMAT_COMPACT |
863 wxGRID_FLOAT_FORMAT_UPPER);
864 }
865 else
866 {
867 wxLogDebug("Invalid wxGridCellFloatRenderer format "
868 "parameter string '%s ignored", params);
869 }
870 }
871 }
872 }
873
874 // ----------------------------------------------------------------------------
875 // wxGridCellBoolRenderer
876 // ----------------------------------------------------------------------------
877
878 wxSize wxGridCellBoolRenderer::ms_sizeCheckMark;
879
880 wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
881 wxGridCellAttr& WXUNUSED(attr),
882 wxDC& WXUNUSED(dc),
883 int WXUNUSED(row),
884 int WXUNUSED(col))
885 {
886 // compute it only once (no locks for MT safeness in GUI thread...)
887 if ( !ms_sizeCheckMark.x )
888 {
889 ms_sizeCheckMark = wxRendererNative::Get().GetCheckBoxSize(&grid);
890 }
891
892 return ms_sizeCheckMark;
893 }
894
895 void wxGridCellBoolRenderer::Draw(wxGrid& grid,
896 wxGridCellAttr& attr,
897 wxDC& dc,
898 const wxRect& rect,
899 int row, int col,
900 bool isSelected)
901 {
902 wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
903
904 // draw a check mark in the centre (ignoring alignment - TODO)
905 wxSize size = GetBestSize(grid, attr, dc, row, col);
906
907 // don't draw outside the cell
908 wxCoord minSize = wxMin(rect.width, rect.height);
909 if ( size.x >= minSize || size.y >= minSize )
910 {
911 // and even leave (at least) 1 pixel margin
912 size.x = size.y = minSize;
913 }
914
915 // draw a border around checkmark
916 int vAlign, hAlign;
917 attr.GetAlignment(&hAlign, &vAlign);
918
919 wxRect rectBorder;
920 if (hAlign == wxALIGN_CENTRE)
921 {
922 rectBorder.x = rect.x + rect.width / 2 - size.x / 2;
923 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
924 rectBorder.width = size.x;
925 rectBorder.height = size.y;
926 }
927 else if (hAlign == wxALIGN_LEFT)
928 {
929 rectBorder.x = rect.x + 2;
930 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
931 rectBorder.width = size.x;
932 rectBorder.height = size.y;
933 }
934 else if (hAlign == wxALIGN_RIGHT)
935 {
936 rectBorder.x = rect.x + rect.width - size.x - 2;
937 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
938 rectBorder.width = size.x;
939 rectBorder.height = size.y;
940 }
941
942 bool value;
943 if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
944 {
945 value = grid.GetTable()->GetValueAsBool(row, col);
946 }
947 else
948 {
949 wxString cellval( grid.GetTable()->GetValue(row, col) );
950 value = wxGridCellBoolEditor::IsTrueValue(cellval);
951 }
952
953 int flags = 0;
954 if (value)
955 flags |= wxCONTROL_CHECKED;
956
957 wxRendererNative::Get().DrawCheckBox( &grid, dc, rectBorder, flags );
958 }
959
960 #endif // wxUSE_GRID
961