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