]> git.saurik.com Git - wxWidgets.git/blame - src/msw/wince/choicece.cpp
removed called to deprecated wxPixelData::UseAlpha() which does nothing now
[wxWidgets.git] / src / msw / wince / choicece.cpp
CommitLineData
1550d5f8
WS
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/msw/wince/choicece.cpp
8300f815 3// Purpose: wxChoice implementation for smart phones driven by WinCE
1550d5f8
WS
4// Author: Wlodzimierz ABX Skiba
5// Modified by:
6// Created: 29.07.2004
7// RCS-ID: $Id$
8// Copyright: (c) Wlodzimierz Skiba
9// License: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
1550d5f8
WS
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
1550d5f8
WS
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
8228b893
WS
27#if wxUSE_CHOICE && defined(__SMARTPHONE__) && defined(__WXWINCE__)
28
b36e08d0
WS
29#include "wx/choice.h"
30
1550d5f8 31#ifndef WX_PRECOMP
57bd4c60 32 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
1550d5f8
WS
33#endif
34
35#include "wx/spinbutt.h" // for wxSpinnerBestSize
36
1550d5f8
WS
37#if wxUSE_EXTENDED_RTTI
38// TODO
39#else
40IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl)
41#endif
42
43#define GetBuddyHwnd() (HWND)(m_hwndBuddy)
44
45#define IsVertical(wxStyle) ( (wxStyle & wxSP_HORIZONTAL) != wxSP_HORIZONTAL )
46
47// ----------------------------------------------------------------------------
48// constants
49// ----------------------------------------------------------------------------
50
51// the margin between the up-down control and its buddy (can be arbitrary,
52// choose what you like - or may be decide during run-time depending on the
53// font size?)
54static const int MARGIN_BETWEEN = 0;
55
56// ============================================================================
57// implementation
58// ============================================================================
59
60wxArrayChoiceSpins wxChoice::ms_allChoiceSpins;
61
62// ----------------------------------------------------------------------------
63// wnd proc for the buddy text ctrl
64// ----------------------------------------------------------------------------
65
66LRESULT APIENTRY _EXPORT wxBuddyChoiceWndProc(HWND hwnd,
67 UINT message,
68 WPARAM wParam,
69 LPARAM lParam)
70{
71 wxChoice *spin = (wxChoice *)wxGetWindowUserData(hwnd);
72
73 // forward some messages (the key and focus ones only so far) to
74 // the spin ctrl
75 switch ( message )
76 {
77 case WM_SETFOCUS:
78 // if the focus comes from the spin control itself, don't set it
79 // back to it -- we don't want to go into an infinite loop
80 if ( (WXHWND)wParam == spin->GetHWND() )
81 break;
82 //else: fall through
83
84 case WM_KILLFOCUS:
85 case WM_CHAR:
86 case WM_DEADCHAR:
87 case WM_KEYUP:
88 case WM_KEYDOWN:
89 spin->MSWWindowProc(message, wParam, lParam);
90
91 // The control may have been deleted at this point, so check.
92 if ( !::IsWindow(hwnd) || wxGetWindowUserData(hwnd) != spin )
93 return 0;
94 break;
95
96 case WM_GETDLGCODE:
97 // we want to get WXK_RETURN in order to generate the event for it
98 return DLGC_WANTCHARS;
99 }
100
101 return ::CallWindowProc(CASTWNDPROC spin->GetBuddyWndProc(),
102 hwnd, message, wParam, lParam);
103}
104
01d2bf4d
WS
105wxChoice *wxChoice::GetChoiceForListBox(WXHWND hwndBuddy)
106{
107 wxChoice *choice = (wxChoice *)wxGetWindowUserData((HWND)hwndBuddy);
108
109 int i = ms_allChoiceSpins.Index(choice);
110
111 if ( i == wxNOT_FOUND )
112 return NULL;
113
114 // sanity check
115 wxASSERT_MSG( choice->m_hwndBuddy == hwndBuddy,
116 _T("wxChoice has incorrect buddy HWND!") );
117
118 return choice;
119}
120
1550d5f8
WS
121// ----------------------------------------------------------------------------
122// creation
123// ----------------------------------------------------------------------------
124
125bool wxChoice::Create(wxWindow *parent,
126 wxWindowID id,
127 const wxPoint& pos,
128 const wxSize& size,
129 int n, const wxString choices[],
130 long style,
131 const wxValidator& validator,
132 const wxString& name)
133{
134 return CreateAndInit(parent, id, pos, size, n, choices, style,
135 validator, name);
136}
137
138bool wxChoice::CreateAndInit(wxWindow *parent,
139 wxWindowID id,
140 const wxPoint& pos,
141 const wxSize& size,
142 int n, const wxString choices[],
143 long style,
144 const wxValidator& validator,
145 const wxString& name)
146{
147 if ( !(style & wxSP_VERTICAL) )
148 style |= wxSP_HORIZONTAL;
149
150 if ( (style & wxBORDER_MASK) == wxBORDER_DEFAULT )
151 style |= wxBORDER_SIMPLE;
152
153 style |= wxSP_ARROW_KEYS;
154
155 SetWindowStyle(style);
156
157 WXDWORD exStyle = 0;
158 WXDWORD msStyle = MSWGetStyle(GetWindowStyle(), & exStyle) ;
159
160 wxSize sizeText(size), sizeBtn(size);
5aaabb37 161 sizeBtn.x = GetBestSpinnerSize(IsVertical(style)).x;
1550d5f8 162
1550d5f8
WS
163 if ( sizeText.x == wxDefaultCoord )
164 {
165 // DEFAULT_ITEM_WIDTH is the default width for the text control
166 sizeText.x = DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN + sizeBtn.x;
167 }
168
169 sizeText.x -= sizeBtn.x + MARGIN_BETWEEN;
170 if ( sizeText.x <= 0 )
171 {
172 wxLogDebug(_T("not enough space for wxSpinCtrl!"));
173 }
174
175 wxPoint posBtn(pos);
176 posBtn.x += sizeText.x + MARGIN_BETWEEN;
177
178 // we must create the list control before the spin button for the purpose
179 // of the dialog navigation: if there is a static text just before the spin
180 // control, activating it by Alt-letter should give focus to the text
181 // control, not the spin and the dialog navigation code will give focus to
182 // the next control (at Windows level), not the one after it
183
184 // create the text window
185
186 m_hwndBuddy = (WXHWND)::CreateWindowEx
187 (
188 exStyle, // sunken border
189 _T("LISTBOX"), // window class
190 NULL, // no window title
191 msStyle, // style (will be shown later)
192 pos.x, pos.y, // position
193 0, 0, // size (will be set later)
194 GetHwndOf(parent), // parent
195 (HMENU)-1, // control id
196 wxGetInstance(), // app instance
197 NULL // unused client data
198 );
199
200 if ( !m_hwndBuddy )
201 {
202 wxLogLastError(wxT("CreateWindow(buddy text window)"));
203
204 return false;
205 }
206
207 // initialize wxControl
208 if ( !CreateControl(parent, id, posBtn, sizeBtn, style, validator, name) )
209 return false;
210
211 // now create the real HWND
212 WXDWORD spiner_style = WS_VISIBLE |
213 UDS_ALIGNRIGHT |
214 UDS_ARROWKEYS |
215 UDS_SETBUDDYINT |
216 UDS_EXPANDABLE;
217
218 if ( !IsVertical(style) )
219 spiner_style |= UDS_HORZ;
220
221 if ( style & wxSP_WRAP )
222 spiner_style |= UDS_WRAP;
223
11e62fe6 224 if ( !MSWCreateControl(UPDOWN_CLASS, spiner_style, posBtn, sizeBtn, wxEmptyString, 0) )
1550d5f8
WS
225 return false;
226
227 // subclass the text ctrl to be able to intercept some events
228 wxSetWindowUserData(GetBuddyHwnd(), this);
229 m_wndProcBuddy = (WXFARPROC)wxSetWindowProc(GetBuddyHwnd(),
230 wxBuddyChoiceWndProc);
231
232 // set up fonts and colours (This is nomally done in MSWCreateControl)
233 InheritAttributes();
234 if (!m_hasFont)
235 SetFont(GetDefaultAttributes().font);
236
237 // set the size of the text window - can do it only now, because we
238 // couldn't call DoGetBestSize() before as font wasn't set
239 if ( sizeText.y <= 0 )
240 {
241 int cx, cy;
242 wxGetCharSize(GetHWND(), &cx, &cy, GetFont());
243
244 sizeText.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
245 }
246
170acdc9 247 SetInitialSize(size);
1550d5f8
WS
248
249 (void)::ShowWindow(GetBuddyHwnd(), SW_SHOW);
250
251 // associate the list window with the spin button
252 (void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)GetBuddyHwnd(), 0);
253
254 // do it after finishing with m_hwndBuddy creation to avoid generating
255 // initial wxEVT_COMMAND_TEXT_UPDATED message
256 ms_allChoiceSpins.Add(this);
257
258 // initialize the controls contents
259 for ( int i = 0; i < n; i++ )
260 {
261 Append(choices[i]);
262 }
263
264 return true;
265}
266
267bool wxChoice::Create(wxWindow *parent,
268 wxWindowID id,
269 const wxPoint& pos,
270 const wxSize& size,
271 const wxArrayString& choices,
272 long style,
273 const wxValidator& validator,
274 const wxString& name)
275{
276 wxCArrayString chs(choices);
277 return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
278 style, validator, name);
279}
280
281WXDWORD wxChoice::MSWGetStyle(long style, WXDWORD *exstyle) const
282{
283 // we never have an external border
284 WXDWORD msStyle = wxControl::MSWGetStyle
285 (
286 (style & ~wxBORDER_MASK) | wxBORDER_NONE, exstyle
287 );
288
289 msStyle |= WS_VISIBLE;
290
291 // wxChoice-specific styles
292 msStyle |= LBS_NOINTEGRALHEIGHT;
293 if ( style & wxCB_SORT )
294 msStyle |= LBS_SORT;
295
01d2bf4d
WS
296 msStyle |= LBS_NOTIFY;
297
1550d5f8
WS
298 return msStyle;
299}
300
01d2bf4d
WS
301bool wxChoice::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
302{
303 if ( param != LBN_SELCHANGE)
304 {
305 // "selection changed" is the only event we're after
306 return false;
307 }
308
309 int n = GetSelection();
310 if (n > -1)
311 {
312 wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, m_windowId);
313 event.SetInt(n);
314 event.SetEventObject(this);
315 event.SetString(GetStringSelection());
316 if ( HasClientObjectData() )
317 event.SetClientObject( GetClientObject(n) );
318 else if ( HasClientUntypedData() )
319 event.SetClientData( GetClientData(n) );
320 ProcessCommand(event);
321 }
322
323 return true;
324}
325
1550d5f8
WS
326wxChoice::~wxChoice()
327{
328 Free();
329}
330
331// ----------------------------------------------------------------------------
332// adding/deleting items to/from the list
333// ----------------------------------------------------------------------------
334
335int wxChoice::DoAppend(const wxString& item)
336{
39fc096d 337 int n = (int)::SendMessage(GetBuddyHwnd(), LB_ADDSTRING, 0, (LPARAM)item.c_str());
1550d5f8
WS
338
339 if ( n == LB_ERR )
340 {
341 wxLogLastError(wxT("SendMessage(LB_ADDSTRING)"));
342 }
343
344 return n;
345}
346
aa61d352 347int wxChoice::DoInsert(const wxString& item, unsigned int pos)
1550d5f8
WS
348{
349 wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into choice"));
8228b893 350 wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index"));
1550d5f8 351
39fc096d 352 int n = (int)::SendMessage(GetBuddyHwnd(), LB_INSERTSTRING, pos, (LPARAM)item.c_str());
1550d5f8
WS
353 if ( n == LB_ERR )
354 {
355 wxLogLastError(wxT("SendMessage(LB_INSERTSTRING)"));
356 }
357
358 return n;
359}
360
aa61d352 361void wxChoice::Delete(unsigned int n)
1550d5f8 362{
8228b893 363 wxCHECK_RET( IsValid(n), wxT("invalid item index in wxChoice::Delete") );
1550d5f8
WS
364
365 if ( HasClientObjectData() )
366 {
367 delete GetClientObject(n);
368 }
369
39fc096d 370 ::SendMessage(GetBuddyHwnd(), LB_DELETESTRING, n, 0);
1550d5f8
WS
371}
372
373void wxChoice::Clear()
374{
375 Free();
376
39fc096d 377 ::SendMessage(GetBuddyHwnd(), LB_RESETCONTENT, 0, 0);
1550d5f8
WS
378}
379
380void wxChoice::Free()
381{
382 if ( HasClientObjectData() )
383 {
aa61d352
VZ
384 unsigned int count = GetCount();
385 for ( unsigned int n = 0; n < count; n++ )
1550d5f8
WS
386 {
387 delete GetClientObject(n);
388 }
389 }
390}
391
392// ----------------------------------------------------------------------------
393// selection
394// ----------------------------------------------------------------------------
395
396int wxChoice::GetSelection() const
397{
39fc096d 398 return (int)::SendMessage(GetBuddyHwnd(), LB_GETCURSEL, 0, 0);
1550d5f8
WS
399}
400
401void wxChoice::SetSelection(int n)
402{
39fc096d 403 ::SendMessage(GetBuddyHwnd(), LB_SETCURSEL, n, 0);
1550d5f8
WS
404}
405
406// ----------------------------------------------------------------------------
407// string list functions
408// ----------------------------------------------------------------------------
409
aa61d352 410unsigned int wxChoice::GetCount() const
1550d5f8 411{
aa61d352 412 return (unsigned int)::SendMessage(GetBuddyHwnd(), LB_GETCOUNT, 0, 0);
1550d5f8
WS
413}
414
11e62fe6 415int wxChoice::FindString(const wxString& s, bool bCase) const
1550d5f8 416{
11e62fe6
WS
417 // back to base class search for not native search type
418 if (bCase)
419 return wxItemContainerImmutable::FindString( s, bCase );
420
39fc096d 421 int pos = (int)::SendMessage(GetBuddyHwnd(), LB_FINDSTRINGEXACT,
1550d5f8
WS
422 (WPARAM)-1, (LPARAM)s.c_str());
423
424 return pos == LB_ERR ? wxNOT_FOUND : pos;
425}
426
aa61d352 427void wxChoice::SetString(unsigned int n, const wxString& s)
1550d5f8 428{
8228b893 429 wxCHECK_RET( IsValid(n),
1550d5f8
WS
430 wxT("invalid item index in wxChoice::SetString") );
431
432 // we have to delete and add back the string as there is no way to change a
433 // string in place
434
435 // we need to preserve the client data
436 void *data;
437 if ( m_clientDataItemsType != wxClientData_None )
438 {
439 data = DoGetItemClientData(n);
440 }
441 else // no client data
442 {
443 data = NULL;
444 }
445
446 ::SendMessage(GetBuddyHwnd(), LB_DELETESTRING, n, 0);
447 ::SendMessage(GetBuddyHwnd(), LB_INSERTSTRING, n, (LPARAM)s.c_str() );
448
449 if ( data )
450 {
451 DoSetItemClientData(n, data);
452 }
453 //else: it's already NULL by default
454}
455
aa61d352 456wxString wxChoice::GetString(unsigned int n) const
1550d5f8
WS
457{
458 int len = (int)::SendMessage(GetBuddyHwnd(), LB_GETTEXTLEN, n, 0);
459
460 wxString str;
461 if ( len != LB_ERR && len > 0 )
462 {
463 if ( ::SendMessage
464 (
465 GetBuddyHwnd(),
466 LB_GETTEXT,
467 n,
468 (LPARAM)(wxChar *)wxStringBuffer(str, len)
469 ) == LB_ERR )
470 {
471 wxLogLastError(wxT("SendMessage(LB_GETLBTEXT)"));
472 }
473 }
474
475 return str;
476}
477
478// ----------------------------------------------------------------------------
479// client data
480// ----------------------------------------------------------------------------
481
aa61d352 482void wxChoice::DoSetItemClientData(unsigned int n, void* clientData)
1550d5f8
WS
483{
484 if ( ::SendMessage(GetHwnd(), LB_SETITEMDATA,
485 n, (LPARAM)clientData) == LB_ERR )
486 {
487 wxLogLastError(wxT("LB_SETITEMDATA"));
488 }
489}
490
aa61d352 491void* wxChoice::DoGetItemClientData(unsigned int n) const
1550d5f8 492{
39fc096d 493 LPARAM rc = ::SendMessage(GetHwnd(), LB_GETITEMDATA, n, 0);
1550d5f8
WS
494 if ( rc == LB_ERR )
495 {
496 wxLogLastError(wxT("LB_GETITEMDATA"));
497
498 // unfortunately, there is no way to return an error code to the user
499 rc = (LPARAM) NULL;
500 }
501
502 return (void *)rc;
503}
504
aa61d352 505void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
1550d5f8
WS
506{
507 DoSetItemClientData(n, clientData);
508}
509
aa61d352 510wxClientData* wxChoice::DoGetItemClientObject(unsigned int n) const
1550d5f8
WS
511{
512 return (wxClientData *)DoGetItemClientData(n);
513}
514
515// ----------------------------------------------------------------------------
516// size calculations
517// ----------------------------------------------------------------------------
518
519wxSize wxChoice::DoGetBestSize() const
520{
5aaabb37 521 wxSize sizeBtn = GetBestSpinnerSize(IsVertical(GetWindowStyle()));
1550d5f8
WS
522 sizeBtn.x += DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN;
523
524 int y;
525 wxGetCharSize(GetHWND(), NULL, &y, GetFont());
526 y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(y);
527
528 // JACS: we should always use the height calculated
529 // from above, because otherwise we'll get a spin control
530 // that's too big. So never use the height calculated
531 // from wxSpinButton::DoGetBestSize().
532
533 // if ( sizeBtn.y < y )
534 {
535 // make the text tall enough
536 sizeBtn.y = y;
537 }
538
539 return sizeBtn;
540}
541
542void wxChoice::DoMoveWindow(int x, int y, int width, int height)
543{
5aaabb37 544 int widthBtn = GetBestSpinnerSize(IsVertical(GetWindowStyle())).x;
1550d5f8
WS
545 int widthText = width - widthBtn - MARGIN_BETWEEN;
546 if ( widthText <= 0 )
547 {
548 wxLogDebug(_T("not enough space for wxSpinCtrl!"));
549 }
550
551 if ( !::MoveWindow(GetBuddyHwnd(), x, y, widthText, height, TRUE) )
552 {
553 wxLogLastError(wxT("MoveWindow(buddy)"));
554 }
555
556 x += widthText + MARGIN_BETWEEN;
557 if ( !::MoveWindow(GetHwnd(), x, y, widthBtn, height, TRUE) )
558 {
559 wxLogLastError(wxT("MoveWindow"));
560 }
561}
562
563// get total size of the control
564void wxChoice::DoGetSize(int *x, int *y) const
565{
566 RECT spinrect, textrect, ctrlrect;
567 GetWindowRect(GetHwnd(), &spinrect);
568 GetWindowRect(GetBuddyHwnd(), &textrect);
569 UnionRect(&ctrlrect, &textrect, &spinrect);
570
571 if ( x )
572 *x = ctrlrect.right - ctrlrect.left;
573 if ( y )
574 *y = ctrlrect.bottom - ctrlrect.top;
575}
576
577void wxChoice::DoGetPosition(int *x, int *y) const
578{
579 // hack: pretend that our HWND is the text control just for a moment
580 WXHWND hWnd = GetHWND();
581 wxConstCast(this, wxChoice)->m_hWnd = m_hwndBuddy;
582
583 wxChoiceBase::DoGetPosition(x, y);
584
585 wxConstCast(this, wxChoice)->m_hWnd = hWnd;
586}
587
8300f815 588#endif // wxUSE_CHOICE && __SMARTPHONE__ && __WXWINCE__