]> git.saurik.com Git - wxWidgets.git/blame - src/msw/choice.cpp
Fix for command bar not painting in Windows Mobile 5
[wxWidgets.git] / src / msw / choice.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
11e62fe6 2// Name: src/msw/choice.cpp
2bda0e17
KB
3// Purpose: wxChoice
4// Author: Julian Smart
8d99be5f 5// Modified by: Vadim Zeitlin to derive from wxChoiceBase
2bda0e17
KB
6// Created: 04/01/98
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
8d99be5f
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
2bda0e17
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
8d99be5f 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
3180bc0e 27#if wxUSE_CHOICE && !(defined(__SMARTPHONE__) && defined(__WXWINCE__))
1e6feb95 28
2bda0e17 29#ifndef WX_PRECOMP
8d99be5f
VZ
30 #include "wx/choice.h"
31 #include "wx/utils.h"
32 #include "wx/log.h"
f6bcfd97 33 #include "wx/brush.h"
c7401637 34 #include "wx/settings.h"
2bda0e17
KB
35#endif
36
37#include "wx/msw/private.h"
38
6a89f9ee 39#if wxUSE_EXTENDED_RTTI
bc9fb572
JS
40WX_DEFINE_FLAGS( wxChoiceStyle )
41
3ff066a4 42wxBEGIN_FLAGS( wxChoiceStyle )
bc9fb572
JS
43 // new style border flags, we put them first to
44 // use them for streaming out
3ff066a4
SC
45 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
46 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
47 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
48 wxFLAGS_MEMBER(wxBORDER_RAISED)
49 wxFLAGS_MEMBER(wxBORDER_STATIC)
50 wxFLAGS_MEMBER(wxBORDER_NONE)
3dfb79a6 51
bc9fb572 52 // old style border flags
3ff066a4
SC
53 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
54 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
55 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
56 wxFLAGS_MEMBER(wxRAISED_BORDER)
57 wxFLAGS_MEMBER(wxSTATIC_BORDER)
cb0afb26 58 wxFLAGS_MEMBER(wxBORDER)
bc9fb572
JS
59
60 // standard window styles
3ff066a4
SC
61 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
62 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
63 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
64 wxFLAGS_MEMBER(wxWANTS_CHARS)
cb0afb26 65 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
3ff066a4
SC
66 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
67 wxFLAGS_MEMBER(wxVSCROLL)
68 wxFLAGS_MEMBER(wxHSCROLL)
bc9fb572 69
3ff066a4 70wxEND_FLAGS( wxChoiceStyle )
bc9fb572
JS
71
72IMPLEMENT_DYNAMIC_CLASS_XTI(wxChoice, wxControl,"wx/choice.h")
6a89f9ee 73
3ff066a4 74wxBEGIN_PROPERTIES_TABLE(wxChoice)
3dfb79a6 75 wxEVENT_PROPERTY( Select , wxEVT_COMMAND_CHOICE_SELECTED , wxCommandEvent )
c5ca409b 76
af498247 77 wxPROPERTY( Font , wxFont , SetFont , GetFont , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
3ff066a4 78 wxPROPERTY_COLLECTION( Choices , wxArrayString , wxString , AppendString , GetStrings , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
3dfb79a6 79 wxPROPERTY( Selection ,int, SetSelection, GetSelection, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
af498247 80 wxPROPERTY_FLAGS( WindowStyle , wxChoiceStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
3ff066a4 81wxEND_PROPERTIES_TABLE()
6a89f9ee 82
3ff066a4
SC
83wxBEGIN_HANDLERS_TABLE(wxChoice)
84wxEND_HANDLERS_TABLE()
2bda0e17 85
3dfb79a6 86wxCONSTRUCTOR_4( wxChoice , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size )
6a89f9ee
SC
87#else
88IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl)
89#endif
066f1b7a 90/*
3dfb79a6
VZ
91 TODO PROPERTIES
92 selection (long)
93 content (list)
94 item
066f1b7a
SC
95*/
96
8d99be5f
VZ
97// ============================================================================
98// implementation
99// ============================================================================
100
101// ----------------------------------------------------------------------------
102// creation
103// ----------------------------------------------------------------------------
104
105bool wxChoice::Create(wxWindow *parent,
106 wxWindowID id,
107 const wxPoint& pos,
108 const wxSize& size,
109 int n, const wxString choices[],
110 long style,
111 const wxValidator& validator,
112 const wxString& name)
2bda0e17 113{
f6bcfd97 114 // Experience shows that wxChoice vs. wxComboBox distinction confuses
8d99be5f
VZ
115 // quite a few people - try to help them
116 wxASSERT_MSG( !(style & wxCB_DROPDOWN) &&
117 !(style & wxCB_READONLY) &&
118 !(style & wxCB_SIMPLE),
f6bcfd97
BP
119 _T("this style flag is ignored by wxChoice, you ")
120 _T("probably want to use a wxComboBox") );
2bda0e17 121
71e57cd6
VZ
122 return CreateAndInit(parent, id, pos, size, n, choices, style,
123 validator, name);
124}
125
cc61d2eb
VZ
126bool wxChoice::CreateAndInit(wxWindow *parent,
127 wxWindowID id,
71e57cd6 128 const wxPoint& pos,
3dfb79a6 129 const wxSize& size,
71e57cd6
VZ
130 int n, const wxString choices[],
131 long style,
132 const wxValidator& validator,
133 const wxString& name)
134{
135 // initialize wxControl
136 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
02b7b6b0 137 return false;
2bda0e17 138
71e57cd6 139 // now create the real HWND
f31a4098 140 if ( !MSWCreateControl(wxT("COMBOBOX"), wxEmptyString, pos, size) )
02b7b6b0 141 return false;
71e57cd6
VZ
142
143
144 // choice/combobox normally has "white" (depends on colour scheme, of
145 // course) background rather than inheriting the parent's background
a756f210 146 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
c92d798f 147
cc61d2eb 148 // initialize the controls contents
8d99be5f
VZ
149 for ( int i = 0; i < n; i++ )
150 {
151 Append(choices[i]);
152 }
2bda0e17 153
cc61d2eb 154 // and now we may finally size the control properly (if needed)
3dfb79a6 155 SetBestSize(size);
cc61d2eb 156
02b7b6b0 157 return true;
2bda0e17
KB
158}
159
584ad2a3
MB
160bool wxChoice::Create(wxWindow *parent,
161 wxWindowID id,
162 const wxPoint& pos,
163 const wxSize& size,
164 const wxArrayString& choices,
165 long style,
166 const wxValidator& validator,
167 const wxString& name)
168{
169 wxCArrayString chs(choices);
170 return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
171 style, validator, name);
172}
173
4b17d2e3
DS
174bool wxChoice::MSWShouldPreProcessMessage(WXMSG *pMsg)
175{
176 MSG *msg = (MSG *) pMsg;
177
dc302518
DS
178 // if the dropdown list is visible, don't preprocess certain keys
179 if ( msg->message == WM_KEYDOWN
180 && (msg->wParam == VK_ESCAPE || msg->wParam == VK_RETURN) )
4b17d2e3
DS
181 {
182 if (::SendMessage(GetHwndOf(this), CB_GETDROPPEDSTATE, 0, 0))
183 {
184 return false;
185 }
186 }
187
188 return wxControl::MSWShouldPreProcessMessage(pMsg);
189}
190
71e57cd6
VZ
191WXDWORD wxChoice::MSWGetStyle(long style, WXDWORD *exstyle) const
192{
193 // we never have an external border
194 WXDWORD msStyle = wxControl::MSWGetStyle
195 (
196 (style & ~wxBORDER_MASK) | wxBORDER_NONE, exstyle
197 );
198
199 // WS_CLIPSIBLINGS is useful with wxChoice and doesn't seem to result in
200 // any problems
201 msStyle |= WS_CLIPSIBLINGS;
202
203 // wxChoice-specific styles
204 msStyle |= CBS_DROPDOWNLIST | WS_HSCROLL | WS_VSCROLL;
205 if ( style & wxCB_SORT )
206 msStyle |= CBS_SORT;
207
208 return msStyle;
209}
210
8ee9d618
VZ
211wxChoice::~wxChoice()
212{
213 Free();
214}
215
8d99be5f
VZ
216// ----------------------------------------------------------------------------
217// adding/deleting items to/from the list
218// ----------------------------------------------------------------------------
2bda0e17 219
def6fb9b 220int wxChoice::DoAppend(const wxString& item)
8d99be5f 221{
c140b7e7 222 int n = (int)SendMessage(GetHwnd(), CB_ADDSTRING, 0, (LPARAM)item.c_str());
def6fb9b
VZ
223 if ( n == CB_ERR )
224 {
f6bcfd97 225 wxLogLastError(wxT("SendMessage(CB_ADDSTRING)"));
def6fb9b 226 }
71e57cd6
VZ
227 else // ok
228 {
229 // we need to refresh our size in order to have enough space for the
230 // newly added items
e0e3a32d
VZ
231 if ( !IsFrozen() )
232 UpdateVisibleHeight();
71e57cd6 233 }
def6fb9b 234
31582e4e 235 InvalidateBestSize();
def6fb9b 236 return n;
2bda0e17
KB
237}
238
243dbf1a
VZ
239int wxChoice::DoInsert(const wxString& item, int pos)
240{
241 wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
8228b893 242 wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index"));
243dbf1a 243
c140b7e7 244 int n = (int)SendMessage(GetHwnd(), CB_INSERTSTRING, pos, (LPARAM)item.c_str());
243dbf1a
VZ
245 if ( n == CB_ERR )
246 {
247 wxLogLastError(wxT("SendMessage(CB_INSERTSTRING)"));
248 }
71e57cd6
VZ
249 else // ok
250 {
e0e3a32d
VZ
251 if ( !IsFrozen() )
252 UpdateVisibleHeight();
71e57cd6 253 }
243dbf1a 254
31582e4e 255 InvalidateBestSize();
243dbf1a
VZ
256 return n;
257}
258
debe6624 259void wxChoice::Delete(int n)
2bda0e17 260{
8228b893 261 wxCHECK_RET( IsValid(n), wxT("invalid item index in wxChoice::Delete") );
8d99be5f 262
6c8a980f
VZ
263 if ( HasClientObjectData() )
264 {
265 delete GetClientObject(n);
266 }
267
8d99be5f 268 SendMessage(GetHwnd(), CB_DELETESTRING, n, 0);
71e57cd6 269
e0e3a32d
VZ
270 if ( !IsFrozen() )
271 UpdateVisibleHeight();
31582e4e
RD
272
273 InvalidateBestSize();
2bda0e17
KB
274}
275
8d99be5f 276void wxChoice::Clear()
8ee9d618 277{
92d2389e 278 Free();
8ee9d618
VZ
279
280 SendMessage(GetHwnd(), CB_RESETCONTENT, 0, 0);
71e57cd6 281
e0e3a32d
VZ
282 if ( !IsFrozen() )
283 UpdateVisibleHeight();
31582e4e
RD
284
285 InvalidateBestSize();
8ee9d618
VZ
286}
287
288void wxChoice::Free()
2bda0e17 289{
6c8a980f
VZ
290 if ( HasClientObjectData() )
291 {
292 size_t count = GetCount();
293 for ( size_t n = 0; n < count; n++ )
294 {
295 delete GetClientObject(n);
296 }
297 }
2bda0e17
KB
298}
299
8d99be5f
VZ
300// ----------------------------------------------------------------------------
301// selection
302// ----------------------------------------------------------------------------
2bda0e17 303
8d99be5f 304int wxChoice::GetSelection() const
6ba93d23
VZ
305{
306 // if m_lastAcceptedSelection is set, it means that the dropdown is
307 // currently shown and that we want to use the last "permanent" selection
308 // instead of whatever is under the mouse pointer currently
309 //
310 // otherwise, get the selection from the control
311 return m_lastAcceptedSelection == wxID_NONE ? GetCurrentSelection()
312 : m_lastAcceptedSelection;
313}
314
315int wxChoice::GetCurrentSelection() const
2bda0e17 316{
8d99be5f 317 return (int)SendMessage(GetHwnd(), CB_GETCURSEL, 0, 0);
2bda0e17
KB
318}
319
debe6624 320void wxChoice::SetSelection(int n)
2bda0e17 321{
8d99be5f
VZ
322 SendMessage(GetHwnd(), CB_SETCURSEL, n, 0);
323}
324
325// ----------------------------------------------------------------------------
326// string list functions
327// ----------------------------------------------------------------------------
328
8228b893 329size_t wxChoice::GetCount() const
8d99be5f 330{
8228b893 331 return (size_t)SendMessage(GetHwnd(), CB_GETCOUNT, 0, 0);
2bda0e17
KB
332}
333
11e62fe6 334int wxChoice::FindString(const wxString& s, bool bCase) const
2bda0e17
KB
335{
336#if defined(__WATCOMC__) && defined(__WIN386__)
8d99be5f
VZ
337 // For some reason, Watcom in WIN386 mode crashes in the CB_FINDSTRINGEXACT message.
338 // wxChoice::Do it the long way instead.
8228b893
WS
339 size_t count = GetCount();
340 for ( size_t i = 0; i < count; i++ )
8d99be5f
VZ
341 {
342 // as CB_FINDSTRINGEXACT is case insensitive, be case insensitive too
11e62fe6 343 if ( GetString(i).IsSameAs(s, bCase) )
8d99be5f
VZ
344 return i;
345 }
346
347 return wxNOT_FOUND;
348#else // !Watcom
4cd1ed99
RN
349 //TODO: Evidently some MSW versions (all?) don't like empty strings
350 //passed to SendMessage, so we have to do it ourselves in that case
beedefb9 351 if ( s.empty() )
4cd1ed99 352 {
8228b893
WS
353 size_t count = GetCount();
354 for ( size_t i = 0; i < count; i++ )
11e62fe6
WS
355 {
356 if ( GetString(i).empty() )
357 return i;
358 }
359
360 return wxNOT_FOUND;
361 }
362 else if (bCase)
363 {
364 // back to base class search for not native search type
365 return wxItemContainerImmutable::FindString( s, bCase );
4cd1ed99
RN
366 }
367 else
368 {
11e62fe6
WS
369 int pos = (int)SendMessage(GetHwnd(), CB_FINDSTRINGEXACT,
370 (WPARAM)-1, (LPARAM)s.c_str());
f31a4098 371
11e62fe6 372 return pos == LB_ERR ? wxNOT_FOUND : pos;
4cd1ed99 373 }
8d99be5f 374#endif // Watcom/!Watcom
2bda0e17
KB
375}
376
b4bfa452 377void wxChoice::SetString(int n, const wxString& s)
6c8a980f 378{
8228b893 379 wxCHECK_RET( IsValid(n), wxT("invalid item index in wxChoice::SetString") );
2b5f62a0
VZ
380
381 // we have to delete and add back the string as there is no way to change a
382 // string in place
383
384 // we need to preserve the client data
385 void *data;
386 if ( m_clientDataItemsType != wxClientData_None )
387 {
388 data = DoGetItemClientData(n);
389 }
390 else // no client data
391 {
392 data = NULL;
393 }
394
395 ::SendMessage(GetHwnd(), CB_DELETESTRING, n, 0);
396 ::SendMessage(GetHwnd(), CB_INSERTSTRING, n, (LPARAM)s.c_str() );
397
398 if ( data )
399 {
400 DoSetItemClientData(n, data);
401 }
402 //else: it's already NULL by default
31582e4e
RD
403
404 InvalidateBestSize();
6c8a980f
VZ
405}
406
debe6624 407wxString wxChoice::GetString(int n) const
2bda0e17 408{
478cabab
VZ
409 int len = (int)::SendMessage(GetHwnd(), CB_GETLBTEXTLEN, n, 0);
410
6c8a980f 411 wxString str;
478cabab
VZ
412 if ( len != CB_ERR && len > 0 )
413 {
414 if ( ::SendMessage
415 (
416 GetHwnd(),
417 CB_GETLBTEXT,
418 n,
419 (LPARAM)(wxChar *)wxStringBuffer(str, len)
420 ) == CB_ERR )
421 {
f6bcfd97 422 wxLogLastError(wxT("SendMessage(CB_GETLBTEXT)"));
21d72d17 423 }
4438caf4 424 }
2bda0e17 425
4438caf4
VZ
426 return str;
427}
2bda0e17 428
8d99be5f
VZ
429// ----------------------------------------------------------------------------
430// client data
431// ----------------------------------------------------------------------------
432
6c8a980f 433void wxChoice::DoSetItemClientData( int n, void* clientData )
8d99be5f 434{
2b5f62a0
VZ
435 if ( ::SendMessage(GetHwnd(), CB_SETITEMDATA,
436 n, (LPARAM)clientData) == CB_ERR )
8d99be5f 437 {
223d09f6 438 wxLogLastError(wxT("CB_SETITEMDATA"));
8d99be5f
VZ
439 }
440}
441
6c8a980f 442void* wxChoice::DoGetItemClientData( int n ) const
8d99be5f
VZ
443{
444 LPARAM rc = SendMessage(GetHwnd(), CB_GETITEMDATA, n, 0);
445 if ( rc == CB_ERR )
446 {
223d09f6 447 wxLogLastError(wxT("CB_GETITEMDATA"));
8d99be5f
VZ
448
449 // unfortunately, there is no way to return an error code to the user
8ee9d618 450 rc = (LPARAM) NULL;
8d99be5f
VZ
451 }
452
453 return (void *)rc;
454}
455
6c8a980f 456void wxChoice::DoSetItemClientObject( int n, wxClientData* clientData )
8d99be5f 457{
6c8a980f 458 DoSetItemClientData(n, clientData);
8d99be5f
VZ
459}
460
6c8a980f 461wxClientData* wxChoice::DoGetItemClientObject( int n ) const
8d99be5f 462{
6c8a980f 463 return (wxClientData *)DoGetItemClientData(n);
8d99be5f
VZ
464}
465
466// ----------------------------------------------------------------------------
467// wxMSW specific helpers
468// ----------------------------------------------------------------------------
469
71e57cd6
VZ
470void wxChoice::UpdateVisibleHeight()
471{
e6968367 472 // be careful to not change the width here
02b7b6b0 473 DoSetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, GetSize().y, wxSIZE_USE_EXISTING);
71e57cd6
VZ
474}
475
18c50997
VZ
476void wxChoice::DoMoveWindow(int x, int y, int width, int height)
477{
478 // here is why this is necessary: if the width is negative, the combobox
479 // window proc makes the window of the size width*height instead of
480 // interpreting height in the usual manner (meaning the height of the drop
481 // down list - usually the height specified in the call to MoveWindow()
482 // will not change the height of combo box per se)
483 //
484 // this behaviour is not documented anywhere, but this is just how it is
485 // here (NT 4.4) and, anyhow, the check shouldn't hurt - however without
486 // the check, constraints/sizers using combos may break the height
487 // constraint will have not at all the same value as expected
488 if ( width < 0 )
489 return;
490
491 wxControl::DoMoveWindow(x, y, width, height);
492}
493
d99957b6
VZ
494void wxChoice::DoGetSize(int *w, int *h) const
495{
94a77ff7
VZ
496 // this is weird: sometimes, the height returned by Windows is clearly the
497 // total height of the control including the drop down list -- but only
498 // sometimes, and normally it isn't... I have no idea about what to do with
499 // this
02b7b6b0 500 wxControl::DoGetSize(w, h);
d99957b6
VZ
501}
502
4438caf4 503void wxChoice::DoSetSize(int x, int y,
d99957b6 504 int width, int height,
4438caf4
VZ
505 int sizeFlags)
506{
d99957b6 507 int heightOrig = height;
a8e65eee 508
d99957b6
VZ
509 // the height which we must pass to Windows should be the total height of
510 // the control including the drop down list while the height given to us
511 // is, of course, just the height of the permanently visible part of it
02b7b6b0 512 if ( height != wxDefaultCoord )
d99957b6
VZ
513 {
514 // don't make the drop down list too tall, arbitrarily limit it to 40
515 // items max and also don't leave it empty
516 size_t nItems = GetCount();
517 if ( !nItems )
518 nItems = 9;
cb828946
RD
519 else if ( nItems > 24 )
520 nItems = 24;
d99957b6
VZ
521
522 // add space for the drop down list
523 const int hItem = SendMessage(GetHwnd(), CB_GETITEMHEIGHT, 0, 0);
524 height += hItem*(nItems + 1);
525 }
d6959d6f
DS
526 else
527 {
528 // We cannot pass wxDefaultCoord as height to wxControl. wxControl uses
f31a4098
WS
529 // wxGetWindowRect() to determine the current height of the combobox,
530 // and then again sets the combobox's height to that value. Unfortunately,
531 // wxGetWindowRect doesn't include the dropdown list's height (at least
532 // on Win2K), so this would result in a combobox with dropdown height of
d6959d6f
DS
533 // 1 pixel. We have to determine the default height ourselves and call
534 // wxControl with that value instead.
535 int w, h;
536 RECT r;
537 DoGetSize(&w, &h);
538 if (::SendMessage(GetHwnd(), CB_GETDROPPEDCONTROLRECT, 0, (LPARAM) &r) != 0)
539 {
f31a4098 540 height = h + r.bottom - r.top;
d6959d6f
DS
541 }
542 }
d99957b6
VZ
543
544 wxControl::DoSetSize(x, y, width, height, sizeFlags);
545
ef036883
JS
546 // I'm commenting this out since the code appears to make choices
547 // and comboxes too high when they have associated sizers. I'm sure this
548 // is not the end of the story, which is why I'm leaving it #if'ed out for
549 // now. JACS.
550#if 0
d99957b6
VZ
551 // if the height specified for the visible part of the control is
552 // different from the current one, we need to change it separately
553 // as it is not affected by normal WM_SETSIZE
02b7b6b0 554 if ( height != wxDefaultCoord )
d99957b6 555 {
94a77ff7
VZ
556 const int delta = heightOrig - GetSize().y;
557 if ( delta )
d99957b6 558 {
94a77ff7
VZ
559 int h = ::SendMessage(GetHwnd(), CB_GETITEMHEIGHT, (WPARAM)-1, 0);
560 SendMessage(GetHwnd(), CB_SETITEMHEIGHT, (WPARAM)-1, h + delta);
d99957b6
VZ
561 }
562 }
e69ba9cb
WS
563#else
564 wxUnusedVar(heightOrig);
ef036883 565#endif
4438caf4 566}
2bda0e17 567
882a8f40 568wxSize wxChoice::DoGetBestSize() const
4438caf4
VZ
569{
570 // find the widest string
4438caf4 571 int wChoice = 0;
d99957b6
VZ
572 const size_t nItems = GetCount();
573 for ( size_t i = 0; i < nItems; i++ )
2bda0e17 574 {
d99957b6
VZ
575 int wLine;
576 GetTextExtent(GetString(i), &wLine, NULL);
4438caf4
VZ
577 if ( wLine > wChoice )
578 wChoice = wLine;
2bda0e17 579 }
fd3f686c 580
4438caf4
VZ
581 // give it some reasonable default value if there are no strings in the
582 // list
583 if ( wChoice == 0 )
584 wChoice = 100;
2bda0e17 585
d99957b6
VZ
586 // the combobox should be slightly larger than the widest string
587 wChoice += 5*GetCharWidth();
2bda0e17 588
1d13cc5d
RD
589 wxSize best(wChoice, EDIT_HEIGHT_FROM_CHAR_HEIGHT(GetCharHeight()));
590 CacheBestSize(best);
591 return best;
2bda0e17
KB
592}
593
c140b7e7 594WXLRESULT wxChoice::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
2bda0e17 595{
f499e614 596 switch ( nMsg )
2bda0e17 597 {
f499e614
VZ
598 case WM_LBUTTONUP:
599 {
600 int x = (int)LOWORD(lParam);
601 int y = (int)HIWORD(lParam);
602
603 // Ok, this is truly weird, but if a panel with a wxChoice
604 // loses the focus, then you get a *fake* WM_LBUTTONUP message
605 // with x = 65535 and y = 65535. Filter out this nonsense.
606 //
607 // VZ: I'd like to know how to reproduce this please...
608 if ( x == 65535 && y == 65535 )
609 return 0;
610 }
611 break;
612
613 // we have to handle both: one for the normal case and the other
614 // for readonly
615 case WM_CTLCOLOREDIT:
616 case WM_CTLCOLORLISTBOX:
617 case WM_CTLCOLORSTATIC:
618 {
f499e614
VZ
619 WXHDC hdc;
620 WXHWND hwnd;
9f368d0d 621 UnpackCtlColor(wParam, lParam, &hdc, &hwnd);
f499e614 622
2bae4332 623 WXHBRUSH hbr = MSWControlColor((WXHDC)hdc, hwnd);
48fa6bd3
VZ
624 if ( hbr )
625 return (WXLRESULT)hbr;
626 //else: fall through to default window proc
f499e614 627 }
2bda0e17
KB
628 }
629
8d99be5f 630 return wxWindow::MSWWindowProc(nMsg, wParam, lParam);
2bda0e17
KB
631}
632
8d99be5f 633bool wxChoice::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
2bda0e17 634{
c11f0412
VZ
635 /*
636 The native control provides a great variety in the events it sends in
637 the different selection scenarios (undoubtedly for greater amusement of
638 the programmers using it). For the reference, here are the cases when
639 the final selection is accepted (things are quite interesting when it
640 is cancelled too):
641
642 A. Selecting with just the arrows without opening the dropdown:
643 1. CBN_SELENDOK
644 2. CBN_SELCHANGE
645
646 B. Opening dropdown with F4 and selecting with arrows:
647 1. CBN_DROPDOWN
648 2. many CBN_SELCHANGE while changing selection in the list
649 3. CBN_SELENDOK
650 4. CBN_CLOSEUP
651
652 C. Selecting with the mouse:
653 1. CBN_DROPDOWN
654 -- no intermediate CBN_SELCHANGEs --
655 2. CBN_SELENDOK
656 3. CBN_CLOSEUP
657 4. CBN_SELCHANGE
658
659 Admire the different order of messages in all of those cases, it must
660 surely have taken a lot of effort to Microsoft developers to achieve
661 such originality.
662 */
6ba93d23 663 switch ( param )
2bda0e17 664 {
6ba93d23 665 case CBN_DROPDOWN:
c11f0412
VZ
666 // we use this value both because we don't want to track selection
667 // using CB_GETCURSEL while the dropdown is opened and because we
668 // need to reset the selection back to it if it's eventually
669 // cancelled by user
6ba93d23
VZ
670 m_lastAcceptedSelection = GetCurrentSelection();
671 break;
2bda0e17 672
6ba93d23 673 case CBN_CLOSEUP:
c11f0412
VZ
674 // if the selection was accepted by the user, it should have been
675 // reset to wxID_NONE by CBN_SELENDOK, otherwise the selection was
676 // cancelled and we must restore the old one
677 if ( m_lastAcceptedSelection != wxID_NONE )
678 {
679 SetSelection(m_lastAcceptedSelection);
680 m_lastAcceptedSelection = wxID_NONE;
681 }
6ba93d23
VZ
682 break;
683
c11f0412
VZ
684 case CBN_SELENDOK:
685 // reset it to prevent CBN_CLOSEUP from undoing the selection (it's
686 // ok to reset it now as GetCurrentSelection() will now return the
687 // same thing anyhow)
688 m_lastAcceptedSelection = wxID_NONE;
689
6ba93d23
VZ
690 {
691 const int n = GetSelection();
692
693 wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, m_windowId);
694 event.SetInt(n);
695 event.SetEventObject(this);
696
697 if ( n > -1 )
698 {
699 event.SetString(GetStringSelection());
700 if ( HasClientObjectData() )
701 event.SetClientObject( GetClientObject(n) );
702 else if ( HasClientUntypedData() )
703 event.SetClientData( GetClientData(n) );
704 }
705
706 ProcessCommand(event);
707 }
c11f0412
VZ
708 break;
709
710 // don't handle CBN_SELENDCANCEL: just leave m_lastAcceptedSelection
711 // valid and the selection will be undone in CBN_CLOSEUP above
712
713 // don't handle CBN_SELCHANGE neither, we don't want to generate events
714 // while the dropdown is opened -- but do add it if we ever need this
715
716 default:
717 return false;
8c1c5302 718 }
2bda0e17 719
c11f0412 720 return true;
8d99be5f 721}
2bda0e17 722
2bae4332 723WXHBRUSH wxChoice::MSWControlColor(WXHDC hDC, WXHWND hWnd)
f6bcfd97 724{
48fa6bd3
VZ
725 if ( !IsEnabled() )
726 return MSWControlColorDisabled(hDC);
f6bcfd97 727
2bae4332 728 return wxChoiceBase::MSWControlColor(hDC, hWnd);
f6bcfd97
BP
729}
730
3180bc0e 731#endif // wxUSE_CHOICE && !(__SMARTPHONE__ && __WXWINCE__)