]>
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 Smartphones 
   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__) 
  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 
= GetBestSpinerSize(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 
= GetBestSpinerSize(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 
= GetBestSpinerSize(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__