]> git.saurik.com Git - wxWidgets.git/blame - src/msw/bmpcbox.cpp
Upgrade bundled zlib to 1.2.8.
[wxWidgets.git] / src / msw / bmpcbox.cpp
CommitLineData
f696015c 1/////////////////////////////////////////////////////////////////////////////
80fdcdb9 2// Name: src/msw/bmpcbox.cpp
f696015c
VZ
3// Purpose: wxBitmapComboBox
4// Author: Jaakko Salli
5// Created: 2008-04-06
f696015c
VZ
6// Copyright: (c) 2008 Jaakko Salli
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
18#include "wx/wxprec.h"
19
20#ifdef __BORLANDC__
21 #pragma hdrstop
22#endif
23
24#if wxUSE_BITMAPCOMBOBOX
25
26#include "wx/bmpcbox.h"
27
28#ifndef WX_PRECOMP
29 #include "wx/log.h"
30#endif
31
32#include "wx/settings.h"
4f082fb3 33#include "wx/vector.h"
f696015c
VZ
34
35#include "wx/msw/dcclient.h"
36#include "wx/msw/private.h"
37
38// For wxODCB_XXX flags
39#include "wx/odcombo.h"
40
41
42#define IMAGE_SPACING_CTRL_VERTICAL 7 // Spacing used in control size calculation
43
44
45// ============================================================================
46// implementation
47// ============================================================================
48
49
50BEGIN_EVENT_TABLE(wxBitmapComboBox, wxComboBox)
51 EVT_SIZE(wxBitmapComboBox::OnSize)
52END_EVENT_TABLE()
53
54
55IMPLEMENT_DYNAMIC_CLASS(wxBitmapComboBox, wxComboBox)
56
57
58// ----------------------------------------------------------------------------
59// wxBitmapComboBox creation
60// ----------------------------------------------------------------------------
61
62void wxBitmapComboBox::Init()
63{
64 m_inResize = false;
65}
66
67wxBitmapComboBox::wxBitmapComboBox(wxWindow *parent,
68 wxWindowID id,
69 const wxString& value,
70 const wxPoint& pos,
71 const wxSize& size,
72 const wxArrayString& choices,
73 long style,
74 const wxValidator& validator,
75 const wxString& name)
76 : wxComboBox(),
77 wxBitmapComboBoxBase()
78{
79 Init();
80
81 Create(parent,id,value,pos,size,choices,style,validator,name);
82}
83
84bool wxBitmapComboBox::Create(wxWindow *parent,
85 wxWindowID id,
86 const wxString& value,
87 const wxPoint& pos,
88 const wxSize& size,
89 const wxArrayString& choices,
90 long style,
91 const wxValidator& validator,
92 const wxString& name)
93{
94 wxCArrayString chs(choices);
95 return Create(parent, id, value, pos, size, chs.GetCount(),
96 chs.GetStrings(), style, validator, name);
97}
98
99bool wxBitmapComboBox::Create(wxWindow *parent,
100 wxWindowID id,
101 const wxString& value,
102 const wxPoint& pos,
103 const wxSize& size,
104 int n,
105 const wxString choices[],
106 long style,
107 const wxValidator& validator,
108 const wxString& name)
109{
110 if ( !wxComboBox::Create(parent, id, value, pos, size,
111 n, choices, style, validator, name) )
112 return false;
113
114 UpdateInternals();
115
116 return true;
117}
118
119WXDWORD wxBitmapComboBox::MSWGetStyle(long style, WXDWORD *exstyle) const
120{
121 return wxComboBox::MSWGetStyle(style, exstyle) | CBS_OWNERDRAWFIXED | CBS_HASSTRINGS;
122}
123
124void wxBitmapComboBox::RecreateControl()
125{
126 //
127 // Recreate control so that WM_MEASUREITEM gets called again.
128 // Can't use CBS_OWNERDRAWVARIABLE because it has odd
129 // mouse-wheel behaviour.
130 //
131 wxString value = GetValue();
132 wxPoint pos = GetPosition();
133 wxSize size = GetSize();
a9afb057 134 size.y = GetBestSize().y;
9e86876e
VZ
135 const wxArrayString strings = GetStrings();
136 const unsigned numItems = strings.size();
039d4cfb 137 unsigned i;
9e86876e
VZ
138
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 )
144 {
145 case wxClientData_None:
146 break;
147
148 case wxClientData_Object:
149 objectClientData.reserve(numItems);
039d4cfb
VZ
150 for ( i = 0; i < numItems; ++i )
151 objectClientData.push_back(GetClientObject(i));
9e86876e
VZ
152 break;
153
154 case wxClientData_Void:
155 voidClientData.reserve(numItems);
039d4cfb
VZ
156 for ( i = 0; i < numItems; ++i )
157 voidClientData.push_back(GetClientData(i));
9e86876e
VZ
158 break;
159 }
4f082fb3 160
f696015c
VZ
161 wxComboBox::DoClear();
162
163 HWND hwnd = GetHwnd();
164 DissociateHandle();
165 ::DestroyWindow(hwnd);
166
4f320d7c 167 if ( !MSWCreateControl(wxT("COMBOBOX"), wxEmptyString, pos, size) )
f696015c
VZ
168 return;
169
170 // initialize the controls contents
039d4cfb 171 for ( i = 0; i < numItems; i++ )
f696015c 172 {
9e86876e
VZ
173 wxComboBox::Append(strings[i]);
174
175 if ( !objectClientData.empty() )
176 SetClientObject(i, objectClientData[i]);
177 else if ( !voidClientData.empty() )
76e7cfab 178 SetClientData(i, voidClientData[i]);
f696015c
VZ
179 }
180
181 // and make sure it has the same attributes as before
182 if ( m_hasFont )
183 {
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
186 // that it did
187 wxFont font = m_font;
188 m_font = wxNullFont;
189 SetFont(font);
190 }
191
192 if ( m_hasFgCol )
193 {
194 wxColour colFg = m_foregroundColour;
195 m_foregroundColour = wxNullColour;
196 SetForegroundColour(colFg);
197 }
198
199 if ( m_hasBgCol )
200 {
201 wxColour colBg = m_backgroundColour;
202 m_backgroundColour = wxNullColour;
203 SetBackgroundColour(colBg);
204 }
205 else
206 {
207 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
208 }
a9afb057
JS
209
210 ::SendMessage(GetHwnd(), CB_SETITEMHEIGHT, 0, MeasureItem(0));
4f320d7c
JS
211
212 // Revert the old string value
df541b86
JS
213 if ( !HasFlag(wxCB_READONLY) )
214 ChangeValue(value);
f696015c
VZ
215}
216
217wxBitmapComboBox::~wxBitmapComboBox()
218{
219 Clear();
220}
221
41ce9ae1
JS
222wxSize wxBitmapComboBox::DoGetBestSize() const
223{
224 wxSize best = wxComboBox::DoGetBestSize();
225 wxSize bitmapSize = GetBitmapSize();
226
227 wxCoord useHeightBitmap = EDIT_HEIGHT_FROM_CHAR_HEIGHT(bitmapSize.y);
228 if ( best.y < useHeightBitmap )
229 {
230 best.y = useHeightBitmap;
231 CacheBestSize(best);
232 }
233 return best;
234}
235
f696015c
VZ
236// ----------------------------------------------------------------------------
237// Item manipulation
238// ----------------------------------------------------------------------------
239
240void wxBitmapComboBox::SetItemBitmap(unsigned int n, const wxBitmap& bitmap)
241{
242 OnAddBitmap(bitmap);
243 DoSetItemBitmap(n, bitmap);
244
245 if ( (int)n == GetSelection() )
246 Refresh();
247}
248
249int wxBitmapComboBox::Append(const wxString& item, const wxBitmap& bitmap)
250{
251 OnAddBitmap(bitmap);
252 const int n = wxComboBox::Append(item);
253 if ( n != wxNOT_FOUND )
254 DoSetItemBitmap(n, bitmap);
255 return n;
256}
257
258int wxBitmapComboBox::Append(const wxString& item, const wxBitmap& bitmap,
259 void *clientData)
260{
261 OnAddBitmap(bitmap);
262 const int n = wxComboBox::Append(item, clientData);
263 if ( n != wxNOT_FOUND )
264 DoSetItemBitmap(n, bitmap);
265 return n;
266}
267
268int wxBitmapComboBox::Append(const wxString& item, const wxBitmap& bitmap,
269 wxClientData *clientData)
270{
271 OnAddBitmap(bitmap);
272 const int n = wxComboBox::Append(item, clientData);
273 if ( n != wxNOT_FOUND )
274 DoSetItemBitmap(n, bitmap);
275 return n;
276}
277
278int wxBitmapComboBox::Insert(const wxString& item,
279 const wxBitmap& bitmap,
280 unsigned int pos)
281{
282 OnAddBitmap(bitmap);
283 const int n = wxComboBox::Insert(item, pos);
284 if ( n != wxNOT_FOUND )
285 DoSetItemBitmap(n, bitmap);
286 return n;
287}
288
05f5b3f7
VZ
289int wxBitmapComboBox::Insert(const wxString& item, const wxBitmap& bitmap,
290 unsigned int pos, void *clientData)
291{
292 OnAddBitmap(bitmap);
293 const int n = wxComboBox::Insert(item, pos, clientData);
294 if ( n != wxNOT_FOUND )
295 DoSetItemBitmap(n, bitmap);
296 return n;
297}
298
f696015c
VZ
299int wxBitmapComboBox::Insert(const wxString& item, const wxBitmap& bitmap,
300 unsigned int pos, wxClientData *clientData)
301{
302 OnAddBitmap(bitmap);
303 const int n = wxComboBox::Insert(item, pos, clientData);
304 if ( n != wxNOT_FOUND )
305 DoSetItemBitmap(n, bitmap);
306 return n;
307}
308
309int wxBitmapComboBox::DoInsertItems(const wxArrayStringsAdapter & items,
310 unsigned int pos,
311 void **clientData, wxClientDataType type)
312{
313 const unsigned int numItems = items.GetCount();
314 const unsigned int countNew = GetCount() + numItems;
315
befee9b7
JS
316 wxASSERT( numItems == 1 || !HasFlag(wxCB_SORT) ); // Sanity check
317
f696015c
VZ
318 m_bitmaps.Alloc(countNew);
319
320 for ( unsigned int i = 0; i < numItems; i++ )
321 {
322 m_bitmaps.Insert(new wxBitmap(wxNullBitmap), pos + i);
323 }
324
325 const int index = wxComboBox::DoInsertItems(items, pos,
326 clientData, type);
327
328 if ( index == wxNOT_FOUND )
329 {
330 for ( int i = numItems-1; i >= 0; i-- )
331 BCBDoDeleteOneItem(pos + i);
332 }
befee9b7
JS
333 else if ( ((unsigned int)index) != pos )
334 {
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);
340 }
f696015c
VZ
341
342 return index;
343}
344
345bool wxBitmapComboBox::OnAddBitmap(const wxBitmap& bitmap)
346{
347 if ( wxBitmapComboBoxBase::OnAddBitmap(bitmap) )
348 {
349 // Need to recreate control for a new measureitem call?
350 int prevItemHeight = ::SendMessage(GetHwnd(), CB_GETITEMHEIGHT, 0, 0);
351
352 if ( prevItemHeight != MeasureItem(0) )
353 RecreateControl();
354
355 return true;
356 }
03647350 357
f696015c
VZ
358 return false;
359}
360
361void wxBitmapComboBox::DoClear()
362{
363 wxComboBox::DoClear();
364 wxBitmapComboBoxBase::BCBDoClear();
365}
366
367void wxBitmapComboBox::DoDeleteOneItem(unsigned int n)
368{
369 wxComboBox::DoDeleteOneItem(n);
370 wxBitmapComboBoxBase::BCBDoDeleteOneItem(n);
371}
372
373// ----------------------------------------------------------------------------
374// wxBitmapComboBox event handlers and such
375// ----------------------------------------------------------------------------
376
377void wxBitmapComboBox::OnSize(wxSizeEvent& event)
378{
379 // Prevent infinite looping
380 if ( !m_inResize )
381 {
382 m_inResize = true;
383 DetermineIndent();
384 m_inResize = false;
385 }
386
387 event.Skip();
388}
389
390// ----------------------------------------------------------------------------
391// wxBitmapComboBox miscellaneous
392// ----------------------------------------------------------------------------
393
394bool wxBitmapComboBox::SetFont(const wxFont& font)
395{
396 bool res = wxComboBox::SetFont(font);
397 UpdateInternals();
398 return res;
399}
400
401// ----------------------------------------------------------------------------
402// wxBitmapComboBox item drawing and measuring
403// ----------------------------------------------------------------------------
404
405bool wxBitmapComboBox::MSWOnDraw(WXDRAWITEMSTRUCT *item)
406{
407 LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT) item;
408 int pos = lpDrawItem->itemID;
409
410 // Draw default for item -1, which means 'focus rect only'
411 if ( pos == -1 )
412 return FALSE;
413
03647350 414 int flags = 0;
f696015c
VZ
415 if ( lpDrawItem->itemState & ODS_COMBOBOXEDIT )
416 flags |= wxODCB_PAINTING_CONTROL;
417 if ( lpDrawItem->itemState & ODS_SELECTED )
418 flags |= wxODCB_PAINTING_SELECTED;
419
420 wxString text;
421
422 if ( flags & wxODCB_PAINTING_CONTROL )
423 {
424 text = GetValue();
425 if ( !HasFlag(wxCB_READONLY) )
426 text.clear();
427 }
428 else
429 {
430 text = GetString(pos);
431 }
432
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);
437
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);
443
444 return TRUE;
445}
446
447bool wxBitmapComboBox::MSWOnMeasure(WXMEASUREITEMSTRUCT *item)
448{
449 LPMEASUREITEMSTRUCT lpMeasureItem = (LPMEASUREITEMSTRUCT) item;
450 int pos = lpMeasureItem->itemID;
451
452 lpMeasureItem->itemHeight = wxBitmapComboBoxBase::MeasureItem(pos);
453
454 return TRUE;
455}
456
457#endif // wxUSE_BITMAPCOMBOBOX