1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/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 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  27 #if wxUSE_CHECKLISTBOX && wxUSE_OWNER_DRAWN 
  29 #include "wx/checklst.h" 
  32     #include "wx/msw/wrapcctl.h" 
  33     #include "wx/object.h" 
  34     #include "wx/colour.h" 
  36     #include "wx/bitmap.h" 
  37     #include "wx/window.h" 
  38     #include "wx/listbox.h" 
  39     #include "wx/dcmemory.h" 
  40     #include "wx/settings.h" 
  44 #include "wx/ownerdrw.h" 
  48 #include "wx/renderer.h" 
  49 #include "wx/msw/private.h" 
  50 #include "wx/msw/dc.h" 
  52 // ---------------------------------------------------------------------------- 
  54 // ---------------------------------------------------------------------------- 
  56 // get item (converted to right type) 
  57 #define GetItem(n)    ((wxCheckListBoxItem *)(GetItem(n))) 
  59 // ============================================================================ 
  61 // ============================================================================ 
  64 #if wxUSE_EXTENDED_RTTI 
  65 WX_DEFINE_FLAGS( wxCheckListBoxStyle 
) 
  67 wxBEGIN_FLAGS( wxCheckListBoxStyle 
) 
  68     // new style border flags, we put them first to 
  69     // use them for streaming out 
  70     wxFLAGS_MEMBER(wxBORDER_SIMPLE
) 
  71     wxFLAGS_MEMBER(wxBORDER_SUNKEN
) 
  72     wxFLAGS_MEMBER(wxBORDER_DOUBLE
) 
  73     wxFLAGS_MEMBER(wxBORDER_RAISED
) 
  74     wxFLAGS_MEMBER(wxBORDER_STATIC
) 
  75     wxFLAGS_MEMBER(wxBORDER_NONE
) 
  77     // old style border flags 
  78     wxFLAGS_MEMBER(wxSIMPLE_BORDER
) 
  79     wxFLAGS_MEMBER(wxSUNKEN_BORDER
) 
  80     wxFLAGS_MEMBER(wxDOUBLE_BORDER
) 
  81     wxFLAGS_MEMBER(wxRAISED_BORDER
) 
  82     wxFLAGS_MEMBER(wxSTATIC_BORDER
) 
  83     wxFLAGS_MEMBER(wxBORDER
) 
  85     // standard window styles 
  86     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
  87     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
  88     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
) 
  89     wxFLAGS_MEMBER(wxWANTS_CHARS
) 
  90     wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
) 
  91     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB 
) 
  92     wxFLAGS_MEMBER(wxVSCROLL
) 
  93     wxFLAGS_MEMBER(wxHSCROLL
) 
  95     wxFLAGS_MEMBER(wxLB_SINGLE
) 
  96     wxFLAGS_MEMBER(wxLB_MULTIPLE
) 
  97     wxFLAGS_MEMBER(wxLB_EXTENDED
) 
  98     wxFLAGS_MEMBER(wxLB_HSCROLL
) 
  99     wxFLAGS_MEMBER(wxLB_ALWAYS_SB
) 
 100     wxFLAGS_MEMBER(wxLB_NEEDED_SB
) 
 101     wxFLAGS_MEMBER(wxLB_SORT
) 
 102     wxFLAGS_MEMBER(wxLB_OWNERDRAW
) 
 104 wxEND_FLAGS( wxCheckListBoxStyle 
) 
 106 IMPLEMENT_DYNAMIC_CLASS_XTI(wxCheckListBox
, wxListBox
,"wx/checklst.h") 
 108 wxBEGIN_PROPERTIES_TABLE(wxCheckListBox
) 
 109     wxEVENT_PROPERTY( Toggle 
, wxEVT_COMMAND_CHECKLISTBOX_TOGGLED 
, wxCommandEvent 
) 
 110     wxPROPERTY_FLAGS( WindowStyle 
, wxCheckListBoxStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, EMPTY_MACROVALUE 
, wxLB_OWNERDRAW 
/*flags*/ , wxT("Helpstring") , wxT("group")) // style 
 111 wxEND_PROPERTIES_TABLE() 
 113 wxBEGIN_HANDLERS_TABLE(wxCheckListBox
) 
 114 wxEND_HANDLERS_TABLE() 
 116 wxCONSTRUCTOR_4( wxCheckListBox 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxPoint 
, Position 
, wxSize 
, Size 
) 
 119 IMPLEMENT_DYNAMIC_CLASS(wxCheckListBox
, wxListBox
) 
 122 // ---------------------------------------------------------------------------- 
 123 // declaration and implementation of wxCheckListBoxItem class 
 124 // ---------------------------------------------------------------------------- 
 126 class wxCheckListBoxItem 
: public wxOwnerDrawn
 
 128 friend class WXDLLIMPEXP_FWD_CORE wxCheckListBox
; 
 131     wxCheckListBoxItem(wxCheckListBox 
*pParent
, size_t nIndex
); 
 134     virtual bool OnDrawItem(wxDC
& dc
, const wxRect
& rc
, wxODAction act
, wxODStatus stat
); 
 136     // simple accessors and operations 
 137     bool IsChecked() const { return m_bChecked
; } 
 139     void Check(bool bCheck
); 
 140     void Toggle() { Check(!IsChecked()); } 
 146     wxCheckListBox 
*m_pParent
; 
 149     wxDECLARE_NO_COPY_CLASS(wxCheckListBoxItem
); 
 152 wxCheckListBoxItem::wxCheckListBoxItem(wxCheckListBox 
*pParent
, size_t nIndex
) 
 153                   : wxOwnerDrawn(wxEmptyString
, true)   // checkable 
 159     // we don't initialize m_nCheckHeight/Width vars because it's 
 160     // done in OnMeasure while they are used only in OnDraw and we 
 161     // know that there will always be OnMeasure before OnDraw 
 163     SetMarginWidth(::GetSystemMetrics(SM_CXMENUCHECK
) - 2); 
 165     SetBackgroundColour(pParent
->GetBackgroundColour()); 
 168 bool wxCheckListBoxItem::OnDrawItem(wxDC
& dc
, const wxRect
& rc
, 
 169                                     wxODAction act
, wxODStatus stat
) 
 171     // first draw the label 
 173         stat 
= (wxOwnerDrawn::wxODStatus
)(stat 
| wxOwnerDrawn::wxODChecked
); 
 175     if ( !wxOwnerDrawn::OnDrawItem(dc
, rc
, act
, stat
) ) 
 178     wxMSWDCImpl 
*impl 
= (wxMSWDCImpl
*) dc
.GetImpl(); 
 179     // now draw the check mark part 
 180     HDC hdc 
= GetHdcOf(*impl
); 
 182     int nBmpWidth  
= ::GetSystemMetrics(SM_CXMENUCHECK
), 
 183         nBmpHeight 
= ::GetSystemMetrics(SM_CYMENUCHECK
); 
 186     // first create bitmap in a memory DC 
 187     MemoryHDC 
hdcMem(hdc
); 
 188     CompatibleBitmap 
hBmpCheck(hdc
, nBmpWidth
, nBmpHeight
); 
 190     // then draw a check mark into it 
 192         SelectInHDC 
selBmp(hdcMem
, hBmpCheck
); 
 194         int flags 
= wxCONTROL_FLAT
; 
 196             flags 
|= wxCONTROL_CHECKED
; 
 198         wxDCTemp 
dcMem(hdcMem
); 
 199         wxRendererNative::Get().DrawCheckBox( 
 200                 m_pParent
, dcMem
, wxRect(0, 0, nBmpWidth
, nBmpHeight
), flags
); 
 201     } // select hBmpCheck out of hdcMem 
 203     // shift check mark 2 pixel to the right and bottom, looks better like this 
 204     int x 
= rc
.GetX() + 2, 
 207     // finally draw bitmap to screen: uses image list functions to blend 
 208     // the bitmap with the background colour (better for the selected items) 
 209     HIMAGELIST himl 
= ImageList_Create(nBmpWidth
, nBmpHeight
, 
 210                                        ILC_COLOR32 
| ILC_MASK
, 1, 1); 
 211     ImageList_Add(himl
, hBmpCheck
, NULL
); 
 213     UINT fStyle 
= stat 
& wxOwnerDrawn::wxODSelected 
? ILD_SELECTED 
: ILD_NORMAL
; 
 214     ImageList_Draw(himl
, 0, hdc
, x
, y
, fStyle
); 
 216     ImageList_Destroy(himl
); 
 218     if (stat 
& wxODHasFocus
) 
 219         wxRendererNative::Get().DrawFocusRect(m_pParent
, dc
, rc
); 
 224 // change the state of the item and redraw it 
 225 void wxCheckListBoxItem::Check(bool check
) 
 229     // index may be changed because new items were added/deleted 
 230     if ( m_pParent
->GetItemIndex(this) != (int)m_nIndex 
) 
 233         int index 
= m_pParent
->GetItemIndex(this); 
 235         wxASSERT_MSG( index 
!= wxNOT_FOUND
, wxT("what does this item do here?") ); 
 237         m_nIndex 
= (size_t)index
; 
 240     HWND hwndListbox 
= (HWND
)m_pParent
->GetHWND(); 
 244     if ( ::SendMessage(hwndListbox
, LB_GETITEMRECT
, 
 245                        m_nIndex
, (LPARAM
)&rcUpdate
) == LB_ERR 
) 
 247         wxLogDebug(wxT("LB_GETITEMRECT failed")); 
 250     ::InvalidateRect(hwndListbox
, &rcUpdate
, FALSE
); 
 253 // send an "item checked" event 
 254 void wxCheckListBoxItem::SendEvent() 
 256     wxCommandEvent 
event(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED
, m_pParent
->GetId()); 
 257     event
.SetInt(m_nIndex
); 
 258     event
.SetEventObject(m_pParent
); 
 259     event
.SetString(m_pParent
->GetString(m_nIndex
)); 
 260     m_pParent
->ProcessCommand(event
); 
 263 // ---------------------------------------------------------------------------- 
 264 // implementation of wxCheckListBox class 
 265 // ---------------------------------------------------------------------------- 
 267 // define event table 
 268 // ------------------ 
 269 BEGIN_EVENT_TABLE(wxCheckListBox
, wxListBox
) 
 270   EVT_KEY_DOWN(wxCheckListBox::OnKeyDown
) 
 271   EVT_LEFT_DOWN(wxCheckListBox::OnLeftClick
) 
 277 // def ctor: use Create() to really create the control 
 278 wxCheckListBox::wxCheckListBox() 
 282 // ctor which creates the associated control 
 283 wxCheckListBox::wxCheckListBox(wxWindow 
*parent
, wxWindowID id
, 
 284                                const wxPoint
& pos
, const wxSize
& size
, 
 285                                int nStrings
, const wxString choices
[], 
 286                                long style
, const wxValidator
& val
, 
 287                                const wxString
& name
) 
 289     Create(parent
, id
, pos
, size
, nStrings
, choices
, style
, val
, name
); 
 292 wxCheckListBox::wxCheckListBox(wxWindow 
*parent
, wxWindowID id
, 
 293                                const wxPoint
& pos
, const wxSize
& size
, 
 294                                const wxArrayString
& choices
, 
 295                                long style
, const wxValidator
& val
, 
 296                                const wxString
& name
) 
 298     Create(parent
, id
, pos
, size
, choices
, style
, val
, name
); 
 301 bool wxCheckListBox::Create(wxWindow 
*parent
, wxWindowID id
, 
 302                             const wxPoint
& pos
, const wxSize
& size
, 
 303                             int n
, const wxString choices
[], 
 305                             const wxValidator
& validator
, const wxString
& name
) 
 307     return wxListBox::Create(parent
, id
, pos
, size
, n
, choices
, 
 308                              style 
| wxLB_OWNERDRAW
, validator
, name
); 
 311 bool wxCheckListBox::Create(wxWindow 
*parent
, wxWindowID id
, 
 312                             const wxPoint
& pos
, const wxSize
& size
, 
 313                             const wxArrayString
& choices
, 
 315                             const wxValidator
& validator
, const wxString
& name
) 
 317     return wxListBox::Create(parent
, id
, pos
, size
, choices
, 
 318                              style 
| wxLB_OWNERDRAW
, validator
, name
); 
 321 // misc overloaded methods 
 322 // ----------------------- 
 324 void wxCheckListBox::Delete(unsigned int n
) 
 326     wxCHECK_RET( IsValid(n
), 
 327                  wxT("invalid index in wxListBox::Delete") ); 
 329     wxListBox::Delete(n
); 
 334     m_aItems
.RemoveAt(n
); 
 337 bool wxCheckListBox::SetFont( const wxFont 
&font 
) 
 340     for ( i 
= 0; i 
< m_aItems
.GetCount(); i
++ ) 
 341         m_aItems
[i
]->SetFont(font
); 
 343     wxListBox::SetFont(font
); 
 348 // create/retrieve item 
 349 // -------------------- 
 351 // create a check list box item 
 352 wxOwnerDrawn 
*wxCheckListBox::CreateLboxItem(size_t nIndex
) 
 354   wxCheckListBoxItem 
*pItem 
= new wxCheckListBoxItem(this, nIndex
); 
 360 bool wxCheckListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT 
*item
) 
 362   if ( wxListBox::MSWOnMeasure(item
) ) { 
 363     MEASUREITEMSTRUCT 
*pStruct 
= (MEASUREITEMSTRUCT 
*)item
; 
 365     // add place for the check mark 
 366     pStruct
->itemWidth  
+= wxOwnerDrawn::GetDefaultMarginWidth(); 
 367     pStruct
->itemHeight 
+= 1; 
 370     m_nItemHeight 
= pStruct
->itemHeight
; 
 381 bool wxCheckListBox::IsChecked(unsigned int uiIndex
) const 
 383     wxCHECK_MSG( IsValid(uiIndex
), false, _T("bad wxCheckListBox index") ); 
 385     return GetItem(uiIndex
)->IsChecked(); 
 388 void wxCheckListBox::Check(unsigned int uiIndex
, bool bCheck
) 
 390     wxCHECK_RET( IsValid(uiIndex
), _T("bad wxCheckListBox index") ); 
 392     GetItem(uiIndex
)->Check(bCheck
); 
 398 void wxCheckListBox::OnKeyDown(wxKeyEvent
& event
) 
 409     switch ( event
.GetKeyCode() ) 
 420         case WXK_NUMPAD_SUBTRACT
: 
 431         wxArrayInt selections
; 
 433         if ( HasMultipleSelection() ) 
 435             count 
= GetSelections(selections
); 
 439             int sel 
= GetSelection(); 
 447         for ( int i 
= 0; i 
< count
; i
++ ) 
 449             wxCheckListBoxItem 
*item 
= GetItem(selections
[i
]); 
 452                 wxFAIL_MSG( _T("no wxCheckListBoxItem?") ); 
 464                     item
->Check( oper 
== Set 
); 
 468                     wxFAIL_MSG( _T("what should this key do?") ); 
 471             // we should send an event as this has been done by the user and 
 472             // not by the program 
 476     else // nothing to do 
 482 void wxCheckListBox::OnLeftClick(wxMouseEvent
& event
) 
 484     // clicking on the item selects it, clicking on the checkmark toggles 
 485     if ( event
.GetX() <= wxOwnerDrawn::GetDefaultMarginWidth() ) 
 487         int nItem 
= HitTest(event
.GetX(), event
.GetY()); 
 489         if ( nItem 
!= wxNOT_FOUND 
) 
 491             // people expect to get "kill focus" event for the currently 
 492             // focused control before getting events from the other controls 
 493             // and, equally importantly, they may prevent the focus change from 
 494             // taking place at all (e.g. because the old control contents is 
 495             // invalid and needs to be corrected) in which case we shouldn't 
 496             // generate this event at all 
 498             if ( FindFocus() == this ) 
 500                 wxCheckListBoxItem 
*item 
= GetItem(nItem
); 
 505         //else: it's not an error, just click outside of client zone 
 509         // implement default behaviour: clicking on the item selects it 
 514 wxSize 
wxCheckListBox::DoGetBestSize() const 
 516     wxSize best 
= wxListBox::DoGetBestSize(); 
 517     best
.x 
+= wxOwnerDrawn::GetDefaultMarginWidth();  // add room for the checkbox 
 522 #endif // wxUSE_CHECKLISTBOX