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
14 #if wxUSE_GRID
15
16 #include "wx/generic/gridctrl.h"
17 #include "wx/generic/grideditors.h"
18
19 #ifndef WX_PRECOMP
20 #include "wx/textctrl.h"
21 #include "wx/dc.h"
22 #include "wx/combobox.h"
23 #include "wx/settings.h"
24 #include "wx/log.h"
25 #include "wx/checkbox.h"
26 #endif // WX_PRECOMP
27
28 #include "wx/tokenzr.h"
29 #include "wx/renderer.h"
30
31 #include "wx/generic/private/grid.h"
32 #include "wx/private/window.h"
33
34 // ----------------------------------------------------------------------------
35 // wxGridCellRenderer
36 // ----------------------------------------------------------------------------
37
Draw(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,const wxRect & rect,int WXUNUSED (row),int WXUNUSED (col),bool isSelected)38 void wxGridCellRenderer::Draw(wxGrid& grid,
39 wxGridCellAttr& attr,
40 wxDC& dc,
41 const wxRect& rect,
42 int WXUNUSED(row), int WXUNUSED(col),
43 bool isSelected)
44 {
45 dc.SetBackgroundMode( wxBRUSHSTYLE_SOLID );
46
47 wxColour clr;
48 if ( grid.IsThisEnabled() )
49 {
50 if ( isSelected )
51 {
52 if ( grid.HasFocus() )
53 clr = grid.GetSelectionBackground();
54 else
55 clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
56 }
57 else
58 {
59 clr = attr.GetBackgroundColour();
60 }
61 }
62 else // grey out fields if the grid is disabled
63 {
64 clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
65 }
66
67 dc.SetBrush(clr);
68 dc.SetPen( *wxTRANSPARENT_PEN );
69 dc.DrawRectangle(rect);
70 }
71
SetTextColoursAndFont(const wxGrid & grid,const wxGridCellAttr & attr,wxDC & dc,bool isSelected)72 void wxGridCellRenderer::SetTextColoursAndFont(const wxGrid& grid,
73 const wxGridCellAttr& attr,
74 wxDC& dc,
75 bool isSelected)
76 {
77 dc.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT );
78
79 // TODO some special colours for attr.IsReadOnly() case?
80
81 // different coloured text when the grid is disabled
82 if ( grid.IsThisEnabled() )
83 {
84 if ( isSelected )
85 {
86 wxColour clr;
87 if ( grid.HasFocus() )
88 clr = grid.GetSelectionBackground();
89 else
90 clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
91 dc.SetTextBackground( clr );
92 dc.SetTextForeground( grid.GetSelectionForeground() );
93 }
94 else
95 {
96 dc.SetTextBackground( attr.GetBackgroundColour() );
97 dc.SetTextForeground( attr.GetTextColour() );
98 }
99 }
100 else
101 {
102 dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
103 dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
104 }
105
106 dc.SetFont( attr.GetFont() );
107 }
108
109 // ----------------------------------------------------------------------------
110 // wxGridCellDateTimeRenderer
111 // ----------------------------------------------------------------------------
112
113 #if wxUSE_DATETIME
114
115 bool
TryGetValueAsDate(wxDateTime & result,const DateParseParams & params,const wxGrid & grid,int row,int col)116 wxGridPrivate::TryGetValueAsDate(wxDateTime& result,
117 const DateParseParams& params,
118 const wxGrid& grid,
119 int row, int col)
120 {
121 wxGridTableBase *table = grid.GetTable();
122
123 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_DATETIME) )
124 {
125 void * tempval = table->GetValueAsCustom(row, col,wxGRID_VALUE_DATETIME);
126
127 if (tempval)
128 {
129 result = *((wxDateTime *)tempval);
130 delete (wxDateTime *)tempval;
131
132 return true;
133 }
134
135 }
136
137 const wxString text = table->GetValue(row, col);
138
139 wxString::const_iterator end;
140
141 if ( result.ParseFormat(text, params.format, &end) && end == text.end() )
142 return true;
143
144 // Check if we can fall back to free-form parsing, which notably allows us
145 // to parse strings such as "today" or "tomorrow" which would be never
146 // accepted by ParseFormat().
147 if ( params.fallbackParseDate &&
148 result.ParseDate(text, &end) && end == text.end() )
149 return true;
150
151 return false;
152 }
153
154 using namespace wxGridPrivate;
155
156 // Enables a grid cell to display a formatted date
157
wxGridCellDateRenderer(const wxString & outformat)158 wxGridCellDateRenderer::wxGridCellDateRenderer(const wxString& outformat)
159 {
160 if ( outformat.empty() )
161 {
162 m_oformat = "%x"; // Localized date representation.
163 }
164 else
165 {
166 m_oformat = outformat;
167 }
168 m_tz = wxDateTime::Local;
169 }
170
Clone() const171 wxGridCellRenderer *wxGridCellDateRenderer::Clone() const
172 {
173 return new wxGridCellDateRenderer(*this);
174 }
175
GetString(const wxGrid & grid,int row,int col)176 wxString wxGridCellDateRenderer::GetString(const wxGrid& grid, int row, int col)
177 {
178 wxString text;
179
180 DateParseParams params;
181 GetDateParseParams(params);
182
183 wxDateTime val;
184 if ( TryGetValueAsDate(val, params, grid, row, col) )
185 text = val.Format(m_oformat, m_tz );
186
187 // If we failed to parse string just show what we where given?
188 return text;
189 }
190
191 void
GetDateParseParams(DateParseParams & params) const192 wxGridCellDateRenderer::GetDateParseParams(DateParseParams& params) const
193 {
194 params = DateParseParams::WithFallback(m_oformat);
195 }
196
Draw(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,const wxRect & rectCell,int row,int col,bool isSelected)197 void wxGridCellDateRenderer::Draw(wxGrid& grid,
198 wxGridCellAttr& attr,
199 wxDC& dc,
200 const wxRect& rectCell,
201 int row, int col,
202 bool isSelected)
203 {
204 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
205
206 SetTextColoursAndFont(grid, attr, dc, isSelected);
207
208 wxRect rect = rectCell;
209 rect.Inflate(-1);
210
211 // draw the text right aligned by default
212 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, attr,
213 wxALIGN_RIGHT);
214 }
215
GetBestSize(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,int row,int col)216 wxSize wxGridCellDateRenderer::GetBestSize(wxGrid& grid,
217 wxGridCellAttr& attr,
218 wxDC& dc,
219 int row, int col)
220 {
221 return DoGetBestSize(attr, dc, GetString(grid, row, col));
222 }
223
GetMaxBestSize(wxGrid & WXUNUSED (grid),wxGridCellAttr & attr,wxDC & dc)224 wxSize wxGridCellDateRenderer::GetMaxBestSize(wxGrid& WXUNUSED(grid),
225 wxGridCellAttr& attr,
226 wxDC& dc)
227 {
228 wxSize size;
229
230 // Try to produce the longest string in the current format: as we don't
231 // know which month is the longest, we need to try all of them.
232 for ( int m = wxDateTime::Jan; m <= wxDateTime::Dec; ++m )
233 {
234 const wxDateTime d(28, static_cast<wxDateTime::Month>(m), 9999);
235
236 size.IncTo(DoGetBestSize(attr, dc, d.Format(m_oformat, m_tz)));
237 }
238
239 return size;
240 }
241
SetParameters(const wxString & params)242 void wxGridCellDateRenderer::SetParameters(const wxString& params)
243 {
244 if (!params.empty())
245 m_oformat=params;
246 }
247
248
249 // Enables a grid cell to display a formatted date and or time
250
wxGridCellDateTimeRenderer(const wxString & outformat,const wxString & informat)251 wxGridCellDateTimeRenderer::wxGridCellDateTimeRenderer(const wxString& outformat, const wxString& informat)
252 : wxGridCellDateRenderer(outformat)
253 , m_iformat(informat)
254 {
255 }
256
Clone() const257 wxGridCellRenderer *wxGridCellDateTimeRenderer::Clone() const
258 {
259 return new wxGridCellDateTimeRenderer(*this);
260 }
261
262 void
GetDateParseParams(DateParseParams & params) const263 wxGridCellDateTimeRenderer::GetDateParseParams(DateParseParams& params) const
264 {
265 params = DateParseParams::WithoutFallback(m_iformat);
266 }
267
268 #endif // wxUSE_DATETIME
269
270 // ----------------------------------------------------------------------------
271 // wxGridCellChoiceRenderer
272 // ----------------------------------------------------------------------------
273
GetMaxBestSize(wxGrid & WXUNUSED (grid),wxGridCellAttr & attr,wxDC & dc)274 wxSize wxGridCellChoiceRenderer::GetMaxBestSize(wxGrid& WXUNUSED(grid),
275 wxGridCellAttr& attr,
276 wxDC& dc)
277 {
278 wxSize size;
279
280 for ( size_t n = 0; n < m_choices.size(); ++n )
281 {
282 size.IncTo(DoGetBestSize(attr, dc, m_choices[n]));
283 }
284
285 return size;
286 }
287
SetParameters(const wxString & params)288 void wxGridCellChoiceRenderer::SetParameters(const wxString& params)
289 {
290 m_choices.clear();
291
292 if ( params.empty() )
293 return;
294
295 wxStringTokenizer tk(params, wxT(','));
296 while ( tk.HasMoreTokens() )
297 {
298 m_choices.Add(tk.GetNextToken());
299 }
300 }
301
302 // ----------------------------------------------------------------------------
303 // wxGridCellEnumRenderer
304 // ----------------------------------------------------------------------------
305 // Renders a number as a textual equivalent.
306 // eg data in cell is 0,1,2 ... n the cell could be rendered as "John","Fred"..."Bob"
307
308
wxGridCellEnumRenderer(const wxString & choices)309 wxGridCellEnumRenderer::wxGridCellEnumRenderer(const wxString& choices)
310 {
311 if (!choices.empty())
312 SetParameters(choices);
313 }
314
Clone() const315 wxGridCellRenderer *wxGridCellEnumRenderer::Clone() const
316 {
317 wxGridCellEnumRenderer *renderer = new wxGridCellEnumRenderer;
318 renderer->m_choices = m_choices;
319 return renderer;
320 }
321
GetString(const wxGrid & grid,int row,int col)322 wxString wxGridCellEnumRenderer::GetString(const wxGrid& grid, int row, int col)
323 {
324 wxGridTableBase *table = grid.GetTable();
325 wxString text;
326 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
327 {
328 int choiceno = table->GetValueAsLong(row, col);
329 text.Printf(wxT("%s"), m_choices[ choiceno ].c_str() );
330 }
331 else
332 {
333 text = table->GetValue(row, col);
334 }
335
336
337 //If we faild to parse string just show what we where given?
338 return text;
339 }
340
Draw(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,const wxRect & rectCell,int row,int col,bool isSelected)341 void wxGridCellEnumRenderer::Draw(wxGrid& grid,
342 wxGridCellAttr& attr,
343 wxDC& dc,
344 const wxRect& rectCell,
345 int row, int col,
346 bool isSelected)
347 {
348 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
349
350 SetTextColoursAndFont(grid, attr, dc, isSelected);
351
352 wxRect rect = rectCell;
353 rect.Inflate(-1);
354
355 // draw the text right aligned by default
356 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, attr,
357 wxALIGN_RIGHT);
358 }
359
GetBestSize(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,int row,int col)360 wxSize wxGridCellEnumRenderer::GetBestSize(wxGrid& grid,
361 wxGridCellAttr& attr,
362 wxDC& dc,
363 int row, int col)
364 {
365 return DoGetBestSize(attr, dc, GetString(grid, row, col));
366 }
367
368 // ----------------------------------------------------------------------------
369 // wxGridCellAutoWrapStringRenderer
370 // ----------------------------------------------------------------------------
371
372
373 void
Draw(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,const wxRect & rectCell,int row,int col,bool isSelected)374 wxGridCellAutoWrapStringRenderer::Draw(wxGrid& grid,
375 wxGridCellAttr& attr,
376 wxDC& dc,
377 const wxRect& rectCell,
378 int row, int col,
379 bool isSelected) {
380
381
382 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
383
384 // now we only have to draw the text
385 SetTextColoursAndFont(grid, attr, dc, isSelected);
386
387 int horizAlign, vertAlign;
388 attr.GetAlignment(&horizAlign, &vertAlign);
389
390 wxRect rect = rectCell;
391 rect.Inflate(-1);
392
393 // Do not use here the overload taking the attribute, as this would
394 // ellipsize the text, which is never necessary with this renderer.
395 grid.DrawTextRectangle(dc, GetTextLines(grid,dc,attr,rect,row,col),
396 rect, horizAlign, vertAlign);
397 }
398
399
400 wxArrayString
GetTextLines(wxGrid & grid,wxDC & dc,const wxGridCellAttr & attr,const wxRect & rect,int row,int col)401 wxGridCellAutoWrapStringRenderer::GetTextLines(wxGrid& grid,
402 wxDC& dc,
403 const wxGridCellAttr& attr,
404 const wxRect& rect,
405 int row, int col)
406 {
407 dc.SetFont(attr.GetFont());
408 const wxCoord maxWidth = rect.GetWidth();
409
410 // Transform logical lines into physical ones, wrapping the longer ones.
411 const wxArrayString
412 logicalLines = wxSplit(grid.GetCellValue(row, col), '\n', '\0');
413
414 // Trying to do anything if the column is hidden anyhow doesn't make sense
415 // and we run into problems in BreakLine() in this case.
416 if ( maxWidth <= 0 )
417 return logicalLines;
418
419 wxArrayString physicalLines;
420 for ( wxArrayString::const_iterator it = logicalLines.begin();
421 it != logicalLines.end();
422 ++it )
423 {
424 const wxString& line = *it;
425
426 if ( dc.GetTextExtent(line).x > maxWidth )
427 {
428 // Line does not fit, break it up.
429 BreakLine(dc, line, maxWidth, physicalLines);
430 }
431 else // The entire line fits as is
432 {
433 physicalLines.push_back(line);
434 }
435 }
436
437 return physicalLines;
438 }
439
440 void
BreakLine(wxDC & dc,const wxString & logicalLine,wxCoord maxWidth,wxArrayString & lines)441 wxGridCellAutoWrapStringRenderer::BreakLine(wxDC& dc,
442 const wxString& logicalLine,
443 wxCoord maxWidth,
444 wxArrayString& lines)
445 {
446 wxCoord lineWidth = 0;
447 wxString line;
448
449 // For each word
450 wxStringTokenizer wordTokenizer(logicalLine, wxS(" \t"), wxTOKEN_RET_DELIMS);
451 while ( wordTokenizer.HasMoreTokens() )
452 {
453 const wxString word = wordTokenizer.GetNextToken();
454 const wxCoord wordWidth = dc.GetTextExtent(word).x;
455 if ( lineWidth + wordWidth < maxWidth )
456 {
457 // Word fits, just add it to this line.
458 line += word;
459 lineWidth += wordWidth;
460 }
461 else
462 {
463 // Word does not fit, check whether the word is itself wider that
464 // available width
465 if ( wordWidth < maxWidth )
466 {
467 // Word can fit in a new line, put it at the beginning
468 // of the new line.
469 lines.push_back(line);
470 line = word;
471 lineWidth = wordWidth;
472 }
473 else // Word cannot fit in available width at all.
474 {
475 if ( !line.empty() )
476 {
477 lines.push_back(line);
478 line.clear();
479 lineWidth = 0;
480 }
481
482 // Break it up in several lines.
483 lineWidth = BreakWord(dc, word, maxWidth, lines, line);
484 }
485 }
486 }
487
488 if ( !line.empty() )
489 lines.push_back(line);
490 }
491
492
493 wxCoord
BreakWord(wxDC & dc,const wxString & word,wxCoord maxWidth,wxArrayString & lines,wxString & line)494 wxGridCellAutoWrapStringRenderer::BreakWord(wxDC& dc,
495 const wxString& word,
496 wxCoord maxWidth,
497 wxArrayString& lines,
498 wxString& line)
499 {
500 wxArrayInt widths;
501 dc.GetPartialTextExtents(word, widths);
502
503 // TODO: Use binary search to find the first element > maxWidth.
504 const unsigned count = widths.size();
505 unsigned n;
506 for ( n = 0; n < count; n++ )
507 {
508 if ( widths[n] > maxWidth )
509 break;
510 }
511
512 if ( n == 0 )
513 {
514 // This is a degenerate case: the first character of the word is
515 // already wider than the available space, so we just can't show it
516 // completely and have to put the first character in this line.
517 n = 1;
518 }
519
520 lines.push_back(word.substr(0, n));
521
522 // Check if the remainder of the string fits in one line.
523 //
524 // Unfortunately we can't use the existing partial text extents as the
525 // extent of the remainder may be different when it's rendered in a
526 // separate line instead of as part of the same one, so we have to
527 // recompute it.
528 const wxString rest = word.substr(n);
529 const wxCoord restWidth = dc.GetTextExtent(rest).x;
530 if ( restWidth <= maxWidth )
531 {
532 line = rest;
533 return restWidth;
534 }
535
536 // Break the rest of the word into lines.
537 //
538 // TODO: Perhaps avoid recursion? The code is simpler like this but using a
539 // loop in this function would probably be more efficient.
540 return BreakWord(dc, rest, maxWidth, lines, line);
541 }
542
543 wxSize
GetBestSize(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,int row,int col)544 wxGridCellAutoWrapStringRenderer::GetBestSize(wxGrid& grid,
545 wxGridCellAttr& attr,
546 wxDC& dc,
547 int row, int col)
548 {
549 // We have to make a choice here and fix either width or height because we
550 // don't have any naturally best size. This choice is mostly arbitrary, but
551 // we need to be consistent about it, otherwise wxGrid auto-sizing code
552 // would get confused. For now we decide to use a single line of text and
553 // compute the width needed to fully display everything.
554 const int height = dc.GetCharHeight();
555
556 return wxSize(GetBestWidth(grid, attr, dc, row, col, height), height);
557 }
558
559 static const int AUTOWRAP_Y_MARGIN = 4;
560
561 int
GetBestHeight(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,int row,int col,int width)562 wxGridCellAutoWrapStringRenderer::GetBestHeight(wxGrid& grid,
563 wxGridCellAttr& attr,
564 wxDC& dc,
565 int row, int col,
566 int width)
567 {
568 const int lineHeight = dc.GetCharHeight();
569
570 // Use as many lines as we need for this width and add a small border to
571 // improve the appearance.
572 return GetTextLines(grid, dc, attr, wxSize(width, lineHeight),
573 row, col).size() * lineHeight + AUTOWRAP_Y_MARGIN;
574 }
575
576 int
GetBestWidth(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,int row,int col,int height)577 wxGridCellAutoWrapStringRenderer::GetBestWidth(wxGrid& grid,
578 wxGridCellAttr& attr,
579 wxDC& dc,
580 int row, int col,
581 int height)
582 {
583 const int lineHeight = dc.GetCharHeight();
584
585 // Base the maximal number of lines either on how many fit or how many
586 // (new)lines the cell's text contains, whichever results in the most lines.
587 //
588 // It's important to take the newlines into account as GetTextLines() splits
589 // based on them and the number of lines returned can never drop below that,
590 // resulting in the while loop below never exiting if there are already more
591 // lines in the text than can fit in the available height.
592 const size_t maxLines = wxMax(
593 (height - AUTOWRAP_Y_MARGIN)/lineHeight,
594 1 + grid.GetCellValue(row, col).Freq(wxS('\n')));
595
596 // Increase width until all the text fits.
597 //
598 // TODO: this is not the most efficient to do it for the long strings.
599 const int charWidth = dc.GetCharWidth();
600 int width = 2*charWidth;
601 while ( GetTextLines(grid, dc, attr, wxSize(width, height),
602 row, col).size() > maxLines )
603 width += charWidth;
604
605 return width;
606 }
607
608 // ----------------------------------------------------------------------------
609 // wxGridCellStringRenderer
610 // ----------------------------------------------------------------------------
611
DoGetBestSize(const wxGridCellAttr & attr,wxDC & dc,const wxString & text)612 wxSize wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr& attr,
613 wxDC& dc,
614 const wxString& text)
615 {
616 dc.SetFont(attr.GetFont());
617 return dc.GetMultiLineTextExtent(text);
618 }
619
GetBestSize(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,int row,int col)620 wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
621 wxGridCellAttr& attr,
622 wxDC& dc,
623 int row, int col)
624 {
625 return DoGetBestSize(attr, dc, grid.GetCellValue(row, col));
626 }
627
Draw(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,const wxRect & rectCell,int row,int col,bool isSelected)628 void wxGridCellStringRenderer::Draw(wxGrid& grid,
629 wxGridCellAttr& attr,
630 wxDC& dc,
631 const wxRect& rectCell,
632 int row, int col,
633 bool isSelected)
634 {
635 wxRect rect = rectCell;
636 rect.Inflate(-1);
637
638 // erase only this cells background, overflow cells should have been erased
639 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
640
641 if ( attr.CanOverflow() )
642 {
643 int hAlign, vAlign;
644 attr.GetAlignment(&hAlign, &vAlign);
645
646 int overflowCols = 0;
647 int cols = grid.GetNumberCols();
648 int best_width = GetBestSize(grid,attr,dc,row,col).GetWidth();
649 int cell_rows, cell_cols;
650 attr.GetSize( &cell_rows, &cell_cols ); // shouldn't get here if <= 0
651 if ((best_width > rectCell.width) && (col < cols) && grid.GetTable())
652 {
653 int i, c_cols, c_rows;
654 for (i = col+cell_cols; i < cols; i++)
655 {
656 bool is_empty = true;
657 for (int j=row; j < row + cell_rows; j++)
658 {
659 // check w/ anchor cell for multicell block
660 grid.GetCellSize(j, i, &c_rows, &c_cols);
661 if (c_rows > 0)
662 c_rows = 0;
663 if (!grid.GetTable()->IsEmptyCell(j + c_rows, i))
664 {
665 is_empty = false;
666 break;
667 }
668 }
669
670 if (is_empty)
671 {
672 rect.width += grid.GetColSize(i);
673 }
674 else
675 {
676 i--;
677 break;
678 }
679
680 if (rect.width >= best_width)
681 break;
682 }
683
684 overflowCols = i - col - cell_cols + 1;
685 if (overflowCols >= cols)
686 overflowCols = cols - 1;
687 }
688
689 if (overflowCols > 0) // redraw overflow cells w/ proper hilight
690 {
691 hAlign = wxALIGN_LEFT; // if oveflowed then it's left aligned
692 wxRect clip = rect;
693 clip.x += rectCell.width;
694 // draw each overflow cell individually
695 int col_end = col + cell_cols + overflowCols;
696 if (col_end >= grid.GetNumberCols())
697 col_end = grid.GetNumberCols() - 1;
698 for (int i = col + cell_cols; i <= col_end; i++)
699 {
700 // redraw the cell to update the background
701 wxGridCellCoords coords(row, i);
702 grid.DrawCell(dc, coords);
703
704 clip.width = grid.GetColSize(i) - 1;
705 wxDCClipper clipper(dc, clip);
706
707 SetTextColoursAndFont(grid, attr, dc,
708 grid.IsInSelection(row,i));
709
710 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
711 rect, hAlign, vAlign);
712 clip.x += grid.GetColSize(i) - 1;
713 }
714
715 rect = rectCell;
716 rect.Inflate(-1);
717 rect.width++;
718 }
719 }
720
721 // now we only have to draw the text
722 SetTextColoursAndFont(grid, attr, dc, isSelected);
723
724 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
725 rect, attr);
726 }
727
728 // ----------------------------------------------------------------------------
729 // wxGridCellNumberRenderer
730 // ----------------------------------------------------------------------------
731
GetString(const wxGrid & grid,int row,int col)732 wxString wxGridCellNumberRenderer::GetString(const wxGrid& grid, int row, int col)
733 {
734 wxGridTableBase *table = grid.GetTable();
735 wxString text;
736 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
737 {
738 text.Printf(wxT("%ld"), table->GetValueAsLong(row, col));
739 }
740 else
741 {
742 text = table->GetValue(row, col);
743 }
744
745 return text;
746 }
747
Draw(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,const wxRect & rectCell,int row,int col,bool isSelected)748 void wxGridCellNumberRenderer::Draw(wxGrid& grid,
749 wxGridCellAttr& attr,
750 wxDC& dc,
751 const wxRect& rectCell,
752 int row, int col,
753 bool isSelected)
754 {
755 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
756
757 SetTextColoursAndFont(grid, attr, dc, isSelected);
758
759 wxRect rect = rectCell;
760 rect.Inflate(-1);
761
762 // draw the text right aligned by default
763 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, attr,
764 wxALIGN_RIGHT);
765 }
766
GetBestSize(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,int row,int col)767 wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
768 wxGridCellAttr& attr,
769 wxDC& dc,
770 int row, int col)
771 {
772 return DoGetBestSize(attr, dc, GetString(grid, row, col));
773 }
774
GetMaxBestSize(wxGrid & WXUNUSED (grid),wxGridCellAttr & attr,wxDC & dc)775 wxSize wxGridCellNumberRenderer::GetMaxBestSize(wxGrid& WXUNUSED(grid),
776 wxGridCellAttr& attr,
777 wxDC& dc)
778 {
779 // In theory, it's possible that there is a value in min..max range which
780 // is longer than both min and max, e.g. we could conceivably have "88" be
781 // wider than both "87" and "91" with some fonts, but it seems something
782 // too exotic to worry about in practice.
783 wxSize size = DoGetBestSize(attr, dc, wxString::Format("%ld", m_minValue));
784 size.IncTo(DoGetBestSize(attr, dc, wxString::Format("%ld", m_maxValue)));
785
786 return size;
787 }
788
SetParameters(const wxString & params)789 void wxGridCellNumberRenderer::SetParameters(const wxString& params)
790 {
791 if ( params.empty() )
792 return;
793
794 wxString maxStr;
795 const wxString minStr = params.BeforeFirst(',', &maxStr);
796
797 if ( !minStr.ToLong(&m_minValue) || !maxStr.ToLong(&m_maxValue) )
798 {
799 wxLogDebug("Invalid wxGridCellNumberRenderer parameters \"%s\"", params);
800 }
801 }
802
803 // ----------------------------------------------------------------------------
804 // wxGridCellFloatRenderer
805 // ----------------------------------------------------------------------------
806
wxGridCellFloatRenderer(int width,int precision,int format)807 wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width,
808 int precision,
809 int format)
810 {
811 SetWidth(width);
812 SetPrecision(precision);
813 SetFormat(format);
814 }
815
Clone() const816 wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
817 {
818 wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
819 renderer->m_width = m_width;
820 renderer->m_precision = m_precision;
821 renderer->m_style = m_style;
822 renderer->m_format = m_format;
823
824 return renderer;
825 }
826
GetString(const wxGrid & grid,int row,int col)827 wxString wxGridCellFloatRenderer::GetString(const wxGrid& grid, int row, int col)
828 {
829 wxGridTableBase *table = grid.GetTable();
830
831 bool hasDouble;
832 double val;
833 wxString text;
834 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
835 {
836 val = table->GetValueAsDouble(row, col);
837 hasDouble = true;
838 }
839 else
840 {
841 text = table->GetValue(row, col);
842 hasDouble = text.ToDouble(&val);
843 }
844
845 if ( hasDouble )
846 {
847 if ( !m_format )
848 {
849 if ( m_width == -1 )
850 {
851 if ( m_precision == -1 )
852 {
853 // default width/precision
854 m_format = wxT("%");
855 }
856 else
857 {
858 m_format.Printf(wxT("%%.%d"), m_precision);
859 }
860 }
861 else if ( m_precision == -1 )
862 {
863 // default precision
864 m_format.Printf(wxT("%%%d."), m_width);
865 }
866 else
867 {
868 m_format.Printf(wxT("%%%d.%d"), m_width, m_precision);
869 }
870
871 bool isUpper = ( ( m_style & wxGRID_FLOAT_FORMAT_UPPER ) == wxGRID_FLOAT_FORMAT_UPPER);
872 if ( ( m_style & wxGRID_FLOAT_FORMAT_SCIENTIFIC ) == wxGRID_FLOAT_FORMAT_SCIENTIFIC)
873 m_format += isUpper ? wxT('E') : wxT('e');
874 else if ( ( m_style & wxGRID_FLOAT_FORMAT_COMPACT ) == wxGRID_FLOAT_FORMAT_COMPACT)
875 m_format += isUpper ? wxT('G') : wxT('g');
876 else
877 m_format += wxT('f');
878 }
879
880 text.Printf(m_format, val);
881
882 }
883 //else: text already contains the string
884
885 return text;
886 }
887
Draw(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,const wxRect & rectCell,int row,int col,bool isSelected)888 void wxGridCellFloatRenderer::Draw(wxGrid& grid,
889 wxGridCellAttr& attr,
890 wxDC& dc,
891 const wxRect& rectCell,
892 int row, int col,
893 bool isSelected)
894 {
895 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
896
897 SetTextColoursAndFont(grid, attr, dc, isSelected);
898
899 wxRect rect = rectCell;
900 rect.Inflate(-1);
901
902 // draw the text right aligned by default
903 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, attr,
904 wxALIGN_RIGHT);
905 }
906
GetBestSize(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,int row,int col)907 wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid,
908 wxGridCellAttr& attr,
909 wxDC& dc,
910 int row, int col)
911 {
912 return DoGetBestSize(attr, dc, GetString(grid, row, col));
913 }
914
SetParameters(const wxString & params)915 void wxGridCellFloatRenderer::SetParameters(const wxString& params)
916 {
917 if ( !params )
918 {
919 // reset to defaults
920 SetWidth(-1);
921 SetPrecision(-1);
922 SetFormat(wxGRID_FLOAT_FORMAT_DEFAULT);
923 }
924 else
925 {
926 wxString rest;
927 wxString tmp = params.BeforeFirst(wxT(','), &rest);
928 if ( !tmp.empty() )
929 {
930 long width;
931 if ( tmp.ToLong(&width) )
932 {
933 SetWidth((int)width);
934 }
935 else
936 {
937 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str());
938 }
939 }
940
941 tmp = rest.BeforeFirst(wxT(','));
942 if ( !tmp.empty() )
943 {
944 long precision;
945 if ( tmp.ToLong(&precision) )
946 {
947 SetPrecision((int)precision);
948 }
949 else
950 {
951 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str());
952 }
953 }
954
955 tmp = rest.AfterFirst(wxT(','));
956 if ( !tmp.empty() )
957 {
958 if ( tmp[0] == wxT('f') )
959 {
960 SetFormat(wxGRID_FLOAT_FORMAT_FIXED);
961 }
962 else if ( tmp[0] == wxT('e') )
963 {
964 SetFormat(wxGRID_FLOAT_FORMAT_SCIENTIFIC);
965 }
966 else if ( tmp[0] == wxT('g') )
967 {
968 SetFormat(wxGRID_FLOAT_FORMAT_COMPACT);
969 }
970 else if ( tmp[0] == wxT('E') )
971 {
972 SetFormat(wxGRID_FLOAT_FORMAT_SCIENTIFIC |
973 wxGRID_FLOAT_FORMAT_UPPER);
974 }
975 else if ( tmp[0] == wxT('F') )
976 {
977 SetFormat(wxGRID_FLOAT_FORMAT_FIXED |
978 wxGRID_FLOAT_FORMAT_UPPER);
979 }
980 else if ( tmp[0] == wxT('G') )
981 {
982 SetFormat(wxGRID_FLOAT_FORMAT_COMPACT |
983 wxGRID_FLOAT_FORMAT_UPPER);
984 }
985 else
986 {
987 wxLogDebug("Invalid wxGridCellFloatRenderer format "
988 "parameter string '%s ignored", params);
989 }
990 }
991 }
992 }
993
994 // ----------------------------------------------------------------------------
995 // wxGridCellBoolRenderer
996 // ----------------------------------------------------------------------------
997
GetBestSize(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,int WXUNUSED (row),int WXUNUSED (col))998 wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
999 wxGridCellAttr& attr,
1000 wxDC& dc,
1001 int WXUNUSED(row),
1002 int WXUNUSED(col))
1003 {
1004 return GetMaxBestSize(grid, attr, dc);
1005 }
1006
GetMaxBestSize(wxGrid & grid,wxGridCellAttr & WXUNUSED (attr),wxDC & WXUNUSED (dc))1007 wxSize wxGridCellBoolRenderer::GetMaxBestSize(wxGrid& grid,
1008 wxGridCellAttr& WXUNUSED(attr),
1009 wxDC& WXUNUSED(dc))
1010 {
1011 static wxPrivate::DpiDependentValue<wxSize> s_sizeCheckMark;
1012
1013 // Get the check mark size in pixels if it hadn't been done yet or if the
1014 // DPI has changed.
1015 if ( s_sizeCheckMark.HasChanged(&grid) )
1016 {
1017 s_sizeCheckMark.SetAtNewDPI
1018 (
1019 wxRendererNative::Get().GetCheckBoxSize(&grid, wxCONTROL_CELL)
1020 );
1021 }
1022
1023 return s_sizeCheckMark.Get();
1024 }
1025
Draw(wxGrid & grid,wxGridCellAttr & attr,wxDC & dc,const wxRect & rect,int row,int col,bool isSelected)1026 void wxGridCellBoolRenderer::Draw(wxGrid& grid,
1027 wxGridCellAttr& attr,
1028 wxDC& dc,
1029 const wxRect& rect,
1030 int row, int col,
1031 bool isSelected)
1032 {
1033 wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
1034
1035 int hAlign = wxALIGN_LEFT;
1036 int vAlign = wxALIGN_CENTRE_VERTICAL;
1037 attr.GetNonDefaultAlignment(&hAlign, &vAlign);
1038
1039 const wxRect checkBoxRect =
1040 wxGetContentRect(GetBestSize(grid, attr, dc, row, col),
1041 rect, hAlign, vAlign);
1042
1043 bool value;
1044 if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
1045 {
1046 value = grid.GetTable()->GetValueAsBool(row, col);
1047 }
1048 else
1049 {
1050 wxString cellval( grid.GetTable()->GetValue(row, col) );
1051 value = wxGridCellBoolEditor::IsTrueValue(cellval);
1052 }
1053
1054 int flags = wxCONTROL_CELL;
1055 if (value)
1056 flags |= wxCONTROL_CHECKED;
1057
1058 wxRendererNative::Get().DrawCheckBox( &grid, dc, checkBoxRect, flags );
1059 }
1060
1061 #endif // wxUSE_GRID
1062
1063