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