1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/bmpcbox.cpp
3 // Purpose: wxBitmapComboBox
4 // Author: Jaakko Salli
7 // Copyright: (c) 2008 Jaakko Salli
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 #include "wx/wxprec.h"
25 #if wxUSE_BITMAPCOMBOBOX
27 #include "wx/bmpcbox.h"
33 #include "wx/settings.h"
34 #include "wx/vector.h"
36 #include "wx/msw/dcclient.h"
37 #include "wx/msw/private.h"
39 // For wxODCB_XXX flags
40 #include "wx/odcombo.h"
43 #define IMAGE_SPACING_CTRL_VERTICAL 7 // Spacing used in control size calculation
46 // ============================================================================
48 // ============================================================================
51 BEGIN_EVENT_TABLE(wxBitmapComboBox
, wxComboBox
)
52 EVT_SIZE(wxBitmapComboBox::OnSize
)
56 IMPLEMENT_DYNAMIC_CLASS(wxBitmapComboBox
, wxComboBox
)
59 // ----------------------------------------------------------------------------
60 // wxBitmapComboBox creation
61 // ----------------------------------------------------------------------------
63 void wxBitmapComboBox::Init()
68 wxBitmapComboBox::wxBitmapComboBox(wxWindow
*parent
,
70 const wxString
& value
,
73 const wxArrayString
& choices
,
75 const wxValidator
& validator
,
78 wxBitmapComboBoxBase()
82 Create(parent
,id
,value
,pos
,size
,choices
,style
,validator
,name
);
85 bool wxBitmapComboBox::Create(wxWindow
*parent
,
87 const wxString
& value
,
90 const wxArrayString
& choices
,
92 const wxValidator
& validator
,
95 wxCArrayString
chs(choices
);
96 return Create(parent
, id
, value
, pos
, size
, chs
.GetCount(),
97 chs
.GetStrings(), style
, validator
, name
);
100 bool wxBitmapComboBox::Create(wxWindow
*parent
,
102 const wxString
& value
,
106 const wxString choices
[],
108 const wxValidator
& validator
,
109 const wxString
& name
)
111 if ( !wxComboBox::Create(parent
, id
, value
, pos
, size
,
112 n
, choices
, style
, validator
, name
) )
120 WXDWORD
wxBitmapComboBox::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
122 return wxComboBox::MSWGetStyle(style
, exstyle
) | CBS_OWNERDRAWFIXED
| CBS_HASSTRINGS
;
125 void wxBitmapComboBox::RecreateControl()
128 // Recreate control so that WM_MEASUREITEM gets called again.
129 // Can't use CBS_OWNERDRAWVARIABLE because it has odd
130 // mouse-wheel behaviour.
132 wxString value
= GetValue();
133 wxPoint pos
= GetPosition();
134 wxSize size
= GetSize();
135 size
.y
= GetBestSize().y
;
136 const wxArrayString strings
= GetStrings();
137 const unsigned numItems
= strings
.size();
140 // Save the client data pointers before clearing the control, if any.
141 const wxClientDataType clientDataType
= GetClientDataType();
142 wxVector
<wxClientData
*> objectClientData
;
143 wxVector
<void*> voidClientData
;
144 switch ( clientDataType
)
146 case wxClientData_None
:
149 case wxClientData_Object
:
150 objectClientData
.reserve(numItems
);
151 for ( i
= 0; i
< numItems
; ++i
)
152 objectClientData
.push_back(GetClientObject(i
));
155 case wxClientData_Void
:
156 voidClientData
.reserve(numItems
);
157 for ( i
= 0; i
< numItems
; ++i
)
158 voidClientData
.push_back(GetClientData(i
));
162 wxComboBox::DoClear();
164 HWND hwnd
= GetHwnd();
166 ::DestroyWindow(hwnd
);
168 if ( !MSWCreateControl(wxT("COMBOBOX"), wxEmptyString
, pos
, size
) )
171 // initialize the controls contents
172 for ( i
= 0; i
< numItems
; i
++ )
174 wxComboBox::Append(strings
[i
]);
176 if ( !objectClientData
.empty() )
177 SetClientObject(i
, objectClientData
[i
]);
178 else if ( !voidClientData
.empty() )
179 SetClientData(i
, objectClientData
[i
]);
182 // and make sure it has the same attributes as before
185 // calling SetFont(m_font) would do nothing as the code would
186 // notice that the font didn't change, so force it to believe
188 wxFont font
= m_font
;
195 wxColour colFg
= m_foregroundColour
;
196 m_foregroundColour
= wxNullColour
;
197 SetForegroundColour(colFg
);
202 wxColour colBg
= m_backgroundColour
;
203 m_backgroundColour
= wxNullColour
;
204 SetBackgroundColour(colBg
);
208 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
211 ::SendMessage(GetHwnd(), CB_SETITEMHEIGHT
, 0, MeasureItem(0));
213 // Revert the old string value
214 if ( !HasFlag(wxCB_READONLY
) )
218 wxBitmapComboBox::~wxBitmapComboBox()
223 wxSize
wxBitmapComboBox::DoGetBestSize() const
225 wxSize best
= wxComboBox::DoGetBestSize();
226 wxSize bitmapSize
= GetBitmapSize();
228 wxCoord useHeightBitmap
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(bitmapSize
.y
);
229 if ( best
.y
< useHeightBitmap
)
231 best
.y
= useHeightBitmap
;
237 // ----------------------------------------------------------------------------
239 // ----------------------------------------------------------------------------
241 void wxBitmapComboBox::SetItemBitmap(unsigned int n
, const wxBitmap
& bitmap
)
244 DoSetItemBitmap(n
, bitmap
);
246 if ( (int)n
== GetSelection() )
250 int wxBitmapComboBox::Append(const wxString
& item
, const wxBitmap
& bitmap
)
253 const int n
= wxComboBox::Append(item
);
254 if ( n
!= wxNOT_FOUND
)
255 DoSetItemBitmap(n
, bitmap
);
259 int wxBitmapComboBox::Append(const wxString
& item
, const wxBitmap
& bitmap
,
263 const int n
= wxComboBox::Append(item
, clientData
);
264 if ( n
!= wxNOT_FOUND
)
265 DoSetItemBitmap(n
, bitmap
);
269 int wxBitmapComboBox::Append(const wxString
& item
, const wxBitmap
& bitmap
,
270 wxClientData
*clientData
)
273 const int n
= wxComboBox::Append(item
, clientData
);
274 if ( n
!= wxNOT_FOUND
)
275 DoSetItemBitmap(n
, bitmap
);
279 int wxBitmapComboBox::Insert(const wxString
& item
,
280 const wxBitmap
& bitmap
,
284 const int n
= wxComboBox::Insert(item
, pos
);
285 if ( n
!= wxNOT_FOUND
)
286 DoSetItemBitmap(n
, bitmap
);
290 int wxBitmapComboBox::Insert(const wxString
& item
, const wxBitmap
& bitmap
,
291 unsigned int pos
, void *clientData
)
294 const int n
= wxComboBox::Insert(item
, pos
, clientData
);
295 if ( n
!= wxNOT_FOUND
)
296 DoSetItemBitmap(n
, bitmap
);
300 int wxBitmapComboBox::Insert(const wxString
& item
, const wxBitmap
& bitmap
,
301 unsigned int pos
, wxClientData
*clientData
)
304 const int n
= wxComboBox::Insert(item
, pos
, clientData
);
305 if ( n
!= wxNOT_FOUND
)
306 DoSetItemBitmap(n
, bitmap
);
310 int wxBitmapComboBox::DoInsertItems(const wxArrayStringsAdapter
& items
,
312 void **clientData
, wxClientDataType type
)
314 const unsigned int numItems
= items
.GetCount();
315 const unsigned int countNew
= GetCount() + numItems
;
317 wxASSERT( numItems
== 1 || !HasFlag(wxCB_SORT
) ); // Sanity check
319 m_bitmaps
.Alloc(countNew
);
321 for ( unsigned int i
= 0; i
< numItems
; i
++ )
323 m_bitmaps
.Insert(new wxBitmap(wxNullBitmap
), pos
+ i
);
326 const int index
= wxComboBox::DoInsertItems(items
, pos
,
329 if ( index
== wxNOT_FOUND
)
331 for ( int i
= numItems
-1; i
>= 0; i
-- )
332 BCBDoDeleteOneItem(pos
+ i
);
334 else if ( ((unsigned int)index
) != pos
)
336 // Move pre-inserted empty bitmap into correct position
337 // (usually happens when combo box has wxCB_SORT style)
338 wxBitmap
* bmp
= static_cast<wxBitmap
*>(m_bitmaps
[pos
]);
339 m_bitmaps
.RemoveAt(pos
);
340 m_bitmaps
.Insert(bmp
, index
);
346 bool wxBitmapComboBox::OnAddBitmap(const wxBitmap
& bitmap
)
348 if ( wxBitmapComboBoxBase::OnAddBitmap(bitmap
) )
350 // Need to recreate control for a new measureitem call?
351 int prevItemHeight
= ::SendMessage(GetHwnd(), CB_GETITEMHEIGHT
, 0, 0);
353 if ( prevItemHeight
!= MeasureItem(0) )
362 void wxBitmapComboBox::DoClear()
364 wxComboBox::DoClear();
365 wxBitmapComboBoxBase::BCBDoClear();
368 void wxBitmapComboBox::DoDeleteOneItem(unsigned int n
)
370 wxComboBox::DoDeleteOneItem(n
);
371 wxBitmapComboBoxBase::BCBDoDeleteOneItem(n
);
374 // ----------------------------------------------------------------------------
375 // wxBitmapComboBox event handlers and such
376 // ----------------------------------------------------------------------------
378 void wxBitmapComboBox::OnSize(wxSizeEvent
& event
)
380 // Prevent infinite looping
391 // ----------------------------------------------------------------------------
392 // wxBitmapComboBox miscellaneous
393 // ----------------------------------------------------------------------------
395 bool wxBitmapComboBox::SetFont(const wxFont
& font
)
397 bool res
= wxComboBox::SetFont(font
);
402 // ----------------------------------------------------------------------------
403 // wxBitmapComboBox item drawing and measuring
404 // ----------------------------------------------------------------------------
406 bool wxBitmapComboBox::MSWOnDraw(WXDRAWITEMSTRUCT
*item
)
408 LPDRAWITEMSTRUCT lpDrawItem
= (LPDRAWITEMSTRUCT
) item
;
409 int pos
= lpDrawItem
->itemID
;
411 // Draw default for item -1, which means 'focus rect only'
416 if ( lpDrawItem
->itemState
& ODS_COMBOBOXEDIT
)
417 flags
|= wxODCB_PAINTING_CONTROL
;
418 if ( lpDrawItem
->itemState
& ODS_SELECTED
)
419 flags
|= wxODCB_PAINTING_SELECTED
;
423 if ( flags
& wxODCB_PAINTING_CONTROL
)
426 if ( !HasFlag(wxCB_READONLY
) )
431 text
= GetString(pos
);
434 wxPaintDCEx
dc(this, lpDrawItem
->hDC
);
435 wxRect rect
= wxRectFromRECT(lpDrawItem
->rcItem
);
436 wxBitmapComboBoxBase::DrawBackground(dc
, rect
, pos
, flags
);
437 wxBitmapComboBoxBase::DrawItem(dc
, rect
, pos
, text
, flags
);
439 // If the item has the focus, draw focus rectangle.
440 // Commented out since regular combo box doesn't
441 // seem to do it either.
442 //if ( lpDrawItem->itemState & ODS_FOCUS )
443 // DrawFocusRect(lpDrawItem->hDC, &lpDrawItem->rcItem);
448 bool wxBitmapComboBox::MSWOnMeasure(WXMEASUREITEMSTRUCT
*item
)
450 LPMEASUREITEMSTRUCT lpMeasureItem
= (LPMEASUREITEMSTRUCT
) item
;
451 int pos
= lpMeasureItem
->itemID
;
453 lpMeasureItem
->itemHeight
= wxBitmapComboBoxBase::MeasureItem(pos
);
458 #endif // wxUSE_BITMAPCOMBOBOX