Simplify wxGridCellAutoWrapStringRenderer::GetBestSize().
[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 const int lineHeight = dc.GetCharHeight();
440
441 // Search for a shape no taller than the golden ratio.
442 wxSize size;
443 for ( size.x = 10; ; size.x += 10 )
444 {
445 const size_t
446 numLines = GetTextLines(grid, dc, attr, size, row, col).size();
447 size.y = numLines * lineHeight;
448 if ( size.x >= size.y*1.68 )
449 break;
450 }
451
452 return size;
453 }
454
455 // ----------------------------------------------------------------------------
456 // wxGridCellStringRenderer
457 // ----------------------------------------------------------------------------
458
459 void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid& grid,
460 const wxGridCellAttr& attr,
461 wxDC& dc,
462 bool isSelected)
463 {
464 dc.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT );
465
466 // TODO some special colours for attr.IsReadOnly() case?
467
468 // different coloured text when the grid is disabled
469 if ( grid.IsThisEnabled() )
470 {
471 if ( isSelected )
472 {
473 wxColour clr;
474 if ( grid.HasFocus() )
475 clr = grid.GetSelectionBackground();
476 else
477 clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
478 dc.SetTextBackground( clr );
479 dc.SetTextForeground( grid.GetSelectionForeground() );
480 }
481 else
482 {
483 dc.SetTextBackground( attr.GetBackgroundColour() );
484 dc.SetTextForeground( attr.GetTextColour() );
485 }
486 }
487 else
488 {
489 dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
490 dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
491 }
492
493 dc.SetFont( attr.GetFont() );
494 }
495
496 wxSize wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr& attr,
497 wxDC& dc,
498 const wxString& text)
499 {
500 wxCoord x = 0, y = 0, max_x = 0;
501 dc.SetFont(attr.GetFont());
502 wxStringTokenizer tk(text, wxT('\n'));
503 while ( tk.HasMoreTokens() )
504 {
505 dc.GetTextExtent(tk.GetNextToken(), &x, &y);
506 max_x = wxMax(max_x, x);
507 }
508
509 y *= 1 + text.Freq(wxT('\n')); // multiply by the number of lines.
510
511 return wxSize(max_x, y);
512 }
513
514 wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
515 wxGridCellAttr& attr,
516 wxDC& dc,
517 int row, int col)
518 {
519 return DoGetBestSize(attr, dc, grid.GetCellValue(row, col));
520 }
521
522 void wxGridCellStringRenderer::Draw(wxGrid& grid,
523 wxGridCellAttr& attr,
524 wxDC& dc,
525 const wxRect& rectCell,
526 int row, int col,
527 bool isSelected)
528 {
529 wxRect rect = rectCell;
530 rect.Inflate(-1);
531
532 // erase only this cells background, overflow cells should have been erased
533 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
534
535 int hAlign, vAlign;
536 attr.GetAlignment(&hAlign, &vAlign);
537
538 int overflowCols = 0;
539
540 if (attr.GetOverflow())
541 {
542 int cols = grid.GetNumberCols();
543 int best_width = GetBestSize(grid,attr,dc,row,col).GetWidth();
544 int cell_rows, cell_cols;
545 attr.GetSize( &cell_rows, &cell_cols ); // shouldn't get here if <= 0
546 if ((best_width > rectCell.width) && (col < cols) && grid.GetTable())
547 {
548 int i, c_cols, c_rows;
549 for (i = col+cell_cols; i < cols; i++)
550 {
551 bool is_empty = true;
552 for (int j=row; j < row + cell_rows; j++)
553 {
554 // check w/ anchor cell for multicell block
555 grid.GetCellSize(j, i, &c_rows, &c_cols);
556 if (c_rows > 0)
557 c_rows = 0;
558 if (!grid.GetTable()->IsEmptyCell(j + c_rows, i))
559 {
560 is_empty = false;
561 break;
562 }
563 }
564
565 if (is_empty)
566 {
567 rect.width += grid.GetColSize(i);
568 }
569 else
570 {
571 i--;
572 break;
573 }
574
575 if (rect.width >= best_width)
576 break;
577 }
578
579 overflowCols = i - col - cell_cols + 1;
580 if (overflowCols >= cols)
581 overflowCols = cols - 1;
582 }
583
584 if (overflowCols > 0) // redraw overflow cells w/ proper hilight
585 {
586 hAlign = wxALIGN_LEFT; // if oveflowed then it's left aligned
587 wxRect clip = rect;
588 clip.x += rectCell.width;
589 // draw each overflow cell individually
590 int col_end = col + cell_cols + overflowCols;
591 if (col_end >= grid.GetNumberCols())
592 col_end = grid.GetNumberCols() - 1;
593 for (int i = col + cell_cols; i <= col_end; i++)
594 {
595 clip.width = grid.GetColSize(i) - 1;
596 dc.DestroyClippingRegion();
597 dc.SetClippingRegion(clip);
598
599 SetTextColoursAndFont(grid, attr, dc,
600 grid.IsInSelection(row,i));
601
602 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
603 rect, hAlign, vAlign);
604 clip.x += grid.GetColSize(i) - 1;
605 }
606
607 rect = rectCell;
608 rect.Inflate(-1);
609 rect.width++;
610 dc.DestroyClippingRegion();
611 }
612 }
613
614 // now we only have to draw the text
615 SetTextColoursAndFont(grid, attr, dc, isSelected);
616
617 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
618 rect, hAlign, vAlign);
619 }
620
621 // ----------------------------------------------------------------------------
622 // wxGridCellNumberRenderer
623 // ----------------------------------------------------------------------------
624
625 wxString wxGridCellNumberRenderer::GetString(const wxGrid& grid, int row, int col)
626 {
627 wxGridTableBase *table = grid.GetTable();
628 wxString text;
629 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
630 {
631 text.Printf(wxT("%ld"), table->GetValueAsLong(row, col));
632 }
633 else
634 {
635 text = table->GetValue(row, col);
636 }
637
638 return text;
639 }
640
641 void wxGridCellNumberRenderer::Draw(wxGrid& grid,
642 wxGridCellAttr& attr,
643 wxDC& dc,
644 const wxRect& rectCell,
645 int row, int col,
646 bool isSelected)
647 {
648 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
649
650 SetTextColoursAndFont(grid, attr, dc, isSelected);
651
652 // draw the text right aligned by default
653 int hAlign = wxALIGN_RIGHT,
654 vAlign = wxALIGN_INVALID;
655 attr.GetNonDefaultAlignment(&hAlign, &vAlign);
656
657 wxRect rect = rectCell;
658 rect.Inflate(-1);
659
660 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
661 }
662
663 wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
664 wxGridCellAttr& attr,
665 wxDC& dc,
666 int row, int col)
667 {
668 return DoGetBestSize(attr, dc, GetString(grid, row, col));
669 }
670
671 // ----------------------------------------------------------------------------
672 // wxGridCellFloatRenderer
673 // ----------------------------------------------------------------------------
674
675 wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width,
676 int precision,
677 int format)
678 {
679 SetWidth(width);
680 SetPrecision(precision);
681 SetFormat(format);
682 }
683
684 wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
685 {
686 wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
687 renderer->m_width = m_width;
688 renderer->m_precision = m_precision;
689 renderer->m_style = m_style;
690 renderer->m_format = m_format;
691
692 return renderer;
693 }
694
695 wxString wxGridCellFloatRenderer::GetString(const wxGrid& grid, int row, int col)
696 {
697 wxGridTableBase *table = grid.GetTable();
698
699 bool hasDouble;
700 double val;
701 wxString text;
702 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
703 {
704 val = table->GetValueAsDouble(row, col);
705 hasDouble = true;
706 }
707 else
708 {
709 text = table->GetValue(row, col);
710 hasDouble = text.ToDouble(&val);
711 }
712
713 if ( hasDouble )
714 {
715 if ( !m_format )
716 {
717 if ( m_width == -1 )
718 {
719 if ( m_precision == -1 )
720 {
721 // default width/precision
722 m_format = wxT("%");
723 }
724 else
725 {
726 m_format.Printf(wxT("%%.%d"), m_precision);
727 }
728 }
729 else if ( m_precision == -1 )
730 {
731 // default precision
732 m_format.Printf(wxT("%%%d."), m_width);
733 }
734 else
735 {
736 m_format.Printf(wxT("%%%d.%d"), m_width, m_precision);
737 }
738
739 bool isUpper = ( ( m_style & wxGRID_FLOAT_FORMAT_UPPER ) == wxGRID_FLOAT_FORMAT_UPPER);
740 if ( ( m_style & wxGRID_FLOAT_FORMAT_SCIENTIFIC ) == wxGRID_FLOAT_FORMAT_SCIENTIFIC)
741 m_format += isUpper ? wxT('E') : wxT('e');
742 else if ( ( m_style & wxGRID_FLOAT_FORMAT_COMPACT ) == wxGRID_FLOAT_FORMAT_COMPACT)
743 m_format += isUpper ? wxT('G') : wxT('g');
744 else
745 m_format += wxT('f');
746 }
747
748 text.Printf(m_format, val);
749
750 }
751 //else: text already contains the string
752
753 return text;
754 }
755
756 void wxGridCellFloatRenderer::Draw(wxGrid& grid,
757 wxGridCellAttr& attr,
758 wxDC& dc,
759 const wxRect& rectCell,
760 int row, int col,
761 bool isSelected)
762 {
763 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
764
765 SetTextColoursAndFont(grid, attr, dc, isSelected);
766
767 // draw the text right aligned by default
768 int hAlign = wxALIGN_RIGHT,
769 vAlign = wxALIGN_INVALID;
770 attr.GetNonDefaultAlignment(&hAlign, &vAlign);
771
772 wxRect rect = rectCell;
773 rect.Inflate(-1);
774
775 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
776 }
777
778 wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid,
779 wxGridCellAttr& attr,
780 wxDC& dc,
781 int row, int col)
782 {
783 return DoGetBestSize(attr, dc, GetString(grid, row, col));
784 }
785
786 void wxGridCellFloatRenderer::SetParameters(const wxString& params)
787 {
788 if ( !params )
789 {
790 // reset to defaults
791 SetWidth(-1);
792 SetPrecision(-1);
793 SetFormat(wxGRID_FLOAT_FORMAT_DEFAULT);
794 }
795 else
796 {
797 wxString rest;
798 wxString tmp = params.BeforeFirst(wxT(','), &rest);
799 if ( !tmp.empty() )
800 {
801 long width;
802 if ( tmp.ToLong(&width) )
803 {
804 SetWidth((int)width);
805 }
806 else
807 {
808 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str());
809 }
810 }
811
812 tmp = rest.BeforeFirst(wxT(','));
813 if ( !tmp.empty() )
814 {
815 long precision;
816 if ( tmp.ToLong(&precision) )
817 {
818 SetPrecision((int)precision);
819 }
820 else
821 {
822 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str());
823 }
824 }
825
826 tmp = rest.AfterFirst(wxT(','));
827 if ( !tmp.empty() )
828 {
829 if ( tmp[0] == wxT('f') )
830 {
831 SetFormat(wxGRID_FLOAT_FORMAT_FIXED);
832 }
833 else if ( tmp[0] == wxT('e') )
834 {
835 SetFormat(wxGRID_FLOAT_FORMAT_SCIENTIFIC);
836 }
837 else if ( tmp[0] == wxT('g') )
838 {
839 SetFormat(wxGRID_FLOAT_FORMAT_COMPACT);
840 }
841 else if ( tmp[0] == wxT('E') )
842 {
843 SetFormat(wxGRID_FLOAT_FORMAT_SCIENTIFIC |
844 wxGRID_FLOAT_FORMAT_UPPER);
845 }
846 else if ( tmp[0] == wxT('F') )
847 {
848 SetFormat(wxGRID_FLOAT_FORMAT_FIXED |
849 wxGRID_FLOAT_FORMAT_UPPER);
850 }
851 else if ( tmp[0] == wxT('G') )
852 {
853 SetFormat(wxGRID_FLOAT_FORMAT_COMPACT |
854 wxGRID_FLOAT_FORMAT_UPPER);
855 }
856 else
857 {
858 wxLogDebug("Invalid wxGridCellFloatRenderer format "
859 "parameter string '%s ignored", params);
860 }
861 }
862 }
863 }
864
865 // ----------------------------------------------------------------------------
866 // wxGridCellBoolRenderer
867 // ----------------------------------------------------------------------------
868
869 wxSize wxGridCellBoolRenderer::ms_sizeCheckMark;
870
871 wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
872 wxGridCellAttr& WXUNUSED(attr),
873 wxDC& WXUNUSED(dc),
874 int WXUNUSED(row),
875 int WXUNUSED(col))
876 {
877 // compute it only once (no locks for MT safeness in GUI thread...)
878 if ( !ms_sizeCheckMark.x )
879 {
880 ms_sizeCheckMark = wxRendererNative::Get().GetCheckBoxSize(&grid);
881 }
882
883 return ms_sizeCheckMark;
884 }
885
886 void wxGridCellBoolRenderer::Draw(wxGrid& grid,
887 wxGridCellAttr& attr,
888 wxDC& dc,
889 const wxRect& rect,
890 int row, int col,
891 bool isSelected)
892 {
893 wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
894
895 // draw a check mark in the centre (ignoring alignment - TODO)
896 wxSize size = GetBestSize(grid, attr, dc, row, col);
897
898 // don't draw outside the cell
899 wxCoord minSize = wxMin(rect.width, rect.height);
900 if ( size.x >= minSize || size.y >= minSize )
901 {
902 // and even leave (at least) 1 pixel margin
903 size.x = size.y = minSize;
904 }
905
906 // draw a border around checkmark
907 int vAlign, hAlign;
908 attr.GetAlignment(&hAlign, &vAlign);
909
910 wxRect rectBorder;
911 if (hAlign == wxALIGN_CENTRE)
912 {
913 rectBorder.x = rect.x + rect.width / 2 - size.x / 2;
914 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
915 rectBorder.width = size.x;
916 rectBorder.height = size.y;
917 }
918 else if (hAlign == wxALIGN_LEFT)
919 {
920 rectBorder.x = rect.x + 2;
921 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
922 rectBorder.width = size.x;
923 rectBorder.height = size.y;
924 }
925 else if (hAlign == wxALIGN_RIGHT)
926 {
927 rectBorder.x = rect.x + rect.width - size.x - 2;
928 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
929 rectBorder.width = size.x;
930 rectBorder.height = size.y;
931 }
932
933 bool value;
934 if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
935 {
936 value = grid.GetTable()->GetValueAsBool(row, col);
937 }
938 else
939 {
940 wxString cellval( grid.GetTable()->GetValue(row, col) );
941 value = wxGridCellBoolEditor::IsTrueValue(cellval);
942 }
943
944 int flags = 0;
945 if (value)
946 flags |= wxCONTROL_CHECKED;
947
948 wxRendererNative::Get().DrawCheckBox( &grid, dc, rectBorder, flags );
949 }
950
951 #endif // wxUSE_GRID
952