1 /////////////////////////////////////////////////////////////////////////// 
   2 // Name:        generic/gridctrl.cpp 
   3 // Purpose:     wxGrid controls 
   4 // Author:      Paul Gammans, Roger Gammans 
   8 // Copyright:   (c) The Computer Surgery (paul@compsurg.co.uk) 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 #include "wx/wxprec.h" 
  20 #include "wx/generic/gridctrl.h" 
  21 #include "wx/generic/grideditors.h" 
  24     #include "wx/textctrl.h" 
  26     #include "wx/combobox.h" 
  27         #include "wx/settings.h" 
  29     #include "wx/checkbox.h" 
  32 #include "wx/tokenzr.h" 
  33 #include "wx/renderer.h" 
  35 // ---------------------------------------------------------------------------- 
  36 // wxGridCellDateTimeRenderer 
  37 // ---------------------------------------------------------------------------- 
  41 // Enables a grid cell to display a formatted date and or time 
  43 wxGridCellDateTimeRenderer::wxGridCellDateTimeRenderer(const wxString
& outformat
, const wxString
& informat
) 
  46     m_oformat 
= outformat
; 
  47     m_tz 
= wxDateTime::Local
; 
  48     m_dateDef 
= wxDefaultDateTime
; 
  51 wxGridCellRenderer 
*wxGridCellDateTimeRenderer::Clone() const 
  53     wxGridCellDateTimeRenderer 
*renderer 
= new wxGridCellDateTimeRenderer
; 
  54     renderer
->m_iformat 
= m_iformat
; 
  55     renderer
->m_oformat 
= m_oformat
; 
  56     renderer
->m_dateDef 
= m_dateDef
; 
  57     renderer
->m_tz 
= m_tz
; 
  62 wxString 
wxGridCellDateTimeRenderer::GetString(const wxGrid
& grid
, int row
, int col
) 
  64     wxGridTableBase 
*table 
= grid
.GetTable(); 
  66     bool hasDatetime 
= false; 
  69     if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_DATETIME
) ) 
  71         void * tempval 
= table
->GetValueAsCustom(row
, col
,wxGRID_VALUE_DATETIME
); 
  75             val 
= *((wxDateTime 
*)tempval
); 
  77             delete (wxDateTime 
*)tempval
; 
  84         text 
= table
->GetValue(row
, col
); 
  85         const char * const end 
= val
.ParseFormat(text
, m_iformat
, m_dateDef
); 
  86         hasDatetime 
= end 
&& !*end
; 
  90         text 
= val
.Format(m_oformat
, m_tz 
); 
  92     // If we failed to parse string just show what we where given? 
  96 void wxGridCellDateTimeRenderer::Draw(wxGrid
& grid
, 
  99                                    const wxRect
& rectCell
, 
 103     wxGridCellRenderer::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
); 
 105     SetTextColoursAndFont(grid
, attr
, dc
, isSelected
); 
 107     // draw the text right aligned by default 
 109     attr
.GetAlignment(&hAlign
, &vAlign
); 
 112     wxRect rect 
= rectCell
; 
 115     grid
.DrawTextRectangle(dc
, GetString(grid
, row
, col
), rect
, hAlign
, vAlign
); 
 118 wxSize 
wxGridCellDateTimeRenderer::GetBestSize(wxGrid
& grid
, 
 119                                             wxGridCellAttr
& attr
, 
 123     return DoGetBestSize(attr
, dc
, GetString(grid
, row
, col
)); 
 126 void wxGridCellDateTimeRenderer::SetParameters(const wxString
& params
) 
 132 #endif // wxUSE_DATETIME 
 134 // ---------------------------------------------------------------------------- 
 135 // wxGridCellChoiceNumberRenderer 
 136 // ---------------------------------------------------------------------------- 
 137 // Renders a number as a textual equivalent. 
 138 // eg data in cell is 0,1,2 ... n the cell could be rendered as "John","Fred"..."Bob" 
 141 wxGridCellEnumRenderer::wxGridCellEnumRenderer(const wxString
& choices
) 
 143     if (!choices
.empty()) 
 144         SetParameters(choices
); 
 147 wxGridCellRenderer 
*wxGridCellEnumRenderer::Clone() const 
 149     wxGridCellEnumRenderer 
*renderer 
= new wxGridCellEnumRenderer
; 
 150     renderer
->m_choices 
= m_choices
; 
 154 wxString 
wxGridCellEnumRenderer::GetString(const wxGrid
& grid
, int row
, int col
) 
 156     wxGridTableBase 
*table 
= grid
.GetTable(); 
 158     if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) ) 
 160         int choiceno 
= table
->GetValueAsLong(row
, col
); 
 161         text
.Printf(_T("%s"), m_choices
[ choiceno 
].c_str() ); 
 165         text 
= table
->GetValue(row
, col
); 
 169     //If we faild to parse string just show what we where given? 
 173 void wxGridCellEnumRenderer::Draw(wxGrid
& grid
, 
 174                                    wxGridCellAttr
& attr
, 
 176                                    const wxRect
& rectCell
, 
 180     wxGridCellRenderer::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
); 
 182     SetTextColoursAndFont(grid
, attr
, dc
, isSelected
); 
 184     // draw the text right aligned by default 
 186     attr
.GetAlignment(&hAlign
, &vAlign
); 
 189     wxRect rect 
= rectCell
; 
 192     grid
.DrawTextRectangle(dc
, GetString(grid
, row
, col
), rect
, hAlign
, vAlign
); 
 195 wxSize 
wxGridCellEnumRenderer::GetBestSize(wxGrid
& grid
, 
 196                                             wxGridCellAttr
& attr
, 
 200     return DoGetBestSize(attr
, dc
, GetString(grid
, row
, col
)); 
 203 void wxGridCellEnumRenderer::SetParameters(const wxString
& params
) 
 213     wxStringTokenizer 
tk(params
, _T(',')); 
 214     while ( tk
.HasMoreTokens() ) 
 216         m_choices
.Add(tk
.GetNextToken()); 
 221 // ---------------------------------------------------------------------------- 
 222 // wxGridCellAutoWrapStringRenderer 
 223 // ---------------------------------------------------------------------------- 
 227 wxGridCellAutoWrapStringRenderer::Draw(wxGrid
& grid
, 
 228                       wxGridCellAttr
& attr
, 
 230                       const wxRect
& rectCell
, 
 235     wxGridCellRenderer::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
); 
 237     // now we only have to draw the text 
 238     SetTextColoursAndFont(grid
, attr
, dc
, isSelected
); 
 240     int horizAlign
, vertAlign
; 
 241     attr
.GetAlignment(&horizAlign
, &vertAlign
); 
 243     wxRect rect 
= rectCell
; 
 246     grid
.DrawTextRectangle(dc
, GetTextLines(grid
,dc
,attr
,rect
,row
,col
), 
 247                            rect
, horizAlign
, vertAlign
); 
 252 wxGridCellAutoWrapStringRenderer::GetTextLines(wxGrid
& grid
, 
 254                                                const wxGridCellAttr
& attr
, 
 258     wxString  data 
= grid
.GetCellValue(row
, col
); 
 261     dc
.SetFont(attr
.GetFont()); 
 263     //Taken from wxGrid again! 
 264     wxCoord x 
= 0, y 
= 0, curr_x 
= 0; 
 265     wxCoord max_x 
= rect
.GetWidth(); 
 267     dc
.SetFont(attr
.GetFont()); 
 268     wxStringTokenizer 
tk(data 
, _T(" \n\t\r")); 
 269     wxString thisline 
= wxEmptyString
; 
 271     while ( tk
.HasMoreTokens() ) 
 273         wxString tok 
= tk
.GetNextToken(); 
 274         //FIXME: this causes us to print an extra unnecesary 
 275         //       space at the end of the line. But it 
 276         //       is invisible , simplifies the size calculation 
 277         //       and ensures tokens are separated in the display 
 280         dc
.GetTextExtent(tok
, &x
, &y
); 
 281         if ( curr_x 
+ x 
> max_x
) 
 283             lines
.Add( wxString(thisline
) ); 
 294     lines
.Add( wxString(thisline
) ); 
 301 wxGridCellAutoWrapStringRenderer::GetBestSize(wxGrid
& grid
, 
 302                                               wxGridCellAttr
& attr
, 
 306     wxCoord x
,y
, height 
, width 
= grid
.GetColSize(col
) -20; 
 307     // for width, subtract 20 because ColSize includes a magin of 10 pixels 
 308     // that we do not want here and because we always start with an increment 
 309     // by 10 in the loop below. 
 310     int count 
= 250; //Limit iterations.. 
 312     wxRect 
rect(0,0,width
,10); 
 314     // M is a nice large character 'y' gives descender!. 
 315     dc
.GetTextExtent(wxT("My"), &x
, &y
); 
 320         rect
.SetWidth(width
); 
 321         height 
= y 
* (wx_truncate_cast(wxCoord
, GetTextLines(grid
,dc
,attr
,rect
,row
,col
).GetCount())); 
 323     // Search for a shape no taller than the golden ratio. 
 324     } while (count 
&& (width  
< (height
*1.68)) ); 
 327     return wxSize(width
,height
); 
 331 // ---------------------------------------------------------------------------- 
 332 // wxGridCellRenderer 
 333 // ---------------------------------------------------------------------------- 
 335 void wxGridCellRenderer::Draw(wxGrid
& grid
, 
 336                               wxGridCellAttr
& attr
, 
 339                               int WXUNUSED(row
), int WXUNUSED(col
), 
 342     dc
.SetBackgroundMode( wxBRUSHSTYLE_SOLID 
); 
 345     if ( grid
.IsEnabled() ) 
 349             if ( grid
.HasFocus() ) 
 350                 clr 
= grid
.GetSelectionBackground(); 
 352                 clr 
= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW
); 
 356             clr 
= attr
.GetBackgroundColour(); 
 359     else // grey out fields if the grid is disabled 
 361         clr 
= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
); 
 365     dc
.SetPen( *wxTRANSPARENT_PEN 
); 
 366     dc
.DrawRectangle(rect
); 
 369 // ---------------------------------------------------------------------------- 
 370 // wxGridCellStringRenderer 
 371 // ---------------------------------------------------------------------------- 
 373 void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid
& grid
, 
 374                                                      const wxGridCellAttr
& attr
, 
 378     dc
.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT 
); 
 380     // TODO some special colours for attr.IsReadOnly() case? 
 382     // different coloured text when the grid is disabled 
 383     if ( grid
.IsEnabled() ) 
 388             if ( grid
.HasFocus() ) 
 389                 clr 
= grid
.GetSelectionBackground(); 
 391                 clr 
= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW
); 
 392             dc
.SetTextBackground( clr 
); 
 393             dc
.SetTextForeground( grid
.GetSelectionForeground() ); 
 397             dc
.SetTextBackground( attr
.GetBackgroundColour() ); 
 398             dc
.SetTextForeground( attr
.GetTextColour() ); 
 403         dc
.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)); 
 404         dc
.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT
)); 
 407     dc
.SetFont( attr
.GetFont() ); 
 410 wxSize 
wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr
& attr
, 
 412                                                const wxString
& text
) 
 414     wxCoord x 
= 0, y 
= 0, max_x 
= 0; 
 415     dc
.SetFont(attr
.GetFont()); 
 416     wxStringTokenizer 
tk(text
, _T('\n')); 
 417     while ( tk
.HasMoreTokens() ) 
 419         dc
.GetTextExtent(tk
.GetNextToken(), &x
, &y
); 
 420         max_x 
= wxMax(max_x
, x
); 
 423     y 
*= 1 + text
.Freq(wxT('\n')); // multiply by the number of lines. 
 425     return wxSize(max_x
, y
); 
 428 wxSize 
wxGridCellStringRenderer::GetBestSize(wxGrid
& grid
, 
 429                                              wxGridCellAttr
& attr
, 
 433     return DoGetBestSize(attr
, dc
, grid
.GetCellValue(row
, col
)); 
 436 void wxGridCellStringRenderer::Draw(wxGrid
& grid
, 
 437                                     wxGridCellAttr
& attr
, 
 439                                     const wxRect
& rectCell
, 
 443     wxRect rect 
= rectCell
; 
 446     // erase only this cells background, overflow cells should have been erased 
 447     wxGridCellRenderer::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
); 
 450     attr
.GetAlignment(&hAlign
, &vAlign
); 
 452     int overflowCols 
= 0; 
 454     if (attr
.GetOverflow()) 
 456         int cols 
= grid
.GetNumberCols(); 
 457         int best_width 
= GetBestSize(grid
,attr
,dc
,row
,col
).GetWidth(); 
 458         int cell_rows
, cell_cols
; 
 459         attr
.GetSize( &cell_rows
, &cell_cols 
); // shouldn't get here if <= 0 
 460         if ((best_width 
> rectCell
.width
) && (col 
< cols
) && grid
.GetTable()) 
 462             int i
, c_cols
, c_rows
; 
 463             for (i 
= col
+cell_cols
; i 
< cols
; i
++) 
 465                 bool is_empty 
= true; 
 466                 for (int j
=row
; j 
< row 
+ cell_rows
; j
++) 
 468                     // check w/ anchor cell for multicell block 
 469                     grid
.GetCellSize(j
, i
, &c_rows
, &c_cols
); 
 472                     if (!grid
.GetTable()->IsEmptyCell(j 
+ c_rows
, i
)) 
 481                     rect
.width 
+= grid
.GetColSize(i
); 
 489                 if (rect
.width 
>= best_width
) 
 493             overflowCols 
= i 
- col 
- cell_cols 
+ 1; 
 494             if (overflowCols 
>= cols
) 
 495                 overflowCols 
= cols 
- 1; 
 498         if (overflowCols 
> 0) // redraw overflow cells w/ proper hilight 
 500             hAlign 
= wxALIGN_LEFT
; // if oveflowed then it's left aligned 
 502             clip
.x 
+= rectCell
.width
; 
 503             // draw each overflow cell individually 
 504             int col_end 
= col 
+ cell_cols 
+ overflowCols
; 
 505             if (col_end 
>= grid
.GetNumberCols()) 
 506                 col_end 
= grid
.GetNumberCols() - 1; 
 507             for (int i 
= col 
+ cell_cols
; i 
<= col_end
; i
++) 
 509                 clip
.width 
= grid
.GetColSize(i
) - 1; 
 510                 dc
.DestroyClippingRegion(); 
 511                 dc
.SetClippingRegion(clip
); 
 513                 SetTextColoursAndFont(grid
, attr
, dc
, 
 514                         grid
.IsInSelection(row
,i
)); 
 516                 grid
.DrawTextRectangle(dc
, grid
.GetCellValue(row
, col
), 
 517                         rect
, hAlign
, vAlign
); 
 518                 clip
.x 
+= grid
.GetColSize(i
) - 1; 
 524             dc
.DestroyClippingRegion(); 
 528     // now we only have to draw the text 
 529     SetTextColoursAndFont(grid
, attr
, dc
, isSelected
); 
 531     grid
.DrawTextRectangle(dc
, grid
.GetCellValue(row
, col
), 
 532                            rect
, hAlign
, vAlign
); 
 535 // ---------------------------------------------------------------------------- 
 536 // wxGridCellNumberRenderer 
 537 // ---------------------------------------------------------------------------- 
 539 wxString 
wxGridCellNumberRenderer::GetString(const wxGrid
& grid
, int row
, int col
) 
 541     wxGridTableBase 
*table 
= grid
.GetTable(); 
 543     if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) ) 
 545         text
.Printf(_T("%ld"), table
->GetValueAsLong(row
, col
)); 
 549         text 
= table
->GetValue(row
, col
); 
 555 void wxGridCellNumberRenderer::Draw(wxGrid
& grid
, 
 556                                     wxGridCellAttr
& attr
, 
 558                                     const wxRect
& rectCell
, 
 562     wxGridCellRenderer::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
); 
 564     SetTextColoursAndFont(grid
, attr
, dc
, isSelected
); 
 566     // draw the text right aligned by default 
 568     attr
.GetAlignment(&hAlign
, &vAlign
); 
 569     hAlign 
= wxALIGN_RIGHT
; 
 571     wxRect rect 
= rectCell
; 
 574     grid
.DrawTextRectangle(dc
, GetString(grid
, row
, col
), rect
, hAlign
, vAlign
); 
 577 wxSize 
wxGridCellNumberRenderer::GetBestSize(wxGrid
& grid
, 
 578                                              wxGridCellAttr
& attr
, 
 582     return DoGetBestSize(attr
, dc
, GetString(grid
, row
, col
)); 
 585 // ---------------------------------------------------------------------------- 
 586 // wxGridCellFloatRenderer 
 587 // ---------------------------------------------------------------------------- 
 589 wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width
, int precision
) 
 592     SetPrecision(precision
); 
 595 wxGridCellRenderer 
*wxGridCellFloatRenderer::Clone() const 
 597     wxGridCellFloatRenderer 
*renderer 
= new wxGridCellFloatRenderer
; 
 598     renderer
->m_width 
= m_width
; 
 599     renderer
->m_precision 
= m_precision
; 
 600     renderer
->m_format 
= m_format
; 
 605 wxString 
wxGridCellFloatRenderer::GetString(const wxGrid
& grid
, int row
, int col
) 
 607     wxGridTableBase 
*table 
= grid
.GetTable(); 
 612     if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) ) 
 614         val 
= table
->GetValueAsDouble(row
, col
); 
 619         text 
= table
->GetValue(row
, col
); 
 620         hasDouble 
= text
.ToDouble(&val
); 
 629                 if ( m_precision 
== -1 ) 
 631                     // default width/precision 
 636                     m_format
.Printf(_T("%%.%df"), m_precision
); 
 639             else if ( m_precision 
== -1 ) 
 642                 m_format
.Printf(_T("%%%d.f"), m_width
); 
 646                 m_format
.Printf(_T("%%%d.%df"), m_width
, m_precision
); 
 650         text
.Printf(m_format
, val
); 
 653     //else: text already contains the string 
 658 void wxGridCellFloatRenderer::Draw(wxGrid
& grid
, 
 659                                    wxGridCellAttr
& attr
, 
 661                                    const wxRect
& rectCell
, 
 665     wxGridCellRenderer::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
); 
 667     SetTextColoursAndFont(grid
, attr
, dc
, isSelected
); 
 669     // draw the text right aligned by default 
 671     attr
.GetAlignment(&hAlign
, &vAlign
); 
 672     hAlign 
= wxALIGN_RIGHT
; 
 674     wxRect rect 
= rectCell
; 
 677     grid
.DrawTextRectangle(dc
, GetString(grid
, row
, col
), rect
, hAlign
, vAlign
); 
 680 wxSize 
wxGridCellFloatRenderer::GetBestSize(wxGrid
& grid
, 
 681                                             wxGridCellAttr
& attr
, 
 685     return DoGetBestSize(attr
, dc
, GetString(grid
, row
, col
)); 
 688 void wxGridCellFloatRenderer::SetParameters(const wxString
& params
) 
 698         wxString tmp 
= params
.BeforeFirst(_T(',')); 
 702             if ( tmp
.ToLong(&width
) ) 
 704                 SetWidth((int)width
); 
 708                 wxLogDebug(_T("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params
.c_str()); 
 712         tmp 
= params
.AfterFirst(_T(',')); 
 716             if ( tmp
.ToLong(&precision
) ) 
 718                 SetPrecision((int)precision
); 
 722                 wxLogDebug(_T("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params
.c_str()); 
 728 // ---------------------------------------------------------------------------- 
 729 // wxGridCellBoolRenderer 
 730 // ---------------------------------------------------------------------------- 
 732 wxSize 
wxGridCellBoolRenderer::ms_sizeCheckMark
; 
 734 // FIXME these checkbox size calculations are really ugly... 
 736 // between checkmark and box 
 737 static const wxCoord wxGRID_CHECKMARK_MARGIN 
= 2; 
 739 wxSize 
wxGridCellBoolRenderer::GetBestSize(wxGrid
& grid
, 
 740                                            wxGridCellAttr
& WXUNUSED(attr
), 
 745     // compute it only once (no locks for MT safeness in GUI thread...) 
 746     if ( !ms_sizeCheckMark
.x 
) 
 749         wxCheckBox 
*checkbox 
= new wxCheckBox(&grid
, wxID_ANY
, wxEmptyString
); 
 750         wxSize size 
= checkbox
->GetBestSize(); 
 751         wxCoord checkSize 
= size
.y 
+ 2 * wxGRID_CHECKMARK_MARGIN
; 
 753 #if defined(__WXMOTIF__) 
 754         checkSize 
-= size
.y 
/ 2; 
 759         ms_sizeCheckMark
.x 
= ms_sizeCheckMark
.y 
= checkSize
; 
 762     return ms_sizeCheckMark
; 
 765 void wxGridCellBoolRenderer::Draw(wxGrid
& grid
, 
 766                                   wxGridCellAttr
& attr
, 
 772     wxGridCellRenderer::Draw(grid
, attr
, dc
, rect
, row
, col
, isSelected
); 
 774     // draw a check mark in the centre (ignoring alignment - TODO) 
 775     wxSize size 
= GetBestSize(grid
, attr
, dc
, row
, col
); 
 777     // don't draw outside the cell 
 778     wxCoord minSize 
= wxMin(rect
.width
, rect
.height
); 
 779     if ( size
.x 
>= minSize 
|| size
.y 
>= minSize 
) 
 781         // and even leave (at least) 1 pixel margin 
 782         size
.x 
= size
.y 
= minSize
; 
 785     // draw a border around checkmark 
 787     attr
.GetAlignment(&hAlign
, &vAlign
); 
 790     if (hAlign 
== wxALIGN_CENTRE
) 
 792         rectBorder
.x 
= rect
.x 
+ rect
.width 
/ 2 - size
.x 
/ 2; 
 793         rectBorder
.y 
= rect
.y 
+ rect
.height 
/ 2 - size
.y 
/ 2; 
 794         rectBorder
.width 
= size
.x
; 
 795         rectBorder
.height 
= size
.y
; 
 797     else if (hAlign 
== wxALIGN_LEFT
) 
 799         rectBorder
.x 
= rect
.x 
+ 2; 
 800         rectBorder
.y 
= rect
.y 
+ rect
.height 
/ 2 - size
.y 
/ 2; 
 801         rectBorder
.width 
= size
.x
; 
 802         rectBorder
.height 
= size
.y
; 
 804     else if (hAlign 
== wxALIGN_RIGHT
) 
 806         rectBorder
.x 
= rect
.x 
+ rect
.width 
- size
.x 
- 2; 
 807         rectBorder
.y 
= rect
.y 
+ rect
.height 
/ 2 - size
.y 
/ 2; 
 808         rectBorder
.width 
= size
.x
; 
 809         rectBorder
.height 
= size
.y
; 
 813     if ( grid
.GetTable()->CanGetValueAs(row
, col
, wxGRID_VALUE_BOOL
) ) 
 815         value 
= grid
.GetTable()->GetValueAsBool(row
, col
); 
 819         wxString 
cellval( grid
.GetTable()->GetValue(row
, col
) ); 
 820         value 
= wxGridCellBoolEditor::IsTrueValue(cellval
); 
 825         flags 
|= wxCONTROL_CHECKED
; 
 827     wxRendererNative::Get().DrawCheckBox( &grid
, dc
, rectBorder
, flags 
);