]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/wince/choicece.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/wince/choicece.cpp
3 // Purpose: wxChoice implementation for smart phones driven by WinCE
4 // Author: Wlodzimierz ABX Skiba
8 // Copyright: (c) Wlodzimierz Skiba
9 // License: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
13 // ============================================================================
15 // ============================================================================
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
21 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
22 #pragma implementation "choicece.h"
25 // For compilers that support precompilation, includes "wx.h".
26 #include "wx/wxprec.h"
33 #include "wx/choice.h"
36 #include "wx/spinbutt.h" // for wxSpinnerBestSize
39 #include "wx/msw/missing.h"
40 #include "wx/msw/winundef.h"
42 #if wxUSE_CHOICE && defined(__SMARTPHONE__) && defined(__WXWINCE__)
44 #if wxUSE_EXTENDED_RTTI
47 IMPLEMENT_DYNAMIC_CLASS(wxChoice
, wxControl
)
50 #define GetBuddyHwnd() (HWND)(m_hwndBuddy)
52 #define IsVertical(wxStyle) ( (wxStyle & wxSP_HORIZONTAL) != wxSP_HORIZONTAL )
54 // ----------------------------------------------------------------------------
56 // ----------------------------------------------------------------------------
58 // the margin between the up-down control and its buddy (can be arbitrary,
59 // choose what you like - or may be decide during run-time depending on the
61 static const int MARGIN_BETWEEN
= 0;
63 // ============================================================================
65 // ============================================================================
67 wxArrayChoiceSpins
wxChoice::ms_allChoiceSpins
;
69 // ----------------------------------------------------------------------------
70 // wnd proc for the buddy text ctrl
71 // ----------------------------------------------------------------------------
73 LRESULT APIENTRY _EXPORT
wxBuddyChoiceWndProc(HWND hwnd
,
78 wxChoice
*spin
= (wxChoice
*)wxGetWindowUserData(hwnd
);
80 // forward some messages (the key and focus ones only so far) to
85 // if the focus comes from the spin control itself, don't set it
86 // back to it -- we don't want to go into an infinite loop
87 if ( (WXHWND
)wParam
== spin
->GetHWND() )
96 spin
->MSWWindowProc(message
, wParam
, lParam
);
98 // The control may have been deleted at this point, so check.
99 if ( !::IsWindow(hwnd
) || wxGetWindowUserData(hwnd
) != spin
)
104 // we want to get WXK_RETURN in order to generate the event for it
105 return DLGC_WANTCHARS
;
108 return ::CallWindowProc(CASTWNDPROC spin
->GetBuddyWndProc(),
109 hwnd
, message
, wParam
, lParam
);
112 // ----------------------------------------------------------------------------
114 // ----------------------------------------------------------------------------
116 bool wxChoice::Create(wxWindow
*parent
,
120 int n
, const wxString choices
[],
122 const wxValidator
& validator
,
123 const wxString
& name
)
125 return CreateAndInit(parent
, id
, pos
, size
, n
, choices
, style
,
129 bool wxChoice::CreateAndInit(wxWindow
*parent
,
133 int n
, const wxString choices
[],
135 const wxValidator
& validator
,
136 const wxString
& name
)
138 if ( !(style
& wxSP_VERTICAL
) )
139 style
|= wxSP_HORIZONTAL
;
141 if ( (style
& wxBORDER_MASK
) == wxBORDER_DEFAULT
)
142 style
|= wxBORDER_SIMPLE
;
144 style
|= wxSP_ARROW_KEYS
;
146 SetWindowStyle(style
);
149 WXDWORD msStyle
= MSWGetStyle(GetWindowStyle(), & exStyle
) ;
151 wxSize
sizeText(size
), sizeBtn(size
);
152 sizeBtn
.x
= GetBestSpinnerSize(IsVertical(style
)).x
;
154 if ( sizeText
.x
== wxDefaultCoord
)
156 // DEFAULT_ITEM_WIDTH is the default width for the text control
157 sizeText
.x
= DEFAULT_ITEM_WIDTH
+ MARGIN_BETWEEN
+ sizeBtn
.x
;
160 sizeText
.x
-= sizeBtn
.x
+ MARGIN_BETWEEN
;
161 if ( sizeText
.x
<= 0 )
163 wxLogDebug(_T("not enough space for wxSpinCtrl!"));
167 posBtn
.x
+= sizeText
.x
+ MARGIN_BETWEEN
;
169 // we must create the list control before the spin button for the purpose
170 // of the dialog navigation: if there is a static text just before the spin
171 // control, activating it by Alt-letter should give focus to the text
172 // control, not the spin and the dialog navigation code will give focus to
173 // the next control (at Windows level), not the one after it
175 // create the text window
177 m_hwndBuddy
= (WXHWND
)::CreateWindowEx
179 exStyle
, // sunken border
180 _T("LISTBOX"), // window class
181 NULL
, // no window title
182 msStyle
, // style (will be shown later)
183 pos
.x
, pos
.y
, // position
184 0, 0, // size (will be set later)
185 GetHwndOf(parent
), // parent
186 (HMENU
)-1, // control id
187 wxGetInstance(), // app instance
188 NULL
// unused client data
193 wxLogLastError(wxT("CreateWindow(buddy text window)"));
198 // initialize wxControl
199 if ( !CreateControl(parent
, id
, posBtn
, sizeBtn
, style
, validator
, name
) )
202 // now create the real HWND
203 WXDWORD spiner_style
= WS_VISIBLE
|
209 if ( !IsVertical(style
) )
210 spiner_style
|= UDS_HORZ
;
212 if ( style
& wxSP_WRAP
)
213 spiner_style
|= UDS_WRAP
;
215 if ( !MSWCreateControl(UPDOWN_CLASS
, spiner_style
, posBtn
, sizeBtn
, _T(""), 0) )
218 // subclass the text ctrl to be able to intercept some events
219 wxSetWindowUserData(GetBuddyHwnd(), this);
220 m_wndProcBuddy
= (WXFARPROC
)wxSetWindowProc(GetBuddyHwnd(),
221 wxBuddyChoiceWndProc
);
223 // set up fonts and colours (This is nomally done in MSWCreateControl)
226 SetFont(GetDefaultAttributes().font
);
228 // set the size of the text window - can do it only now, because we
229 // couldn't call DoGetBestSize() before as font wasn't set
230 if ( sizeText
.y
<= 0 )
233 wxGetCharSize(GetHWND(), &cx
, &cy
, GetFont());
235 sizeText
.y
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy
);
240 (void)::ShowWindow(GetBuddyHwnd(), SW_SHOW
);
242 // associate the list window with the spin button
243 (void)::SendMessage(GetHwnd(), UDM_SETBUDDY
, (WPARAM
)GetBuddyHwnd(), 0);
245 // do it after finishing with m_hwndBuddy creation to avoid generating
246 // initial wxEVT_COMMAND_TEXT_UPDATED message
247 ms_allChoiceSpins
.Add(this);
249 // initialize the controls contents
250 for ( int i
= 0; i
< n
; i
++ )
258 bool wxChoice::Create(wxWindow
*parent
,
262 const wxArrayString
& choices
,
264 const wxValidator
& validator
,
265 const wxString
& name
)
267 wxCArrayString
chs(choices
);
268 return Create(parent
, id
, pos
, size
, chs
.GetCount(), chs
.GetStrings(),
269 style
, validator
, name
);
272 WXDWORD
wxChoice::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
274 // we never have an external border
275 WXDWORD msStyle
= wxControl::MSWGetStyle
277 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
, exstyle
280 msStyle
|= WS_VISIBLE
;
282 // wxChoice-specific styles
283 msStyle
|= LBS_NOINTEGRALHEIGHT
;
284 if ( style
& wxCB_SORT
)
290 wxChoice::~wxChoice()
295 // ----------------------------------------------------------------------------
296 // adding/deleting items to/from the list
297 // ----------------------------------------------------------------------------
299 int wxChoice::DoAppend(const wxString
& item
)
301 int n
= (int)::SendMessage(GetBuddyHwnd(), LB_ADDSTRING
, 0, (LPARAM
)item
.c_str());
305 wxLogLastError(wxT("SendMessage(LB_ADDSTRING)"));
311 int wxChoice::DoInsert(const wxString
& item
, int pos
)
313 wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT
), -1, wxT("can't insert into choice"));
314 wxCHECK_MSG((pos
>=0) && (pos
<=GetCount()), -1, wxT("invalid index"));
316 int n
= (int)::SendMessage(GetBuddyHwnd(), LB_INSERTSTRING
, pos
, (LPARAM
)item
.c_str());
319 wxLogLastError(wxT("SendMessage(LB_INSERTSTRING)"));
325 void wxChoice::Delete(int n
)
327 wxCHECK_RET( n
< GetCount(), wxT("invalid item index in wxChoice::Delete") );
329 if ( HasClientObjectData() )
331 delete GetClientObject(n
);
334 ::SendMessage(GetBuddyHwnd(), LB_DELETESTRING
, n
, 0);
337 void wxChoice::Clear()
341 ::SendMessage(GetBuddyHwnd(), LB_RESETCONTENT
, 0, 0);
344 void wxChoice::Free()
346 if ( HasClientObjectData() )
348 size_t count
= GetCount();
349 for ( size_t n
= 0; n
< count
; n
++ )
351 delete GetClientObject(n
);
356 // ----------------------------------------------------------------------------
358 // ----------------------------------------------------------------------------
360 int wxChoice::GetSelection() const
362 return (int)::SendMessage(GetBuddyHwnd(), LB_GETCURSEL
, 0, 0);
365 void wxChoice::SetSelection(int n
)
367 ::SendMessage(GetBuddyHwnd(), LB_SETCURSEL
, n
, 0);
370 // ----------------------------------------------------------------------------
371 // string list functions
372 // ----------------------------------------------------------------------------
374 int wxChoice::GetCount() const
376 return (int)::SendMessage(GetBuddyHwnd(), LB_GETCOUNT
, 0, 0);
379 int wxChoice::FindString(const wxString
& s
) const
381 int pos
= (int)::SendMessage(GetBuddyHwnd(), LB_FINDSTRINGEXACT
,
382 (WPARAM
)-1, (LPARAM
)s
.c_str());
384 return pos
== LB_ERR
? wxNOT_FOUND
: pos
;
387 void wxChoice::SetString(int n
, const wxString
& s
)
389 wxCHECK_RET( n
>= 0 && n
< GetCount(),
390 wxT("invalid item index in wxChoice::SetString") );
392 // we have to delete and add back the string as there is no way to change a
395 // we need to preserve the client data
397 if ( m_clientDataItemsType
!= wxClientData_None
)
399 data
= DoGetItemClientData(n
);
401 else // no client data
406 ::SendMessage(GetBuddyHwnd(), LB_DELETESTRING
, n
, 0);
407 ::SendMessage(GetBuddyHwnd(), LB_INSERTSTRING
, n
, (LPARAM
)s
.c_str() );
411 DoSetItemClientData(n
, data
);
413 //else: it's already NULL by default
416 wxString
wxChoice::GetString(int n
) const
418 int len
= (int)::SendMessage(GetBuddyHwnd(), LB_GETTEXTLEN
, n
, 0);
421 if ( len
!= LB_ERR
&& len
> 0 )
428 (LPARAM
)(wxChar
*)wxStringBuffer(str
, len
)
431 wxLogLastError(wxT("SendMessage(LB_GETLBTEXT)"));
438 // ----------------------------------------------------------------------------
440 // ----------------------------------------------------------------------------
442 void wxChoice::DoSetItemClientData( int n
, void* clientData
)
444 if ( ::SendMessage(GetHwnd(), LB_SETITEMDATA
,
445 n
, (LPARAM
)clientData
) == LB_ERR
)
447 wxLogLastError(wxT("LB_SETITEMDATA"));
451 void* wxChoice::DoGetItemClientData( int n
) const
453 LPARAM rc
= ::SendMessage(GetHwnd(), LB_GETITEMDATA
, n
, 0);
456 wxLogLastError(wxT("LB_GETITEMDATA"));
458 // unfortunately, there is no way to return an error code to the user
465 void wxChoice::DoSetItemClientObject( int n
, wxClientData
* clientData
)
467 DoSetItemClientData(n
, clientData
);
470 wxClientData
* wxChoice::DoGetItemClientObject( int n
) const
472 return (wxClientData
*)DoGetItemClientData(n
);
475 // ----------------------------------------------------------------------------
477 // ----------------------------------------------------------------------------
479 wxSize
wxChoice::DoGetBestSize() const
481 wxSize sizeBtn
= GetBestSpinnerSize(IsVertical(GetWindowStyle()));
482 sizeBtn
.x
+= DEFAULT_ITEM_WIDTH
+ MARGIN_BETWEEN
;
485 wxGetCharSize(GetHWND(), NULL
, &y
, GetFont());
486 y
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(y
);
488 // JACS: we should always use the height calculated
489 // from above, because otherwise we'll get a spin control
490 // that's too big. So never use the height calculated
491 // from wxSpinButton::DoGetBestSize().
493 // if ( sizeBtn.y < y )
495 // make the text tall enough
502 void wxChoice::DoMoveWindow(int x
, int y
, int width
, int height
)
504 int widthBtn
= GetBestSpinnerSize(IsVertical(GetWindowStyle())).x
;
505 int widthText
= width
- widthBtn
- MARGIN_BETWEEN
;
506 if ( widthText
<= 0 )
508 wxLogDebug(_T("not enough space for wxSpinCtrl!"));
511 if ( !::MoveWindow(GetBuddyHwnd(), x
, y
, widthText
, height
, TRUE
) )
513 wxLogLastError(wxT("MoveWindow(buddy)"));
516 x
+= widthText
+ MARGIN_BETWEEN
;
517 if ( !::MoveWindow(GetHwnd(), x
, y
, widthBtn
, height
, TRUE
) )
519 wxLogLastError(wxT("MoveWindow"));
523 // get total size of the control
524 void wxChoice::DoGetSize(int *x
, int *y
) const
526 RECT spinrect
, textrect
, ctrlrect
;
527 GetWindowRect(GetHwnd(), &spinrect
);
528 GetWindowRect(GetBuddyHwnd(), &textrect
);
529 UnionRect(&ctrlrect
, &textrect
, &spinrect
);
532 *x
= ctrlrect
.right
- ctrlrect
.left
;
534 *y
= ctrlrect
.bottom
- ctrlrect
.top
;
537 void wxChoice::DoGetPosition(int *x
, int *y
) const
539 // hack: pretend that our HWND is the text control just for a moment
540 WXHWND hWnd
= GetHWND();
541 wxConstCast(this, wxChoice
)->m_hWnd
= m_hwndBuddy
;
543 wxChoiceBase::DoGetPosition(x
, y
);
545 wxConstCast(this, wxChoice
)->m_hWnd
= hWnd
;
548 #endif // wxUSE_CHOICE && __SMARTPHONE__ && __WXWINCE__