]> git.saurik.com Git - wxWidgets.git/blob - src/msw/choice.cpp
merged Ctrl-Space fix from 2.2 branch
[wxWidgets.git] / src / msw / choice.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: choice.cpp
3 // Purpose: wxChoice
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin to derive from wxChoiceBase
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "choice.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/choice.h"
33 #include "wx/utils.h"
34 #include "wx/log.h"
35 #include "wx/brush.h"
36 #include "wx/settings.h"
37 #endif
38
39 #include "wx/msw/private.h"
40
41 IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl)
42
43 // ============================================================================
44 // implementation
45 // ============================================================================
46
47 // ----------------------------------------------------------------------------
48 // creation
49 // ----------------------------------------------------------------------------
50
51 bool wxChoice::Create(wxWindow *parent,
52 wxWindowID id,
53 const wxPoint& pos,
54 const wxSize& size,
55 int n, const wxString choices[],
56 long style,
57 const wxValidator& validator,
58 const wxString& name)
59 {
60 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
61 return FALSE;
62
63 long msStyle = WS_CHILD | CBS_DROPDOWNLIST | WS_TABSTOP | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL /* | WS_CLIPSIBLINGS */;
64 if ( style & wxCB_SORT )
65 msStyle |= CBS_SORT;
66
67 // Experience shows that wxChoice vs. wxComboBox distinction confuses
68 // quite a few people - try to help them
69 wxASSERT_MSG( !(style & wxCB_DROPDOWN) &&
70 !(style & wxCB_READONLY) &&
71 !(style & wxCB_SIMPLE),
72 _T("this style flag is ignored by wxChoice, you ")
73 _T("probably want to use a wxComboBox") );
74
75 if ( !MSWCreateControl(wxT("COMBOBOX"), msStyle) )
76 return FALSE;
77
78 // A choice/combobox normally has a white background (or other, depending
79 // on global settings) rather than inheriting the parent's background colour.
80 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
81
82 for ( int i = 0; i < n; i++ )
83 {
84 Append(choices[i]);
85 }
86
87 SetSize(pos.x, pos.y, size.x, size.y);
88
89 return TRUE;
90 }
91
92 wxChoice::~wxChoice()
93 {
94 Free();
95 }
96
97 // ----------------------------------------------------------------------------
98 // adding/deleting items to/from the list
99 // ----------------------------------------------------------------------------
100
101 int wxChoice::DoAppend(const wxString& item)
102 {
103 int n = (int)SendMessage(GetHwnd(), CB_ADDSTRING, 0, (LONG)item.c_str());
104 if ( n == CB_ERR )
105 {
106 wxLogLastError(wxT("SendMessage(CB_ADDSTRING)"));
107 }
108
109 return n;
110 }
111
112 void wxChoice::Delete(int n)
113 {
114 wxCHECK_RET( n < GetCount(), wxT("invalid item index in wxChoice::Delete") );
115
116 if ( HasClientObjectData() )
117 {
118 delete GetClientObject(n);
119 }
120
121 SendMessage(GetHwnd(), CB_DELETESTRING, n, 0);
122 }
123
124 void wxChoice::Clear()
125 {
126 Free();
127
128 SendMessage(GetHwnd(), CB_RESETCONTENT, 0, 0);
129 }
130
131 void wxChoice::Free()
132 {
133 if ( HasClientObjectData() )
134 {
135 size_t count = GetCount();
136 for ( size_t n = 0; n < count; n++ )
137 {
138 delete GetClientObject(n);
139 }
140 }
141 }
142
143 // ----------------------------------------------------------------------------
144 // selection
145 // ----------------------------------------------------------------------------
146
147 int wxChoice::GetSelection() const
148 {
149 return (int)SendMessage(GetHwnd(), CB_GETCURSEL, 0, 0);
150 }
151
152 void wxChoice::SetSelection(int n)
153 {
154 SendMessage(GetHwnd(), CB_SETCURSEL, n, 0);
155 }
156
157 // ----------------------------------------------------------------------------
158 // string list functions
159 // ----------------------------------------------------------------------------
160
161 int wxChoice::GetCount() const
162 {
163 return (int)SendMessage(GetHwnd(), CB_GETCOUNT, 0, 0);
164 }
165
166 int wxChoice::FindString(const wxString& s) const
167 {
168 #if defined(__WATCOMC__) && defined(__WIN386__)
169 // For some reason, Watcom in WIN386 mode crashes in the CB_FINDSTRINGEXACT message.
170 // wxChoice::Do it the long way instead.
171 int count = GetCount();
172 for ( int i = 0; i < count; i++ )
173 {
174 // as CB_FINDSTRINGEXACT is case insensitive, be case insensitive too
175 if ( GetString(i).IsSameAs(s, FALSE) )
176 return i;
177 }
178
179 return wxNOT_FOUND;
180 #else // !Watcom
181 int pos = (int)SendMessage(GetHwnd(), CB_FINDSTRINGEXACT,
182 (WPARAM)-1, (LPARAM)s.c_str());
183
184 return pos == LB_ERR ? wxNOT_FOUND : pos;
185 #endif // Watcom/!Watcom
186 }
187
188 void wxChoice::SetString(int n, const wxString& s)
189 {
190 wxFAIL_MSG(wxT("not implemented"));
191
192 #if 0 // should do this, but no Insert() so far
193 Delete(n);
194 Insert(n + 1, s);
195 #endif
196 }
197
198 wxString wxChoice::GetString(int n) const
199 {
200 size_t len = (size_t)::SendMessage(GetHwnd(), CB_GETLBTEXTLEN, n, 0);
201 wxString str;
202 if (len) {
203 if ( ::SendMessage(GetHwnd(), CB_GETLBTEXT, n,
204 (LPARAM)str.GetWriteBuf(len)) == CB_ERR ) {
205 wxLogLastError(wxT("SendMessage(CB_GETLBTEXT)"));
206 }
207 str.UngetWriteBuf();
208 }
209
210 return str;
211 }
212
213 // ----------------------------------------------------------------------------
214 // client data
215 // ----------------------------------------------------------------------------
216
217 void wxChoice::DoSetItemClientData( int n, void* clientData )
218 {
219 if ( SendMessage(GetHwnd(), CB_SETITEMDATA, n, (LPARAM)clientData) == CB_ERR )
220 {
221 wxLogLastError(wxT("CB_SETITEMDATA"));
222 }
223 }
224
225 void* wxChoice::DoGetItemClientData( int n ) const
226 {
227 LPARAM rc = SendMessage(GetHwnd(), CB_GETITEMDATA, n, 0);
228 if ( rc == CB_ERR )
229 {
230 wxLogLastError(wxT("CB_GETITEMDATA"));
231
232 // unfortunately, there is no way to return an error code to the user
233 rc = (LPARAM) NULL;
234 }
235
236 return (void *)rc;
237 }
238
239 void wxChoice::DoSetItemClientObject( int n, wxClientData* clientData )
240 {
241 DoSetItemClientData(n, clientData);
242 }
243
244 wxClientData* wxChoice::DoGetItemClientObject( int n ) const
245 {
246 return (wxClientData *)DoGetItemClientData(n);
247 }
248
249 // ----------------------------------------------------------------------------
250 // wxMSW specific helpers
251 // ----------------------------------------------------------------------------
252
253 void wxChoice::DoSetSize(int x, int y,
254 int width, int height,
255 int sizeFlags)
256 {
257 // Ignore height parameter because height doesn't mean 'initially
258 // displayed' height, it refers to the drop-down menu as well. The
259 // wxWindows interpretation is different; also, getting the size returns
260 // the _displayed_ size (NOT the drop down menu size) so
261 // setting-getting-setting size would not work.
262 wxControl::DoSetSize(x, y, width, -1, sizeFlags);
263 }
264
265 wxSize wxChoice::DoGetBestSize() const
266 {
267 // find the widest string
268 int wLine;
269 int wChoice = 0;
270 int nItems = GetCount();
271 for ( int i = 0; i < nItems; i++ )
272 {
273 wxString str(GetString(i));
274 GetTextExtent(str, &wLine, NULL);
275 if ( wLine > wChoice )
276 wChoice = wLine;
277 }
278
279 // give it some reasonable default value if there are no strings in the
280 // list
281 if ( wChoice == 0 )
282 wChoice = 100;
283
284 // the combobox should be larger than the widest string
285 int cx, cy;
286 wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
287
288 wChoice += 5*cx;
289
290 // Choice drop-down list depends on number of items (limited to 10)
291 size_t nStrings = nItems == 0 ? 10 : wxMin(10, nItems) + 1;
292 int hChoice = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy)*nStrings;
293
294 return wxSize(wChoice, hChoice);
295 }
296
297 long wxChoice::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
298 {
299 if ( nMsg == WM_LBUTTONUP )
300 {
301 int x = (int)LOWORD(lParam);
302 int y = (int)HIWORD(lParam);
303
304 // Ok, this is truly weird, but if a panel with a wxChoice loses the
305 // focus, then you get a *fake* WM_LBUTTONUP message with x = 65535 and
306 // y = 65535. Filter out this nonsense.
307 //
308 // VZ: I'd like to know how to reproduce this please...
309 if ( x == 65535 && y == 65535 )
310 return 0;
311 }
312
313 return wxWindow::MSWWindowProc(nMsg, wParam, lParam);
314 }
315
316 bool wxChoice::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
317 {
318 if ( param != CBN_SELCHANGE)
319 {
320 // "selection changed" is the only event we're after
321 return FALSE;
322 }
323
324 int n = GetSelection();
325 if (n > -1)
326 {
327 wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, m_windowId);
328 event.SetInt(n);
329 event.SetEventObject(this);
330 event.SetString(GetStringSelection());
331 if ( HasClientObjectData() )
332 event.SetClientObject( GetClientObject(n) );
333 else if ( HasClientUntypedData() )
334 event.SetClientData( GetClientData(n) );
335 ProcessCommand(event);
336 }
337
338 return TRUE;
339 }
340
341 WXHBRUSH wxChoice::OnCtlColor(WXHDC pDC, WXHWND pWnd, WXUINT nCtlColor,
342 WXUINT message,
343 WXWPARAM wParam,
344 WXLPARAM lParam)
345 {
346 #if wxUSE_CTL3D
347 if ( m_useCtl3D )
348 {
349 HBRUSH hbrush = Ctl3dCtlColorEx(message, wParam, lParam);
350 return (WXHBRUSH) hbrush;
351 }
352 #endif // wxUSE_CTL3D
353
354 HDC hdc = (HDC)pDC;
355 if (GetParent()->GetTransparentBackground())
356 SetBkMode(hdc, TRANSPARENT);
357 else
358 SetBkMode(hdc, OPAQUE);
359
360 wxColour colBack = GetBackgroundColour();
361
362 if (!IsEnabled())
363 colBack = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE);
364
365 ::SetBkColor(hdc, wxColourToRGB(colBack));
366 ::SetTextColor(hdc, wxColourToRGB(GetForegroundColour()));
367
368 wxBrush *brush = wxTheBrushList->FindOrCreateBrush(colBack, wxSOLID);
369
370 return (WXHBRUSH)brush->GetResourceHandle();
371 }
372
373