1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        msw/checklst.cpp 
   3 // Purpose:     implementation of wxCheckListBox class 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21 #pragma implementation "checklst.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  31 #if wxUSE_CHECKLISTBOX && wxUSE_OWNER_DRAWN 
  34     #include "wx/object.h" 
  35     #include "wx/colour.h" 
  37     #include "wx/bitmap.h" 
  38     #include "wx/window.h" 
  39     #include "wx/listbox.h" 
  40     #include "wx/dcmemory.h" 
  42     #include "wx/settings.h" 
  47 #include "wx/ownerdrw.h" 
  48 #include "wx/checklst.h" 
  50 #include "wx/msw/wrapwin.h" 
  53 #include "wx/msw/private.h" 
  55 #if defined(__GNUWIN32_OLD__) 
  56     #include "wx/msw/gnuwin32/extra.h" 
  59 // ---------------------------------------------------------------------------- 
  61 // ---------------------------------------------------------------------------- 
  63 // get item (converted to right type) 
  64 #define GetItem(n)    ((wxCheckListBoxItem *)(GetItem(n))) 
  66 // ============================================================================ 
  68 // ============================================================================ 
  71 #if wxUSE_EXTENDED_RTTI 
  72 WX_DEFINE_FLAGS( wxCheckListBoxStyle 
) 
  74 wxBEGIN_FLAGS( wxCheckListBoxStyle 
) 
  75     // new style border flags, we put them first to 
  76     // use them for streaming out 
  77     wxFLAGS_MEMBER(wxBORDER_SIMPLE
) 
  78     wxFLAGS_MEMBER(wxBORDER_SUNKEN
) 
  79     wxFLAGS_MEMBER(wxBORDER_DOUBLE
) 
  80     wxFLAGS_MEMBER(wxBORDER_RAISED
) 
  81     wxFLAGS_MEMBER(wxBORDER_STATIC
) 
  82     wxFLAGS_MEMBER(wxBORDER_NONE
) 
  84     // old style border flags 
  85     wxFLAGS_MEMBER(wxSIMPLE_BORDER
) 
  86     wxFLAGS_MEMBER(wxSUNKEN_BORDER
) 
  87     wxFLAGS_MEMBER(wxDOUBLE_BORDER
) 
  88     wxFLAGS_MEMBER(wxRAISED_BORDER
) 
  89     wxFLAGS_MEMBER(wxSTATIC_BORDER
) 
  90     wxFLAGS_MEMBER(wxBORDER
) 
  92     // standard window styles 
  93     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
  94     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
  95     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
) 
  96     wxFLAGS_MEMBER(wxWANTS_CHARS
) 
  97     wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
) 
  98     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB 
) 
  99     wxFLAGS_MEMBER(wxVSCROLL
) 
 100     wxFLAGS_MEMBER(wxHSCROLL
) 
 102     wxFLAGS_MEMBER(wxLB_SINGLE
) 
 103     wxFLAGS_MEMBER(wxLB_MULTIPLE
) 
 104     wxFLAGS_MEMBER(wxLB_EXTENDED
) 
 105     wxFLAGS_MEMBER(wxLB_HSCROLL
) 
 106     wxFLAGS_MEMBER(wxLB_ALWAYS_SB
) 
 107     wxFLAGS_MEMBER(wxLB_NEEDED_SB
) 
 108     wxFLAGS_MEMBER(wxLB_SORT
) 
 109     wxFLAGS_MEMBER(wxLB_OWNERDRAW
) 
 111 wxEND_FLAGS( wxCheckListBoxStyle 
) 
 113 IMPLEMENT_DYNAMIC_CLASS_XTI(wxCheckListBox
, wxListBox
,"wx/checklst.h") 
 115 wxBEGIN_PROPERTIES_TABLE(wxCheckListBox
) 
 116     wxEVENT_PROPERTY( Toggle 
, wxEVT_COMMAND_CHECKLISTBOX_TOGGLED 
, wxCommandEvent 
) 
 117     wxPROPERTY_FLAGS( WindowStyle 
, wxCheckListBoxStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, EMPTY_MACROVALUE 
, wxLB_OWNERDRAW 
/*flags*/ , wxT("Helpstring") , wxT("group")) // style 
 118 wxEND_PROPERTIES_TABLE() 
 120 wxBEGIN_HANDLERS_TABLE(wxCheckListBox
) 
 121 wxEND_HANDLERS_TABLE() 
 123 wxCONSTRUCTOR_4( wxCheckListBox 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxPoint 
, Position 
, wxSize 
, Size 
) 
 126 IMPLEMENT_DYNAMIC_CLASS(wxCheckListBox
, wxListBox
) 
 129 // ---------------------------------------------------------------------------- 
 130 // declaration and implementation of wxCheckListBoxItem class 
 131 // ---------------------------------------------------------------------------- 
 133 class wxCheckListBoxItem 
: public wxOwnerDrawn
 
 135 friend class WXDLLEXPORT wxCheckListBox
; 
 138   wxCheckListBoxItem(wxCheckListBox 
*pParent
, size_t nIndex
); 
 141   virtual bool OnDrawItem(wxDC
& dc
, const wxRect
& rc
, wxODAction act
, wxODStatus stat
); 
 143   // simple accessors and operations 
 144   bool IsChecked() const { return m_bChecked
; } 
 146   void Check(bool bCheck
); 
 147   void Toggle() { Check(!IsChecked()); } 
 153     DECLARE_NO_COPY_CLASS(wxCheckListBoxItem
) 
 155   wxCheckListBox 
*m_pParent
; 
 159 wxCheckListBoxItem::wxCheckListBoxItem(wxCheckListBox 
*pParent
, size_t nIndex
) 
 160                   : wxOwnerDrawn(wxEmptyString
, true)   // checkable 
 166   // we don't initialize m_nCheckHeight/Width vars because it's 
 167   // done in OnMeasure while they are used only in OnDraw and we 
 168   // know that there will always be OnMeasure before OnDraw 
 171   SetMarginWidth(GetDefaultMarginWidth()); 
 174 bool wxCheckListBoxItem::OnDrawItem(wxDC
& dc
, const wxRect
& rc
, 
 175                                     wxODAction act
, wxODStatus stat
) 
 178     stat 
= (wxOwnerDrawn::wxODStatus
)(stat 
| wxOwnerDrawn::wxODChecked
); 
 180   if ( wxOwnerDrawn::OnDrawItem(dc
, rc
, act
, stat
) ) { 
 181     // ## using native API for performance and precision 
 182     size_t nCheckWidth  
= GetDefaultMarginWidth(), 
 183          nCheckHeight 
= m_pParent
->GetItemHeight(); 
 188     HDC hdc 
= (HDC
)dc
.GetHDC(); 
 191     HPEN hpenBack 
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_WINDOW
)), 
 192          hpenGray 
= CreatePen(PS_SOLID
, 0, RGB(128, 128, 128)), 
 193          hpenPrev 
= (HPEN
)SelectObject(hdc
, hpenBack
); 
 195     // we erase the 1-pixel border 
 196     Rectangle(hdc
, x
, y
, x 
+ nCheckWidth
, y 
+ nCheckHeight
); 
 198     // shift check mark 1 pixel to the right (it looks better like this) 
 202       // first create a monochrome bitmap in a memory DC 
 203       HDC hdcMem 
= CreateCompatibleDC(hdc
); 
 204       HBITMAP hbmpCheck 
= CreateBitmap(nCheckWidth
, nCheckHeight
, 1, 1, 0); 
 205       HBITMAP hbmpOld 
= (HBITMAP
)SelectObject(hdcMem
, hbmpCheck
); 
 207       // then draw a check mark into it 
 212       rect
.right  
= nCheckWidth
; 
 213       rect
.bottom 
= nCheckHeight
; 
 216       DrawFrameControl(hdcMem
, &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
); 
 218       DrawFrameControl(hdcMem
, &rect
, DFC_MENU
, DFCS_MENUCHECK
); 
 221       // finally copy it to screen DC and clean up 
 222       BitBlt(hdc
, x
, y
, nCheckWidth 
- 1, nCheckHeight
, 
 223              hdcMem
, 0, 0, SRCCOPY
); 
 225       SelectObject(hdcMem
, hbmpOld
); 
 226       DeleteObject(hbmpCheck
); 
 230     // now we draw the smaller rectangle 
 235     // draw hollow gray rectangle 
 236     (void)SelectObject(hdc
, hpenGray
); 
 237     HBRUSH hbrPrev  
= (HBRUSH
)SelectObject(hdc
, GetStockObject(NULL_BRUSH
)); 
 238     Rectangle(hdc
, x
, y
, x 
+ nCheckWidth
, y 
+ nCheckHeight
); 
 241     (void)SelectObject(hdc
, hpenPrev
); 
 242     (void)SelectObject(hdc
, hbrPrev
); 
 244     DeleteObject(hpenBack
); 
 245     DeleteObject(hpenGray
); 
 248     dc.DrawRectangle(x, y, nCheckWidth, nCheckHeight); 
 251       dc.DrawLine(x, y, x + nCheckWidth, y + nCheckHeight); 
 252       dc.DrawLine(x, y + nCheckHeight, x + nCheckWidth, y); 
 262 // change the state of the item and redraw it 
 263 void wxCheckListBoxItem::Check(bool check
) 
 267     // index may be changed because new items were added/deleted 
 268     if ( m_pParent
->GetItemIndex(this) != (int)m_nIndex 
) 
 271         int index 
= m_pParent
->GetItemIndex(this); 
 273         wxASSERT_MSG( index 
!= wxNOT_FOUND
, wxT("what does this item do here?") ); 
 275         m_nIndex 
= (size_t)index
; 
 278     HWND hwndListbox 
= (HWND
)m_pParent
->GetHWND(); 
 282     if ( ::SendMessage(hwndListbox
, LB_GETITEMRECT
, 
 283                        m_nIndex
, (LPARAM
)&rcUpdate
) == LB_ERR 
) 
 285         wxLogDebug(wxT("LB_GETITEMRECT failed")); 
 288     ::InvalidateRect(hwndListbox
, &rcUpdate
, FALSE
); 
 291 // send an "item checked" event 
 292 void wxCheckListBoxItem::SendEvent() 
 294     wxCommandEvent 
event(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED
, m_pParent
->GetId()); 
 295     event
.SetInt(m_nIndex
); 
 296     event
.SetEventObject(m_pParent
); 
 297     m_pParent
->ProcessCommand(event
); 
 300 // ---------------------------------------------------------------------------- 
 301 // implementation of wxCheckListBox class 
 302 // ---------------------------------------------------------------------------- 
 304 // define event table 
 305 // ------------------ 
 306 BEGIN_EVENT_TABLE(wxCheckListBox
, wxListBox
) 
 307   EVT_KEY_DOWN(wxCheckListBox::OnKeyDown
) 
 308   EVT_LEFT_DOWN(wxCheckListBox::OnLeftClick
) 
 314 // def ctor: use Create() to really create the control 
 315 wxCheckListBox::wxCheckListBox() 
 319 // ctor which creates the associated control 
 320 wxCheckListBox::wxCheckListBox(wxWindow 
*parent
, wxWindowID id
, 
 321                                const wxPoint
& pos
, const wxSize
& size
, 
 322                                int nStrings
, const wxString choices
[], 
 323                                long style
, const wxValidator
& val
, 
 324                                const wxString
& name
) 
 326     Create(parent
, id
, pos
, size
, nStrings
, choices
, style
, val
, name
); 
 329 wxCheckListBox::wxCheckListBox(wxWindow 
*parent
, wxWindowID id
, 
 330                                const wxPoint
& pos
, const wxSize
& size
, 
 331                                const wxArrayString
& choices
, 
 332                                long style
, const wxValidator
& val
, 
 333                                const wxString
& name
) 
 335     Create(parent
, id
, pos
, size
, choices
, style
, val
, name
); 
 338 bool wxCheckListBox::Create(wxWindow 
*parent
, wxWindowID id
, 
 339                             const wxPoint
& pos
, const wxSize
& size
, 
 340                             int n
, const wxString choices
[], 
 342                             const wxValidator
& validator
, const wxString
& name
) 
 344     return wxListBox::Create(parent
, id
, pos
, size
, n
, choices
, 
 345                              style 
| wxLB_OWNERDRAW
, validator
, name
); 
 348 bool wxCheckListBox::Create(wxWindow 
*parent
, wxWindowID id
, 
 349                             const wxPoint
& pos
, const wxSize
& size
, 
 350                             const wxArrayString
& choices
, 
 352                             const wxValidator
& validator
, const wxString
& name
) 
 354     return wxListBox::Create(parent
, id
, pos
, size
, choices
, 
 355                              style 
| wxLB_OWNERDRAW
, validator
, name
); 
 358 // misc overloaded methods 
 359 // ----------------------- 
 361 void wxCheckListBox::Delete(int N
) 
 363     wxCHECK_RET( N 
>= 0 && N 
< m_noItems
, 
 364                  wxT("invalid index in wxListBox::Delete") ); 
 366     wxListBox::Delete(N
); 
 371     m_aItems
.RemoveAt(N
); 
 374 bool wxCheckListBox::SetFont( const wxFont 
&font 
) 
 377     for ( i 
= 0; i 
< m_aItems
.GetCount(); i
++ ) 
 378         m_aItems
[i
]->SetFont(font
); 
 380     wxListBox::SetFont(font
); 
 385 // create/retrieve item 
 386 // -------------------- 
 388 // create a check list box item 
 389 wxOwnerDrawn 
*wxCheckListBox::CreateLboxItem(size_t nIndex
) 
 391   wxCheckListBoxItem 
*pItem 
= new wxCheckListBoxItem(this, nIndex
); 
 397 bool wxCheckListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT 
*item
) 
 399   if ( wxListBox::MSWOnMeasure(item
) ) { 
 400     MEASUREITEMSTRUCT 
*pStruct 
= (MEASUREITEMSTRUCT 
*)item
; 
 403     m_nItemHeight 
= pStruct
->itemHeight
; 
 405     // add place for the check mark 
 406     pStruct
->itemWidth 
+= wxOwnerDrawn::GetDefaultMarginWidth(); 
 417 bool wxCheckListBox::IsChecked(size_t uiIndex
) const 
 419     wxCHECK_MSG( uiIndex 
< (size_t)GetCount(), false, _T("bad wxCheckListBox index") ); 
 421     return GetItem(uiIndex
)->IsChecked(); 
 424 void wxCheckListBox::Check(size_t uiIndex
, bool bCheck
) 
 426     wxCHECK_RET( uiIndex 
< (size_t)GetCount(), _T("bad wxCheckListBox index") ); 
 428     GetItem(uiIndex
)->Check(bCheck
); 
 434 void wxCheckListBox::OnKeyDown(wxKeyEvent
& event
) 
 445     switch ( event
.GetKeyCode() ) 
 456         case WXK_NUMPAD_SUBTRACT
: 
 467         wxArrayInt selections
; 
 469         if ( HasMultipleSelection() ) 
 471             count 
= GetSelections(selections
); 
 475             int sel 
= GetSelection(); 
 483         for ( int i 
= 0; i 
< count
; i
++ ) 
 485             wxCheckListBoxItem 
*item 
= GetItem(selections
[i
]); 
 488                 wxFAIL_MSG( _T("no wxCheckListBoxItem?") ); 
 500                     item
->Check( oper 
== Set 
); 
 504                     wxFAIL_MSG( _T("what should this key do?") ); 
 507             // we should send an event as this has been done by the user and 
 508             // not by the program 
 512     else // nothing to do 
 518 void wxCheckListBox::OnLeftClick(wxMouseEvent
& event
) 
 520   // clicking on the item selects it, clicking on the checkmark toggles 
 521   if ( event
.GetX() <= wxOwnerDrawn::GetDefaultMarginWidth() ) { 
 522     int nItem 
= HitTest(event
.GetX(), event
.GetY()); 
 524     if ( nItem 
!= wxNOT_FOUND 
) { 
 525       wxCheckListBoxItem 
*item 
= GetItem(nItem
); 
 529     //else: it's not an error, just click outside of client zone 
 532     // implement default behaviour: clicking on the item selects it 
 537 int wxCheckListBox::DoHitTestItem(wxCoord x
, wxCoord y
) const 
 539     int nItem 
= (int)::SendMessage
 
 547   return nItem 
>= m_noItems 
? wxNOT_FOUND 
: nItem
; 
 551 wxSize 
wxCheckListBox::DoGetBestSize() const 
 553     wxSize best 
= wxListBox::DoGetBestSize(); 
 554     best
.x 
+= wxOwnerDrawn::GetDefaultMarginWidth();  // add room for the checkbox