]>
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
7 // Copyright: (c) Wlodzimierz Skiba
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
26 #if wxUSE_CHOICE && defined(__SMARTPHONE__) && defined(__WXWINCE__)
28 #include "wx/choice.h"
31 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
34 #include "wx/spinbutt.h" // for wxSpinnerBestSize
36 #define GetBuddyHwnd() (HWND)(m_hwndBuddy)
38 #define IsVertical(wxStyle) ( (wxStyle & wxSP_HORIZONTAL) != wxSP_HORIZONTAL )
40 // ----------------------------------------------------------------------------
42 // ----------------------------------------------------------------------------
44 // the margin between the up-down control and its buddy (can be arbitrary,
45 // choose what you like - or may be decide during run-time depending on the
47 static const int MARGIN_BETWEEN
= 0;
49 // ============================================================================
51 // ============================================================================
53 wxArrayChoiceSpins
wxChoice::ms_allChoiceSpins
;
55 // ----------------------------------------------------------------------------
56 // wnd proc for the buddy text ctrl
57 // ----------------------------------------------------------------------------
59 LRESULT APIENTRY _EXPORT
wxBuddyChoiceWndProc(HWND hwnd
,
64 wxChoice
*spin
= (wxChoice
*)wxGetWindowUserData(hwnd
);
66 // forward some messages (the key and focus ones only so far) to
71 // if the focus comes from the spin control itself, don't set it
72 // back to it -- we don't want to go into an infinite loop
73 if ( (WXHWND
)wParam
== spin
->GetHWND() )
82 spin
->MSWWindowProc(message
, wParam
, lParam
);
84 // The control may have been deleted at this point, so check.
85 if ( !::IsWindow(hwnd
) || wxGetWindowUserData(hwnd
) != spin
)
90 // we want to get WXK_RETURN in order to generate the event for it
91 return DLGC_WANTCHARS
;
94 return ::CallWindowProc(CASTWNDPROC spin
->GetBuddyWndProc(),
95 hwnd
, message
, wParam
, lParam
);
98 wxChoice
*wxChoice::GetChoiceForListBox(WXHWND hwndBuddy
)
100 wxChoice
*choice
= (wxChoice
*)wxGetWindowUserData((HWND
)hwndBuddy
);
102 int i
= ms_allChoiceSpins
.Index(choice
);
104 if ( i
== wxNOT_FOUND
)
108 wxASSERT_MSG( choice
->m_hwndBuddy
== hwndBuddy
,
109 wxT("wxChoice has incorrect buddy HWND!") );
114 // ----------------------------------------------------------------------------
116 // ----------------------------------------------------------------------------
118 bool wxChoice::Create(wxWindow
*parent
,
122 int n
, const wxString choices
[],
124 const wxValidator
& validator
,
125 const wxString
& name
)
127 return CreateAndInit(parent
, id
, pos
, size
, n
, choices
, style
,
131 bool wxChoice::CreateAndInit(wxWindow
*parent
,
135 int n
, const wxString choices
[],
137 const wxValidator
& validator
,
138 const wxString
& name
)
140 if ( !(style
& wxSP_VERTICAL
) )
141 style
|= wxSP_HORIZONTAL
;
143 if ( (style
& wxBORDER_MASK
) == wxBORDER_DEFAULT
)
144 style
|= wxBORDER_SIMPLE
;
146 style
|= wxSP_ARROW_KEYS
;
148 SetWindowStyle(style
);
151 WXDWORD msStyle
= MSWGetStyle(GetWindowStyle(), & exStyle
) ;
153 wxSize
sizeText(size
), sizeBtn(size
);
154 sizeBtn
.x
= GetBestSpinnerSize(IsVertical(style
)).x
;
156 if ( sizeText
.x
== wxDefaultCoord
)
158 // DEFAULT_ITEM_WIDTH is the default width for the text control
159 sizeText
.x
= DEFAULT_ITEM_WIDTH
+ MARGIN_BETWEEN
+ sizeBtn
.x
;
162 sizeText
.x
-= sizeBtn
.x
+ MARGIN_BETWEEN
;
163 if ( sizeText
.x
<= 0 )
165 wxLogDebug(wxT("not enough space for wxSpinCtrl!"));
169 posBtn
.x
+= sizeText
.x
+ MARGIN_BETWEEN
;
171 // we must create the list control before the spin button for the purpose
172 // of the dialog navigation: if there is a static text just before the spin
173 // control, activating it by Alt-letter should give focus to the text
174 // control, not the spin and the dialog navigation code will give focus to
175 // the next control (at Windows level), not the one after it
177 // create the text window
179 m_hwndBuddy
= (WXHWND
)::CreateWindowEx
181 exStyle
, // sunken border
182 wxT("LISTBOX"), // window class
183 NULL
, // no window title
184 msStyle
, // style (will be shown later)
185 pos
.x
, pos
.y
, // position
186 0, 0, // size (will be set later)
187 GetHwndOf(parent
), // parent
188 (HMENU
)-1, // control id
189 wxGetInstance(), // app instance
190 NULL
// unused client data
195 wxLogLastError(wxT("CreateWindow(buddy text window)"));
200 // initialize wxControl
201 if ( !CreateControl(parent
, id
, posBtn
, sizeBtn
, style
, validator
, name
) )
204 // now create the real HWND
205 WXDWORD spiner_style
= WS_VISIBLE
|
211 if ( !IsVertical(style
) )
212 spiner_style
|= UDS_HORZ
;
214 if ( style
& wxSP_WRAP
)
215 spiner_style
|= UDS_WRAP
;
217 if ( !MSWCreateControl(UPDOWN_CLASS
, spiner_style
, posBtn
, sizeBtn
, wxEmptyString
, 0) )
220 // subclass the text ctrl to be able to intercept some events
221 wxSetWindowUserData(GetBuddyHwnd(), this);
222 m_wndProcBuddy
= (WXFARPROC
)wxSetWindowProc(GetBuddyHwnd(),
223 wxBuddyChoiceWndProc
);
225 // set up fonts and colours (This is nomally done in MSWCreateControl)
228 SetFont(GetDefaultAttributes().font
);
230 // set the size of the text window - can do it only now, because we
231 // couldn't call DoGetBestSize() before as font wasn't set
232 if ( sizeText
.y
<= 0 )
235 wxGetCharSize(GetHWND(), &cx
, &cy
, GetFont());
237 sizeText
.y
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy
);
240 SetInitialSize(size
);
242 (void)::ShowWindow(GetBuddyHwnd(), SW_SHOW
);
244 // associate the list window with the spin button
245 (void)::SendMessage(GetHwnd(), UDM_SETBUDDY
, (WPARAM
)GetBuddyHwnd(), 0);
247 // do it after finishing with m_hwndBuddy creation to avoid generating
248 // initial wxEVT_TEXT message
249 ms_allChoiceSpins
.Add(this);
251 // initialize the controls contents
252 for ( int i
= 0; i
< n
; i
++ )
260 bool wxChoice::Create(wxWindow
*parent
,
264 const wxArrayString
& choices
,
266 const wxValidator
& validator
,
267 const wxString
& name
)
269 wxCArrayString
chs(choices
);
270 return Create(parent
, id
, pos
, size
, chs
.GetCount(), chs
.GetStrings(),
271 style
, validator
, name
);
274 WXDWORD
wxChoice::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
276 // we never have an external border
277 WXDWORD msStyle
= wxControl::MSWGetStyle
279 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
, exstyle
282 msStyle
|= WS_VISIBLE
;
284 // wxChoice-specific styles
285 msStyle
|= LBS_NOINTEGRALHEIGHT
;
286 if ( style
& wxCB_SORT
)
289 msStyle
|= LBS_NOTIFY
;
294 bool wxChoice::MSWCommand(WXUINT param
, WXWORD
WXUNUSED(id
))
296 if ( param
!= LBN_SELCHANGE
)
298 // "selection changed" is the only event we're after
302 int n
= GetSelection();
305 wxCommandEvent
event(wxEVT_CHOICE
, m_windowId
);
307 event
.SetEventObject(this);
308 event
.SetString(GetStringSelection());
309 if ( HasClientObjectData() )
310 event
.SetClientObject( GetClientObject(n
) );
311 else if ( HasClientUntypedData() )
312 event
.SetClientData( GetClientData(n
) );
313 ProcessCommand(event
);
319 wxChoice::~wxChoice()
324 // ----------------------------------------------------------------------------
325 // adding/deleting items to/from the list
326 // ----------------------------------------------------------------------------
328 int wxChoice::DoInsertItems(const wxArrayStringsAdapter
& items
,
331 wxClientDataType type
)
333 MSWAllocStorage(items
, LB_INITSTORAGE
);
335 const bool append
= pos
== GetCount();
336 const unsigned msg
= append
? LB_ADDSTRING
: LB_INSERTSTRING
;
342 const unsigned int numItems
= items
.GetCount();
343 for ( unsigned int i
= 0; i
< numItems
; ++i
)
345 n
= MSWInsertOrAppendItem(pos
, items
[i
], msg
);
349 AssignNewItemClientData(n
, clientData
, i
, type
);
355 void wxChoice::DoDeleteOneItem(unsigned int n
)
357 wxCHECK_RET( IsValid(n
), wxT("invalid item index in wxChoice::Delete") );
359 ::SendMessage(GetBuddyHwnd(), LB_DELETESTRING
, n
, 0);
362 void wxChoice::DoClear()
364 ::SendMessage(GetBuddyHwnd(), LB_RESETCONTENT
, 0, 0);
367 // ----------------------------------------------------------------------------
369 // ----------------------------------------------------------------------------
371 int wxChoice::GetSelection() const
373 return (int)::SendMessage(GetBuddyHwnd(), LB_GETCURSEL
, 0, 0);
376 void wxChoice::SetSelection(int n
)
378 ::SendMessage(GetBuddyHwnd(), LB_SETCURSEL
, n
, 0);
381 // ----------------------------------------------------------------------------
382 // string list functions
383 // ----------------------------------------------------------------------------
385 unsigned int wxChoice::GetCount() const
387 return (unsigned int)::SendMessage(GetBuddyHwnd(), LB_GETCOUNT
, 0, 0);
390 int wxChoice::FindString(const wxString
& s
, bool bCase
) const
392 // back to base class search for not native search type
394 return wxItemContainerImmutable::FindString( s
, bCase
);
396 int pos
= (int)::SendMessage(GetBuddyHwnd(), LB_FINDSTRINGEXACT
,
397 (WPARAM
)-1, (LPARAM
)s
.c_str());
399 return pos
== LB_ERR
? wxNOT_FOUND
: pos
;
402 void wxChoice::SetString(unsigned int n
, const wxString
& s
)
404 wxCHECK_RET( IsValid(n
),
405 wxT("invalid item index in wxChoice::SetString") );
407 // we have to delete and add back the string as there is no way to change a
410 // we need to preserve the client data
412 if ( m_clientDataItemsType
!= wxClientData_None
)
414 data
= DoGetItemClientData(n
);
416 else // no client data
421 ::SendMessage(GetBuddyHwnd(), LB_DELETESTRING
, n
, 0);
422 ::SendMessage(GetBuddyHwnd(), LB_INSERTSTRING
, n
, (LPARAM
)s
.c_str() );
426 DoSetItemClientData(n
, data
);
428 //else: it's already NULL by default
431 wxString
wxChoice::GetString(unsigned int n
) const
433 int len
= (int)::SendMessage(GetBuddyHwnd(), LB_GETTEXTLEN
, n
, 0);
436 if ( len
!= LB_ERR
&& len
> 0 )
443 (LPARAM
)(wxChar
*)wxStringBuffer(str
, len
)
446 wxLogLastError(wxT("SendMessage(LB_GETLBTEXT)"));
453 // ----------------------------------------------------------------------------
455 // ----------------------------------------------------------------------------
457 void wxChoice::DoSetItemClientData(unsigned int n
, void* clientData
)
459 if ( ::SendMessage(GetHwnd(), LB_SETITEMDATA
,
460 n
, (LPARAM
)clientData
) == LB_ERR
)
462 wxLogLastError(wxT("LB_SETITEMDATA"));
466 void* wxChoice::DoGetItemClientData(unsigned int n
) const
468 LPARAM rc
= ::SendMessage(GetHwnd(), LB_GETITEMDATA
, n
, 0);
471 wxLogLastError(wxT("LB_GETITEMDATA"));
473 // unfortunately, there is no way to return an error code to the user
480 // ----------------------------------------------------------------------------
482 // ----------------------------------------------------------------------------
484 wxSize
wxChoice::DoGetBestSize() const
486 wxSize sizeBtn
= GetBestSpinnerSize(IsVertical(GetWindowStyle()));
487 sizeBtn
.x
+= DEFAULT_ITEM_WIDTH
+ MARGIN_BETWEEN
;
490 wxGetCharSize(GetHWND(), NULL
, &y
, GetFont());
491 y
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(y
);
493 // JACS: we should always use the height calculated
494 // from above, because otherwise we'll get a spin control
495 // that's too big. So never use the height calculated
496 // from wxSpinButton::DoGetBestSize().
498 // if ( sizeBtn.y < y )
500 // make the text tall enough
507 void wxChoice::DoMoveWindow(int x
, int y
, int width
, int height
)
509 int widthBtn
= GetBestSpinnerSize(IsVertical(GetWindowStyle())).x
;
510 int widthText
= width
- widthBtn
- MARGIN_BETWEEN
;
511 if ( widthText
<= 0 )
513 wxLogDebug(wxT("not enough space for wxSpinCtrl!"));
516 if ( !::MoveWindow(GetBuddyHwnd(), x
, y
, widthText
, height
, TRUE
) )
518 wxLogLastError(wxT("MoveWindow(buddy)"));
521 x
+= widthText
+ MARGIN_BETWEEN
;
522 if ( !::MoveWindow(GetHwnd(), x
, y
, widthBtn
, height
, TRUE
) )
524 wxLogLastError(wxT("MoveWindow"));
528 // get total size of the control
529 void wxChoice::DoGetSize(int *x
, int *y
) const
531 RECT spinrect
, textrect
, ctrlrect
;
532 GetWindowRect(GetHwnd(), &spinrect
);
533 GetWindowRect(GetBuddyHwnd(), &textrect
);
534 UnionRect(&ctrlrect
, &textrect
, &spinrect
);
537 *x
= ctrlrect
.right
- ctrlrect
.left
;
539 *y
= ctrlrect
.bottom
- ctrlrect
.top
;
542 void wxChoice::DoGetPosition(int *x
, int *y
) const
544 // hack: pretend that our HWND is the text control just for a moment
545 WXHWND hWnd
= GetHWND();
546 wxConstCast(this, wxChoice
)->m_hWnd
= m_hwndBuddy
;
548 wxChoiceBase::DoGetPosition(x
, y
);
550 wxConstCast(this, wxChoice
)->m_hWnd
= hWnd
;
553 #endif // wxUSE_CHOICE && __SMARTPHONE__ && __WXWINCE__