]> git.saurik.com Git - wxWidgets.git/blame - src/msw/choice.cpp
Final and global PRIOR/NEXT change: keep consistency using only PAGE versions, deprec...
[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
aa61d352 239int wxChoice::DoInsert(const wxString& item, unsigned int pos)
243dbf1a
VZ
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
aa61d352 259void wxChoice::Delete(unsigned 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 {
aa61d352
VZ
292 unsigned int count = GetCount();
293 for ( unsigned int n = 0; n < count; n++ )
6c8a980f
VZ
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
aa61d352 329unsigned int wxChoice::GetCount() const
8d99be5f 330{
aa61d352 331 return (unsigned int)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.
aa61d352
VZ
339 unsigned int count = GetCount();
340 for ( unsigned int i = 0; i < count; i++ )
8d99be5f
VZ
341 {
342 // as CB_FINDSTRINGEXACT is case insensitive, be case insensitive too
aa61d352 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 {
aa61d352
VZ
353 unsigned int count = GetCount();
354 for ( unsigned int i = 0; i < count; i++ )
11e62fe6 355 {
aa61d352 356 if (GetString(i).empty())
11e62fe6
WS
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
aa61d352 377void wxChoice::SetString(unsigned 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
aa61d352 407wxString wxChoice::GetString(unsigned 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
aa61d352 433void wxChoice::DoSetItemClientData(unsigned 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
aa61d352 442void* wxChoice::DoGetItemClientData(unsigned 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
aa61d352 456void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
8d99be5f 457{
6c8a980f 458 DoSetItemClientData(n, clientData);
8d99be5f
VZ
459}
460
aa61d352 461wxClientData* wxChoice::DoGetItemClientObject(unsigned 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
e3e78de1
VZ
509 int widthCurrent, heightCurrent;
510 DoGetSize(&widthCurrent, &heightCurrent);
511
d99957b6
VZ
512 // the height which we must pass to Windows should be the total height of
513 // the control including the drop down list while the height given to us
514 // is, of course, just the height of the permanently visible part of it
e3e78de1 515 if ( height != wxDefaultCoord && height != heightCurrent )
d99957b6 516 {
e3e78de1
VZ
517 // don't make the drop down list too tall, arbitrarily limit it to 40
518 // items max and also don't leave it empty
aa61d352 519 unsigned int nItems = GetCount();
e3e78de1
VZ
520 if ( !nItems )
521 nItems = 9;
522 else if ( nItems > 24 )
523 nItems = 24;
524
525 // add space for the drop down list
526 const int hItem = SendMessage(GetHwnd(), CB_GETITEMHEIGHT, 0, 0);
527 height += hItem*(nItems + 1);
d99957b6 528 }
e3e78de1 529 else // keep the same height as now
d6959d6f 530 {
e3e78de1
VZ
531 // normally wxWindow::DoSetSize() checks if we set the same size as the
532 // window already has and does nothing in this case, but for us the
533 // check fails as the size we pass to it includes the dropdown while
534 // the size returned by our GetSize() does not, so test if the size
535 // didn't really change ourselves here
536 if ( width == wxDefaultCoord || width == widthCurrent )
537 {
538 // size doesn't change, what about position?
539 int xCurrent, yCurrent;
540 DoGetPosition(&xCurrent, &yCurrent);
541 const bool defMeansUnchanged = !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE);
542 if ( ((x == wxDefaultCoord && defMeansUnchanged) || x == xCurrent)
543 &&
544 ((y == wxDefaultCoord && defMeansUnchanged) || y == yCurrent) )
545 {
546 // nothing changes, nothing to do
547 return;
548 }
549 }
550
d6959d6f 551 // We cannot pass wxDefaultCoord as height to wxControl. wxControl uses
f31a4098
WS
552 // wxGetWindowRect() to determine the current height of the combobox,
553 // and then again sets the combobox's height to that value. Unfortunately,
554 // wxGetWindowRect doesn't include the dropdown list's height (at least
555 // on Win2K), so this would result in a combobox with dropdown height of
d6959d6f
DS
556 // 1 pixel. We have to determine the default height ourselves and call
557 // wxControl with that value instead.
e3e78de1
VZ
558 //
559 // Also notice that sometimes CB_GETDROPPEDCONTROLRECT seems to return
560 // wildly incorrect values (~32000) which looks like a bug in it, just
561 // ignore them in this case
d6959d6f 562 RECT r;
e3e78de1
VZ
563 if ( ::SendMessage(GetHwnd(), CB_GETDROPPEDCONTROLRECT, 0, (LPARAM) &r)
564 && r.bottom < 30000 )
d6959d6f 565 {
e3e78de1 566 height = heightCurrent + r.bottom - r.top;
d6959d6f
DS
567 }
568 }
d99957b6
VZ
569
570 wxControl::DoSetSize(x, y, width, height, sizeFlags);
571
ef036883
JS
572 // I'm commenting this out since the code appears to make choices
573 // and comboxes too high when they have associated sizers. I'm sure this
574 // is not the end of the story, which is why I'm leaving it #if'ed out for
575 // now. JACS.
576#if 0
d99957b6
VZ
577 // if the height specified for the visible part of the control is
578 // different from the current one, we need to change it separately
579 // as it is not affected by normal WM_SETSIZE
02b7b6b0 580 if ( height != wxDefaultCoord )
d99957b6 581 {
94a77ff7
VZ
582 const int delta = heightOrig - GetSize().y;
583 if ( delta )
d99957b6 584 {
94a77ff7
VZ
585 int h = ::SendMessage(GetHwnd(), CB_GETITEMHEIGHT, (WPARAM)-1, 0);
586 SendMessage(GetHwnd(), CB_SETITEMHEIGHT, (WPARAM)-1, h + delta);
d99957b6
VZ
587 }
588 }
e69ba9cb
WS
589#else
590 wxUnusedVar(heightOrig);
ef036883 591#endif
4438caf4 592}
2bda0e17 593
882a8f40 594wxSize wxChoice::DoGetBestSize() const
4438caf4
VZ
595{
596 // find the widest string
4438caf4 597 int wChoice = 0;
aa61d352
VZ
598 const unsigned int nItems = GetCount();
599 for ( unsigned int i = 0; i < nItems; i++ )
2bda0e17 600 {
d99957b6
VZ
601 int wLine;
602 GetTextExtent(GetString(i), &wLine, NULL);
4438caf4
VZ
603 if ( wLine > wChoice )
604 wChoice = wLine;
2bda0e17 605 }
fd3f686c 606
4438caf4
VZ
607 // give it some reasonable default value if there are no strings in the
608 // list
609 if ( wChoice == 0 )
610 wChoice = 100;
2bda0e17 611
d99957b6
VZ
612 // the combobox should be slightly larger than the widest string
613 wChoice += 5*GetCharWidth();
2bda0e17 614
1d13cc5d
RD
615 wxSize best(wChoice, EDIT_HEIGHT_FROM_CHAR_HEIGHT(GetCharHeight()));
616 CacheBestSize(best);
617 return best;
2bda0e17
KB
618}
619
c140b7e7 620WXLRESULT wxChoice::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
2bda0e17 621{
f499e614 622 switch ( nMsg )
2bda0e17 623 {
f499e614
VZ
624 case WM_LBUTTONUP:
625 {
626 int x = (int)LOWORD(lParam);
627 int y = (int)HIWORD(lParam);
628
629 // Ok, this is truly weird, but if a panel with a wxChoice
630 // loses the focus, then you get a *fake* WM_LBUTTONUP message
631 // with x = 65535 and y = 65535. Filter out this nonsense.
632 //
633 // VZ: I'd like to know how to reproduce this please...
634 if ( x == 65535 && y == 65535 )
635 return 0;
636 }
637 break;
638
639 // we have to handle both: one for the normal case and the other
640 // for readonly
641 case WM_CTLCOLOREDIT:
642 case WM_CTLCOLORLISTBOX:
643 case WM_CTLCOLORSTATIC:
644 {
f499e614
VZ
645 WXHDC hdc;
646 WXHWND hwnd;
9f368d0d 647 UnpackCtlColor(wParam, lParam, &hdc, &hwnd);
f499e614 648
2bae4332 649 WXHBRUSH hbr = MSWControlColor((WXHDC)hdc, hwnd);
48fa6bd3
VZ
650 if ( hbr )
651 return (WXLRESULT)hbr;
652 //else: fall through to default window proc
f499e614 653 }
2bda0e17
KB
654 }
655
8d99be5f 656 return wxWindow::MSWWindowProc(nMsg, wParam, lParam);
2bda0e17
KB
657}
658
8d99be5f 659bool wxChoice::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
2bda0e17 660{
c11f0412
VZ
661 /*
662 The native control provides a great variety in the events it sends in
663 the different selection scenarios (undoubtedly for greater amusement of
664 the programmers using it). For the reference, here are the cases when
665 the final selection is accepted (things are quite interesting when it
666 is cancelled too):
667
668 A. Selecting with just the arrows without opening the dropdown:
669 1. CBN_SELENDOK
670 2. CBN_SELCHANGE
671
672 B. Opening dropdown with F4 and selecting with arrows:
673 1. CBN_DROPDOWN
674 2. many CBN_SELCHANGE while changing selection in the list
675 3. CBN_SELENDOK
676 4. CBN_CLOSEUP
677
678 C. Selecting with the mouse:
679 1. CBN_DROPDOWN
680 -- no intermediate CBN_SELCHANGEs --
681 2. CBN_SELENDOK
682 3. CBN_CLOSEUP
683 4. CBN_SELCHANGE
684
685 Admire the different order of messages in all of those cases, it must
686 surely have taken a lot of effort to Microsoft developers to achieve
687 such originality.
688 */
6ba93d23 689 switch ( param )
2bda0e17 690 {
6ba93d23 691 case CBN_DROPDOWN:
c11f0412
VZ
692 // we use this value both because we don't want to track selection
693 // using CB_GETCURSEL while the dropdown is opened and because we
694 // need to reset the selection back to it if it's eventually
695 // cancelled by user
6ba93d23
VZ
696 m_lastAcceptedSelection = GetCurrentSelection();
697 break;
2bda0e17 698
6ba93d23 699 case CBN_CLOSEUP:
c11f0412
VZ
700 // if the selection was accepted by the user, it should have been
701 // reset to wxID_NONE by CBN_SELENDOK, otherwise the selection was
702 // cancelled and we must restore the old one
703 if ( m_lastAcceptedSelection != wxID_NONE )
704 {
705 SetSelection(m_lastAcceptedSelection);
706 m_lastAcceptedSelection = wxID_NONE;
707 }
6ba93d23
VZ
708 break;
709
c11f0412
VZ
710 case CBN_SELENDOK:
711 // reset it to prevent CBN_CLOSEUP from undoing the selection (it's
712 // ok to reset it now as GetCurrentSelection() will now return the
713 // same thing anyhow)
714 m_lastAcceptedSelection = wxID_NONE;
715
6ba93d23
VZ
716 {
717 const int n = GetSelection();
718
719 wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, m_windowId);
720 event.SetInt(n);
721 event.SetEventObject(this);
722
723 if ( n > -1 )
724 {
725 event.SetString(GetStringSelection());
726 if ( HasClientObjectData() )
727 event.SetClientObject( GetClientObject(n) );
728 else if ( HasClientUntypedData() )
729 event.SetClientData( GetClientData(n) );
730 }
731
732 ProcessCommand(event);
733 }
c11f0412
VZ
734 break;
735
736 // don't handle CBN_SELENDCANCEL: just leave m_lastAcceptedSelection
737 // valid and the selection will be undone in CBN_CLOSEUP above
738
739 // don't handle CBN_SELCHANGE neither, we don't want to generate events
740 // while the dropdown is opened -- but do add it if we ever need this
741
742 default:
743 return false;
8c1c5302 744 }
2bda0e17 745
c11f0412 746 return true;
8d99be5f 747}
2bda0e17 748
2bae4332 749WXHBRUSH wxChoice::MSWControlColor(WXHDC hDC, WXHWND hWnd)
f6bcfd97 750{
48fa6bd3
VZ
751 if ( !IsEnabled() )
752 return MSWControlColorDisabled(hDC);
f6bcfd97 753
2bae4332 754 return wxChoiceBase::MSWControlColor(hDC, hWnd);
f6bcfd97
BP
755}
756
3180bc0e 757#endif // wxUSE_CHOICE && !(__SMARTPHONE__ && __WXWINCE__)