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