1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/bmpcbox.cpp
3 // Purpose: wxBitmapComboBox
4 // Author: Jaakko Salli
6 // Copyright: (c) 2008 Jaakko Salli
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 #include "wx/wxprec.h"
24 #if wxUSE_BITMAPCOMBOBOX
26 #include "wx/bmpcbox.h"
32 #include "wx/settings.h"
33 #include "wx/vector.h"
35 #include "wx/msw/dcclient.h"
36 #include "wx/msw/private.h"
38 // For wxODCB_XXX flags
39 #include "wx/odcombo.h"
42 #define IMAGE_SPACING_CTRL_VERTICAL 7 // Spacing used in control size calculation
45 // ============================================================================
47 // ============================================================================
50 BEGIN_EVENT_TABLE(wxBitmapComboBox
, wxComboBox
)
51 EVT_SIZE(wxBitmapComboBox::OnSize
)
55 IMPLEMENT_DYNAMIC_CLASS(wxBitmapComboBox
, wxComboBox
)
58 // ----------------------------------------------------------------------------
59 // wxBitmapComboBox creation
60 // ----------------------------------------------------------------------------
62 void wxBitmapComboBox::Init()
67 wxBitmapComboBox::wxBitmapComboBox(wxWindow
*parent
,
69 const wxString
& value
,
72 const wxArrayString
& choices
,
74 const wxValidator
& validator
,
77 wxBitmapComboBoxBase()
81 Create(parent
,id
,value
,pos
,size
,choices
,style
,validator
,name
);
84 bool wxBitmapComboBox::Create(wxWindow
*parent
,
86 const wxString
& value
,
89 const wxArrayString
& choices
,
91 const wxValidator
& validator
,
94 wxCArrayString
chs(choices
);
95 return Create(parent
, id
, value
, pos
, size
, chs
.GetCount(),
96 chs
.GetStrings(), style
, validator
, name
);
99 bool wxBitmapComboBox::Create(wxWindow
*parent
,
101 const wxString
& value
,
105 const wxString choices
[],
107 const wxValidator
& validator
,
108 const wxString
& name
)
110 if ( !wxComboBox::Create(parent
, id
, value
, pos
, size
,
111 n
, choices
, style
, validator
, name
) )
119 WXDWORD
wxBitmapComboBox::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
121 return wxComboBox::MSWGetStyle(style
, exstyle
) | CBS_OWNERDRAWFIXED
| CBS_HASSTRINGS
;
124 void wxBitmapComboBox::RecreateControl()
127 // Recreate control so that WM_MEASUREITEM gets called again.
128 // Can't use CBS_OWNERDRAWVARIABLE because it has odd
129 // mouse-wheel behaviour.
131 wxString value
= GetValue();
132 wxPoint pos
= GetPosition();
133 wxSize size
= GetSize();
134 size
.y
= GetBestSize().y
;
135 const wxArrayString strings
= GetStrings();
136 const unsigned numItems
= strings
.size();
139 // Save the client data pointers before clearing the control, if any.
140 const wxClientDataType clientDataType
= GetClientDataType();
141 wxVector
<wxClientData
*> objectClientData
;
142 wxVector
<void*> voidClientData
;
143 switch ( clientDataType
)
145 case wxClientData_None
:
148 case wxClientData_Object
:
149 objectClientData
.reserve(numItems
);
150 for ( i
= 0; i
< numItems
; ++i
)
151 objectClientData
.push_back(GetClientObject(i
));
154 case wxClientData_Void
:
155 voidClientData
.reserve(numItems
);
156 for ( i
= 0; i
< numItems
; ++i
)
157 voidClientData
.push_back(GetClientData(i
));
161 wxComboBox::DoClear();
163 HWND hwnd
= GetHwnd();
165 ::DestroyWindow(hwnd
);
167 if ( !MSWCreateControl(wxT("COMBOBOX"), wxEmptyString
, pos
, size
) )
170 // initialize the controls contents
171 for ( i
= 0; i
< numItems
; i
++ )
173 wxComboBox::Append(strings
[i
]);
175 if ( !objectClientData
.empty() )
176 SetClientObject(i
, objectClientData
[i
]);
177 else if ( !voidClientData
.empty() )
178 SetClientData(i
, voidClientData
[i
]);
181 // and make sure it has the same attributes as before
184 // calling SetFont(m_font) would do nothing as the code would
185 // notice that the font didn't change, so force it to believe
187 wxFont font
= m_font
;
194 wxColour colFg
= m_foregroundColour
;
195 m_foregroundColour
= wxNullColour
;
196 SetForegroundColour(colFg
);
201 wxColour colBg
= m_backgroundColour
;
202 m_backgroundColour
= wxNullColour
;
203 SetBackgroundColour(colBg
);
207 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
210 ::SendMessage(GetHwnd(), CB_SETITEMHEIGHT
, 0, MeasureItem(0));
212 // Revert the old string value
213 if ( !HasFlag(wxCB_READONLY
) )
217 wxBitmapComboBox::~wxBitmapComboBox()
222 wxSize
wxBitmapComboBox::DoGetBestSize() const
224 wxSize best
= wxComboBox::DoGetBestSize();
225 wxSize bitmapSize
= GetBitmapSize();
227 wxCoord useHeightBitmap
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(bitmapSize
.y
);
228 if ( best
.y
< useHeightBitmap
)
230 best
.y
= useHeightBitmap
;
236 // ----------------------------------------------------------------------------
238 // ----------------------------------------------------------------------------
240 void wxBitmapComboBox::SetItemBitmap(unsigned int n
, const wxBitmap
& bitmap
)
243 DoSetItemBitmap(n
, bitmap
);
245 if ( (int)n
== GetSelection() )
249 int wxBitmapComboBox::Append(const wxString
& item
, const wxBitmap
& bitmap
)
252 const int n
= wxComboBox::Append(item
);
253 if ( n
!= wxNOT_FOUND
)
254 DoSetItemBitmap(n
, bitmap
);
258 int wxBitmapComboBox::Append(const wxString
& item
, const wxBitmap
& bitmap
,
262 const int n
= wxComboBox::Append(item
, clientData
);
263 if ( n
!= wxNOT_FOUND
)
264 DoSetItemBitmap(n
, bitmap
);
268 int wxBitmapComboBox::Append(const wxString
& item
, const wxBitmap
& bitmap
,
269 wxClientData
*clientData
)
272 const int n
= wxComboBox::Append(item
, clientData
);
273 if ( n
!= wxNOT_FOUND
)
274 DoSetItemBitmap(n
, bitmap
);
278 int wxBitmapComboBox::Insert(const wxString
& item
,
279 const wxBitmap
& bitmap
,
283 const int n
= wxComboBox::Insert(item
, pos
);
284 if ( n
!= wxNOT_FOUND
)
285 DoSetItemBitmap(n
, bitmap
);
289 int wxBitmapComboBox::Insert(const wxString
& item
, const wxBitmap
& bitmap
,
290 unsigned int pos
, void *clientData
)
293 const int n
= wxComboBox::Insert(item
, pos
, clientData
);
294 if ( n
!= wxNOT_FOUND
)
295 DoSetItemBitmap(n
, bitmap
);
299 int wxBitmapComboBox::Insert(const wxString
& item
, const wxBitmap
& bitmap
,
300 unsigned int pos
, wxClientData
*clientData
)
303 const int n
= wxComboBox::Insert(item
, pos
, clientData
);
304 if ( n
!= wxNOT_FOUND
)
305 DoSetItemBitmap(n
, bitmap
);
309 int wxBitmapComboBox::DoInsertItems(const wxArrayStringsAdapter
& items
,
311 void **clientData
, wxClientDataType type
)
313 const unsigned int numItems
= items
.GetCount();
314 const unsigned int countNew
= GetCount() + numItems
;
316 wxASSERT( numItems
== 1 || !HasFlag(wxCB_SORT
) ); // Sanity check
318 m_bitmaps
.Alloc(countNew
);
320 for ( unsigned int i
= 0; i
< numItems
; i
++ )
322 m_bitmaps
.Insert(new wxBitmap(wxNullBitmap
), pos
+ i
);
325 const int index
= wxComboBox::DoInsertItems(items
, pos
,
328 if ( index
== wxNOT_FOUND
)
330 for ( int i
= numItems
-1; i
>= 0; i
-- )
331 BCBDoDeleteOneItem(pos
+ i
);
333 else if ( ((unsigned int)index
) != pos
)
335 // Move pre-inserted empty bitmap into correct position
336 // (usually happens when combo box has wxCB_SORT style)
337 wxBitmap
* bmp
= static_cast<wxBitmap
*>(m_bitmaps
[pos
]);
338 m_bitmaps
.RemoveAt(pos
);
339 m_bitmaps
.Insert(bmp
, index
);
345 bool wxBitmapComboBox::OnAddBitmap(const wxBitmap
& bitmap
)
347 if ( wxBitmapComboBoxBase::OnAddBitmap(bitmap
) )
349 // Need to recreate control for a new measureitem call?
350 int prevItemHeight
= ::SendMessage(GetHwnd(), CB_GETITEMHEIGHT
, 0, 0);
352 if ( prevItemHeight
!= MeasureItem(0) )
361 void wxBitmapComboBox::DoClear()
363 wxComboBox::DoClear();
364 wxBitmapComboBoxBase::BCBDoClear();
367 void wxBitmapComboBox::DoDeleteOneItem(unsigned int n
)
369 wxComboBox::DoDeleteOneItem(n
);
370 wxBitmapComboBoxBase::BCBDoDeleteOneItem(n
);
373 // ----------------------------------------------------------------------------
374 // wxBitmapComboBox event handlers and such
375 // ----------------------------------------------------------------------------
377 void wxBitmapComboBox::OnSize(wxSizeEvent
& event
)
379 // Prevent infinite looping
390 // ----------------------------------------------------------------------------
391 // wxBitmapComboBox miscellaneous
392 // ----------------------------------------------------------------------------
394 bool wxBitmapComboBox::SetFont(const wxFont
& font
)
396 bool res
= wxComboBox::SetFont(font
);
401 // ----------------------------------------------------------------------------
402 // wxBitmapComboBox item drawing and measuring
403 // ----------------------------------------------------------------------------
405 bool wxBitmapComboBox::MSWOnDraw(WXDRAWITEMSTRUCT
*item
)
407 LPDRAWITEMSTRUCT lpDrawItem
= (LPDRAWITEMSTRUCT
) item
;
408 int pos
= lpDrawItem
->itemID
;
410 // Draw default for item -1, which means 'focus rect only'
415 if ( lpDrawItem
->itemState
& ODS_COMBOBOXEDIT
)
416 flags
|= wxODCB_PAINTING_CONTROL
;
417 if ( lpDrawItem
->itemState
& ODS_SELECTED
)
418 flags
|= wxODCB_PAINTING_SELECTED
;
422 if ( flags
& wxODCB_PAINTING_CONTROL
)
425 if ( !HasFlag(wxCB_READONLY
) )
430 text
= GetString(pos
);
433 wxPaintDCEx
dc(this, lpDrawItem
->hDC
);
434 wxRect rect
= wxRectFromRECT(lpDrawItem
->rcItem
);
435 wxBitmapComboBoxBase::DrawBackground(dc
, rect
, pos
, flags
);
436 wxBitmapComboBoxBase::DrawItem(dc
, rect
, pos
, text
, flags
);
438 // If the item has the focus, draw focus rectangle.
439 // Commented out since regular combo box doesn't
440 // seem to do it either.
441 //if ( lpDrawItem->itemState & ODS_FOCUS )
442 // DrawFocusRect(lpDrawItem->hDC, &lpDrawItem->rcItem);
447 bool wxBitmapComboBox::MSWOnMeasure(WXMEASUREITEMSTRUCT
*item
)
449 LPMEASUREITEMSTRUCT lpMeasureItem
= (LPMEASUREITEMSTRUCT
) item
;
450 int pos
= lpMeasureItem
->itemID
;
452 lpMeasureItem
->itemHeight
= wxBitmapComboBoxBase::MeasureItem(pos
);
457 #endif // wxUSE_BITMAPCOMBOBOX