]> git.saurik.com Git - wxWidgets.git/blame - src/generic/gridctrl.cpp
Fix horizontal mouse wheel scrolling in wxGTK.
[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
85d2dec9
VZ
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
0ec98fd6
VZ
309 wxArrayString physicalLines;
310 for ( wxArrayString::const_iterator it = logicalLines.begin();
311 it != logicalLines.end();
312 ++it )
313 {
314 const wxString& line = *it;
d10f4bf9 315
0ec98fd6
VZ
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
330void
331wxGridCellAutoWrapStringRenderer::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() )
d10f4bf9 342 {
0ec98fd6
VZ
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
7448de8d 352 {
0ec98fd6
VZ
353 // Word does not fit, check whether the word is itself wider that
354 // available width
355 if ( wordWidth < maxWidth )
5c3a7f71 356 {
0ec98fd6
VZ
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;
5c3a7f71 362 }
0ec98fd6 363 else // Word cannot fit in available width at all.
5c3a7f71 364 {
0ec98fd6
VZ
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);
5c3a7f71 374 }
7448de8d 375 }
d10f4bf9 376 }
d10f4bf9 377
0ec98fd6
VZ
378 if ( !line.empty() )
379 lines.push_back(line);
d10f4bf9
VZ
380}
381
382
0ec98fd6
VZ
383wxCoord
384wxGridCellAutoWrapStringRenderer::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
d10f4bf9
VZ
433wxSize
434wxGridCellAutoWrapStringRenderer::GetBestSize(wxGrid& grid,
435 wxGridCellAttr& attr,
436 wxDC& dc,
437 int row, int col)
438{
89653319 439 const int lineHeight = dc.GetCharHeight();
d10f4bf9 440
d10f4bf9 441 // Search for a shape no taller than the golden ratio.
89653319
VZ
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 }
d10f4bf9 451
89653319 452 return size;
d10f4bf9
VZ
453}
454
29efc6e4
FM
455// ----------------------------------------------------------------------------
456// wxGridCellStringRenderer
457// ----------------------------------------------------------------------------
458
459void 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
01a65e7c 469 if ( grid.IsThisEnabled() )
29efc6e4
FM
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
496wxSize 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());
9a83f860 502 wxStringTokenizer tk(text, wxT('\n'));
29efc6e4
FM
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
514wxSize 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
522void 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
625wxString 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 {
9a83f860 631 text.Printf(wxT("%ld"), table->GetValueAsLong(row, col));
29efc6e4
FM
632 }
633 else
634 {
635 text = table->GetValue(row, col);
636 }
637
638 return text;
639}
640
641void 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
cfbc15ee
VZ
653 int hAlign = wxALIGN_RIGHT,
654 vAlign = wxALIGN_INVALID;
655 attr.GetNonDefaultAlignment(&hAlign, &vAlign);
29efc6e4
FM
656
657 wxRect rect = rectCell;
658 rect.Inflate(-1);
659
660 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
661}
662
663wxSize 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
1d8d3cc5
VZ
675wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width,
676 int precision,
677 int format)
29efc6e4
FM
678{
679 SetWidth(width);
680 SetPrecision(precision);
1d8d3cc5 681 SetFormat(format);
29efc6e4
FM
682}
683
684wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
685{
686 wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
687 renderer->m_width = m_width;
688 renderer->m_precision = m_precision;
1d8d3cc5 689 renderer->m_style = m_style;
29efc6e4
FM
690 renderer->m_format = m_format;
691
692 return renderer;
693}
694
695wxString 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
1d8d3cc5 722 m_format = wxT("%");
29efc6e4
FM
723 }
724 else
725 {
1d8d3cc5 726 m_format.Printf(wxT("%%.%d"), m_precision);
29efc6e4
FM
727 }
728 }
729 else if ( m_precision == -1 )
730 {
731 // default precision
1d8d3cc5 732 m_format.Printf(wxT("%%%d."), m_width);
29efc6e4
FM
733 }
734 else
735 {
1d8d3cc5 736 m_format.Printf(wxT("%%%d.%d"), m_width, m_precision);
29efc6e4 737 }
1d8d3cc5
VZ
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');
29efc6e4
FM
746 }
747
748 text.Printf(m_format, val);
749
750 }
751 //else: text already contains the string
752
753 return text;
754}
755
756void 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
cfbc15ee
VZ
768 int hAlign = wxALIGN_RIGHT,
769 vAlign = wxALIGN_INVALID;
770 attr.GetNonDefaultAlignment(&hAlign, &vAlign);
29efc6e4
FM
771
772 wxRect rect = rectCell;
773 rect.Inflate(-1);
774
775 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
776}
777
778wxSize 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
786void wxGridCellFloatRenderer::SetParameters(const wxString& params)
787{
788 if ( !params )
789 {
790 // reset to defaults
791 SetWidth(-1);
792 SetPrecision(-1);
1d8d3cc5 793 SetFormat(wxGRID_FLOAT_FORMAT_DEFAULT);
29efc6e4
FM
794 }
795 else
796 {
1d8d3cc5
VZ
797 wxString rest;
798 wxString tmp = params.BeforeFirst(wxT(','), &rest);
29efc6e4
FM
799 if ( !tmp.empty() )
800 {
801 long width;
802 if ( tmp.ToLong(&width) )
803 {
804 SetWidth((int)width);
805 }
806 else
807 {
9a83f860 808 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str());
29efc6e4
FM
809 }
810 }
811
1d8d3cc5 812 tmp = rest.BeforeFirst(wxT(','));
29efc6e4
FM
813 if ( !tmp.empty() )
814 {
815 long precision;
816 if ( tmp.ToLong(&precision) )
817 {
818 SetPrecision((int)precision);
819 }
820 else
821 {
9a83f860 822 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str());
29efc6e4
FM
823 }
824 }
1d8d3cc5
VZ
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 }
29efc6e4
FM
862 }
863}
864
865// ----------------------------------------------------------------------------
866// wxGridCellBoolRenderer
867// ----------------------------------------------------------------------------
868
869wxSize wxGridCellBoolRenderer::ms_sizeCheckMark;
870
191e43fd 871wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
29efc6e4
FM
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 {
191e43fd 880 ms_sizeCheckMark = wxRendererNative::Get().GetCheckBoxSize(&grid);
29efc6e4
FM
881 }
882
883 return ms_sizeCheckMark;
884}
885
886void 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
3a8c693a
VZ
951#endif // wxUSE_GRID
952