]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/choice.cpp
Rotated text patch from Hans-Joachim Baader (with some corrections)
[wxWidgets.git] / src / msw / choice.cpp
... / ...
CommitLineData
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#endif
36
37#include "wx/msw/private.h"
38
39#if !USE_SHARED_LIBRARY
40 IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl)
41#endif
42
43// ============================================================================
44// implementation
45// ============================================================================
46
47// ----------------------------------------------------------------------------
48// creation
49// ----------------------------------------------------------------------------
50
51bool 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 // A choice/combobox normally has a white background (or other, depending
64 // on global settings) rather than inheriting the parent's background colour.
65 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
66
67 long msStyle = WS_CHILD | CBS_DROPDOWNLIST | WS_TABSTOP | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;
68 if ( style & wxCB_SORT )
69 msStyle |= CBS_SORT;
70
71 // the experience shows that wxChoice vs. wxComboBox distinction confuses
72 // quite a few people - try to help them
73 wxASSERT_MSG( !(style & wxCB_DROPDOWN) &&
74 !(style & wxCB_READONLY) &&
75 !(style & wxCB_SIMPLE),
76 wxT("this style flag is ignored by wxChoice, you "
77 "probably want to use a wxComboBox") );
78
79 if ( !MSWCreateControl(wxT("COMBOBOX"), msStyle) )
80 return FALSE;
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
92wxChoice::~wxChoice()
93{
94 Free();
95}
96
97// ----------------------------------------------------------------------------
98// adding/deleting items to/from the list
99// ----------------------------------------------------------------------------
100
101int 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("SendMessage(CB_ADDSTRING)");
107 }
108
109 return n;
110}
111
112void 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
124void wxChoice::Clear()
125{
126 Free();
127
128 SendMessage(GetHwnd(), CB_RESETCONTENT, 0, 0);
129}
130
131void 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
147int wxChoice::GetSelection() const
148{
149 return (int)SendMessage(GetHwnd(), CB_GETCURSEL, 0, 0);
150}
151
152void wxChoice::SetSelection(int n)
153{
154 SendMessage(GetHwnd(), CB_SETCURSEL, n, 0);
155}
156
157// ----------------------------------------------------------------------------
158// string list functions
159// ----------------------------------------------------------------------------
160
161int wxChoice::GetCount() const
162{
163 return (int)SendMessage(GetHwnd(), CB_GETCOUNT, 0, 0);
164}
165
166int 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
188void 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
198wxString 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("SendMessage(CB_GETLBTEXT)");
206 }
207 str.UngetWriteBuf();
208 }
209
210 return str;
211}
212
213// ----------------------------------------------------------------------------
214// client data
215// ----------------------------------------------------------------------------
216
217void 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
225void* 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
239void wxChoice::DoSetItemClientObject( int n, wxClientData* clientData )
240{
241 DoSetItemClientData(n, clientData);
242}
243
244wxClientData* wxChoice::DoGetItemClientObject( int n ) const
245{
246 return (wxClientData *)DoGetItemClientData(n);
247}
248
249// ----------------------------------------------------------------------------
250// wxMSW specific helpers
251// ----------------------------------------------------------------------------
252
253void 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
265wxSize wxChoice::DoGetBestSize()
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
297long 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
316bool 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