Native SmartPhone wxChoice implementation.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@28865 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Włodzimierz Skiba 2004-08-23 10:53:57 +00:00
parent c9ecfbe4cd
commit 1550d5f80d
7 changed files with 707 additions and 5 deletions

View File

@ -1318,15 +1318,17 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
src/generic/dirdlgg.cpp
src/generic/fdrepdlg.cpp
src/generic/fontdlgg.cpp
src/msw/wince/choicece.cpp
src/msw/wince/crt.cpp
src/msw/wince/filedlgwce.cpp
src/msw/wince/helpwce.cpp
src/msw/wince/tbarwce.cpp
src/msw/wince/menuce.cpp
src/msw/wince/tbarwce.cpp
</set>
<set var="WINCE_HDR" hints="files">
wx/generic/fdrepdlg.h
wx/generic/fontdlgg.h
wx/msw/wince/choicece.h
wx/msw/wince/helpwce.h
wx/msw/wince/libraries.h
wx/msw/wince/missing.h

View File

@ -273,6 +273,7 @@ wxUniv/X11:
wxWinCE:
- added native SmartPhone wxChoice implementation using spinners
- added automatized but customizable handling of native SmartPhone menus
- fixed wxRadioBox and wxStaticBox

View File

@ -67,6 +67,8 @@ private:
#if defined(__WXUNIVERSAL__)
#include "wx/univ/choice.h"
#elif defined(__SMARTPHONE__)
#include "wx/msw/wince/choicece.h"
#elif defined(__WXMSW__)
#include "wx/msw/choice.h"
#elif defined(__WXMOTIF__)

View File

@ -0,0 +1,141 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/msw/wince/choicece.h
// Purpose: wxChoice implementation for Smartphones
// Author: Wlodzimierz ABX Skiba
// Modified by:
// Created: 29.07.2004
// RCS-ID: $Id$
// Copyright: (c) Wlodzimierz Skiba
// License: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_CHOICECE_H_BASE_
#define _WX_CHOICECE_H_BASE_
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma interface "choicece.h"
#endif
#include "wx/defs.h"
#if wxUSE_CHOICE
#include "wx/dynarray.h"
class WXDLLEXPORT wxChoice;
WX_DEFINE_EXPORTED_ARRAY_PTR(wxChoice *, wxArrayChoiceSpins);
// ----------------------------------------------------------------------------
// Choice item
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxChoice : public wxChoiceBase
{
public:
// ctors
wxChoice() { }
virtual ~wxChoice();
wxChoice(wxWindow *parent,
wxWindowID id,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
int n = 0, const wxString choices[] = NULL,
long style = 0,
const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxChoiceNameStr)
{
Create(parent, id, pos, size, n, choices, style, validator, name);
}
wxChoice(wxWindow *parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
const wxArrayString& choices,
long style = 0,
const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxChoiceNameStr)
{
Create(parent, id, pos, size, choices, style, validator, name);
}
bool Create(wxWindow *parent,
wxWindowID id,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
int n = 0, const wxString choices[] = NULL,
long style = 0,
const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxChoiceNameStr);
bool Create(wxWindow *parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
const wxArrayString& choices,
long style = 0,
const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxChoiceNameStr);
// implement base class pure virtuals
virtual int DoAppend(const wxString& item);
virtual int DoInsert(const wxString& item, int pos);
virtual void Delete(int n);
virtual void Clear() ;
virtual int GetCount() const;
virtual int GetSelection() const;
virtual void SetSelection(int n);
virtual int FindString(const wxString& s) const;
virtual wxString GetString(int n) const;
virtual void SetString(int n, const wxString& s);
// get the subclassed window proc of the buddy list of choices
WXFARPROC GetBuddyWndProc() const { return m_wndProcBuddy; }
protected:
virtual void DoSetItemClientData( int n, void* clientData );
virtual void* DoGetItemClientData( int n ) const;
virtual void DoSetItemClientObject( int n, wxClientData* clientData );
virtual wxClientData* DoGetItemClientObject( int n ) const;
// MSW implementation
virtual void DoGetPosition(int *x, int *y) const;
virtual void DoMoveWindow(int x, int y, int width, int height);
virtual wxSize DoGetBestSize() const;
virtual void DoGetSize(int *width, int *height) const;
virtual WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const;
// create and initialize the control
bool CreateAndInit(wxWindow *parent, wxWindowID id,
const wxPoint& pos,
const wxSize& size,
int n, const wxString choices[],
long style,
const wxValidator& validator,
const wxString& name);
// free all memory we have (used by Clear() and dtor)
void Free();
// the data for the "buddy" list
WXHWND m_hwndBuddy;
WXFARPROC m_wndProcBuddy;
// all existing wxChoice - this allows to find the one corresponding to
// the given buddy window in GetSpinChoiceCtrl()
static wxArrayChoiceSpins ms_allChoiceSpins;
private:
DECLARE_DYNAMIC_CLASS_NO_COPY(wxChoice)
};
#endif // wxUSE_CHOICE
#endif // _WX_CHOICECE_H_BASE_

View File

@ -28,7 +28,7 @@
#pragma hdrstop
#endif
#if wxUSE_CHOICE
#if wxUSE_CHOICE && !defined(__SMARTPHONE__)
#ifndef WX_PRECOMP
#include "wx/choice.h"
@ -601,4 +601,4 @@ WXHBRUSH wxChoice::OnCtlColor(WXHDC pDC, WXHWND WXUNUSED(pWnd), WXUINT WXUNUSED(
return (WXHBRUSH)brush->GetResourceHandle();
}
#endif // wxUSE_CHOICE
#endif // wxUSE_CHOICE && !__SMARTPHONE__

View File

@ -213,8 +213,14 @@ wxSize wxControl::DoGetBestSize() const
wxSize wxControl::GetBestSpinerSize(const bool is_vertical) const
{
// take size according to layout
wxSize bestSize(GetSystemMetrics(is_vertical ? SM_CXVSCROLL : SM_CXHSCROLL),
GetSystemMetrics(is_vertical ? SM_CYVSCROLL : SM_CYHSCROLL));
wxSize bestSize(
#ifdef __SMARTPHONE__
0,GetCharHeight()
#else !__SMARTPHONE__
GetSystemMetrics(is_vertical ? SM_CXVSCROLL : SM_CXHSCROLL),
GetSystemMetrics(is_vertical ? SM_CYVSCROLL : SM_CYHSCROLL)
#endif __SMARTPHONE__/!__SMARTPHONE__
);
// correct size as for undocumented MSW variants cases (WinCE and perhaps others)
if (bestSize.x==0)

550
src/msw/wince/choicece.cpp Normal file
View File

@ -0,0 +1,550 @@
///////////////////////////////////////////////////////////////////////////////
// Name: src/msw/wince/choicece.cpp
// Purpose: wxChoice implementation for Smartphones
// Author: Wlodzimierz ABX Skiba
// Modified by:
// Created: 29.07.2004
// RCS-ID: $Id$
// Copyright: (c) Wlodzimierz Skiba
// License: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "choicece.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/choice.h"
#endif
#include "wx/spinbutt.h" // for wxSpinnerBestSize
#include <commctrl.h>
#include "wx/msw/missing.h"
#include "wx/msw/winundef.h"
#if wxUSE_CHOICE && defined(__SMARTPHONE__)
#if wxUSE_EXTENDED_RTTI
// TODO
#else
IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl)
#endif
#define GetBuddyHwnd() (HWND)(m_hwndBuddy)
#define IsVertical(wxStyle) ( (wxStyle & wxSP_HORIZONTAL) != wxSP_HORIZONTAL )
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// the margin between the up-down control and its buddy (can be arbitrary,
// choose what you like - or may be decide during run-time depending on the
// font size?)
static const int MARGIN_BETWEEN = 0;
// ============================================================================
// implementation
// ============================================================================
wxArrayChoiceSpins wxChoice::ms_allChoiceSpins;
// ----------------------------------------------------------------------------
// wnd proc for the buddy text ctrl
// ----------------------------------------------------------------------------
LRESULT APIENTRY _EXPORT wxBuddyChoiceWndProc(HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
wxChoice *spin = (wxChoice *)wxGetWindowUserData(hwnd);
// forward some messages (the key and focus ones only so far) to
// the spin ctrl
switch ( message )
{
case WM_SETFOCUS:
// if the focus comes from the spin control itself, don't set it
// back to it -- we don't want to go into an infinite loop
if ( (WXHWND)wParam == spin->GetHWND() )
break;
//else: fall through
case WM_KILLFOCUS:
case WM_CHAR:
case WM_DEADCHAR:
case WM_KEYUP:
case WM_KEYDOWN:
spin->MSWWindowProc(message, wParam, lParam);
// The control may have been deleted at this point, so check.
if ( !::IsWindow(hwnd) || wxGetWindowUserData(hwnd) != spin )
return 0;
break;
case WM_GETDLGCODE:
// we want to get WXK_RETURN in order to generate the event for it
return DLGC_WANTCHARS;
}
return ::CallWindowProc(CASTWNDPROC spin->GetBuddyWndProc(),
hwnd, message, wParam, lParam);
}
// ----------------------------------------------------------------------------
// creation
// ----------------------------------------------------------------------------
bool wxChoice::Create(wxWindow *parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
int n, const wxString choices[],
long style,
const wxValidator& validator,
const wxString& name)
{
return CreateAndInit(parent, id, pos, size, n, choices, style,
validator, name);
}
bool wxChoice::CreateAndInit(wxWindow *parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
int n, const wxString choices[],
long style,
const wxValidator& validator,
const wxString& name)
{
if ( !(style & wxSP_VERTICAL) )
style |= wxSP_HORIZONTAL;
if ( (style & wxBORDER_MASK) == wxBORDER_DEFAULT )
style |= wxBORDER_SIMPLE;
style |= wxSP_ARROW_KEYS;
SetWindowStyle(style);
WXDWORD exStyle = 0;
WXDWORD msStyle = MSWGetStyle(GetWindowStyle(), & exStyle) ;
wxSize sizeText(size), sizeBtn(size);
sizeBtn.x = GetBestSpinerSize(IsVertical(style)).x;
sizeBtn.x;
if ( sizeText.x == wxDefaultCoord )
{
// DEFAULT_ITEM_WIDTH is the default width for the text control
sizeText.x = DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN + sizeBtn.x;
}
sizeText.x -= sizeBtn.x + MARGIN_BETWEEN;
if ( sizeText.x <= 0 )
{
wxLogDebug(_T("not enough space for wxSpinCtrl!"));
}
wxPoint posBtn(pos);
posBtn.x += sizeText.x + MARGIN_BETWEEN;
// we must create the list control before the spin button for the purpose
// of the dialog navigation: if there is a static text just before the spin
// control, activating it by Alt-letter should give focus to the text
// control, not the spin and the dialog navigation code will give focus to
// the next control (at Windows level), not the one after it
// create the text window
m_hwndBuddy = (WXHWND)::CreateWindowEx
(
exStyle, // sunken border
_T("LISTBOX"), // window class
NULL, // no window title
msStyle, // style (will be shown later)
pos.x, pos.y, // position
0, 0, // size (will be set later)
GetHwndOf(parent), // parent
(HMENU)-1, // control id
wxGetInstance(), // app instance
NULL // unused client data
);
if ( !m_hwndBuddy )
{
wxLogLastError(wxT("CreateWindow(buddy text window)"));
return false;
}
// initialize wxControl
if ( !CreateControl(parent, id, posBtn, sizeBtn, style, validator, name) )
return false;
// now create the real HWND
WXDWORD spiner_style = WS_VISIBLE |
UDS_ALIGNRIGHT |
UDS_ARROWKEYS |
UDS_SETBUDDYINT |
UDS_EXPANDABLE;
if ( !IsVertical(style) )
spiner_style |= UDS_HORZ;
if ( style & wxSP_WRAP )
spiner_style |= UDS_WRAP;
if ( !MSWCreateControl(UPDOWN_CLASS, spiner_style, posBtn, sizeBtn, _T(""), 0) )
return false;
// subclass the text ctrl to be able to intercept some events
wxSetWindowUserData(GetBuddyHwnd(), this);
m_wndProcBuddy = (WXFARPROC)wxSetWindowProc(GetBuddyHwnd(),
wxBuddyChoiceWndProc);
// set up fonts and colours (This is nomally done in MSWCreateControl)
InheritAttributes();
if (!m_hasFont)
SetFont(GetDefaultAttributes().font);
// set the size of the text window - can do it only now, because we
// couldn't call DoGetBestSize() before as font wasn't set
if ( sizeText.y <= 0 )
{
int cx, cy;
wxGetCharSize(GetHWND(), &cx, &cy, GetFont());
sizeText.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
}
SetBestSize(size);
(void)::ShowWindow(GetBuddyHwnd(), SW_SHOW);
// associate the list window with the spin button
(void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)GetBuddyHwnd(), 0);
// do it after finishing with m_hwndBuddy creation to avoid generating
// initial wxEVT_COMMAND_TEXT_UPDATED message
ms_allChoiceSpins.Add(this);
// initialize the controls contents
for ( int i = 0; i < n; i++ )
{
Append(choices[i]);
}
return true;
}
bool wxChoice::Create(wxWindow *parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
const wxArrayString& choices,
long style,
const wxValidator& validator,
const wxString& name)
{
wxCArrayString chs(choices);
return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
style, validator, name);
}
WXDWORD wxChoice::MSWGetStyle(long style, WXDWORD *exstyle) const
{
// we never have an external border
WXDWORD msStyle = wxControl::MSWGetStyle
(
(style & ~wxBORDER_MASK) | wxBORDER_NONE, exstyle
);
msStyle |= WS_VISIBLE;
// wxChoice-specific styles
msStyle |= LBS_NOINTEGRALHEIGHT;
if ( style & wxCB_SORT )
msStyle |= LBS_SORT;
return msStyle;
}
wxChoice::~wxChoice()
{
Free();
}
// ----------------------------------------------------------------------------
// adding/deleting items to/from the list
// ----------------------------------------------------------------------------
int wxChoice::DoAppend(const wxString& item)
{
int n = (int)SendMessage(GetBuddyHwnd(), LB_ADDSTRING, 0, (LPARAM)item.c_str());
if ( n == LB_ERR )
{
wxLogLastError(wxT("SendMessage(LB_ADDSTRING)"));
}
return n;
}
int wxChoice::DoInsert(const wxString& item, int pos)
{
wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into choice"));
wxCHECK_MSG((pos>=0) && (pos<=GetCount()), -1, wxT("invalid index"));
int n = (int)SendMessage(GetBuddyHwnd(), LB_INSERTSTRING, pos, (LPARAM)item.c_str());
if ( n == LB_ERR )
{
wxLogLastError(wxT("SendMessage(LB_INSERTSTRING)"));
}
return n;
}
void wxChoice::Delete(int n)
{
wxCHECK_RET( n < GetCount(), wxT("invalid item index in wxChoice::Delete") );
if ( HasClientObjectData() )
{
delete GetClientObject(n);
}
SendMessage(GetBuddyHwnd(), LB_DELETESTRING, n, 0);
}
void wxChoice::Clear()
{
Free();
SendMessage(GetBuddyHwnd(), LB_RESETCONTENT, 0, 0);
}
void wxChoice::Free()
{
if ( HasClientObjectData() )
{
size_t count = GetCount();
for ( size_t n = 0; n < count; n++ )
{
delete GetClientObject(n);
}
}
}
// ----------------------------------------------------------------------------
// selection
// ----------------------------------------------------------------------------
int wxChoice::GetSelection() const
{
return (int)SendMessage(GetBuddyHwnd(), LB_GETCURSEL, 0, 0);
}
void wxChoice::SetSelection(int n)
{
SendMessage(GetBuddyHwnd(), LB_SETCURSEL, n, 0);
}
// ----------------------------------------------------------------------------
// string list functions
// ----------------------------------------------------------------------------
int wxChoice::GetCount() const
{
return (int)SendMessage(GetBuddyHwnd(), LB_GETCOUNT, 0, 0);
}
int wxChoice::FindString(const wxString& s) const
{
int pos = (int)SendMessage(GetBuddyHwnd(), LB_FINDSTRINGEXACT,
(WPARAM)-1, (LPARAM)s.c_str());
return pos == LB_ERR ? wxNOT_FOUND : pos;
}
void wxChoice::SetString(int n, const wxString& s)
{
wxCHECK_RET( n >= 0 && n < GetCount(),
wxT("invalid item index in wxChoice::SetString") );
// we have to delete and add back the string as there is no way to change a
// string in place
// we need to preserve the client data
void *data;
if ( m_clientDataItemsType != wxClientData_None )
{
data = DoGetItemClientData(n);
}
else // no client data
{
data = NULL;
}
::SendMessage(GetBuddyHwnd(), LB_DELETESTRING, n, 0);
::SendMessage(GetBuddyHwnd(), LB_INSERTSTRING, n, (LPARAM)s.c_str() );
if ( data )
{
DoSetItemClientData(n, data);
}
//else: it's already NULL by default
}
wxString wxChoice::GetString(int n) const
{
int len = (int)::SendMessage(GetBuddyHwnd(), LB_GETTEXTLEN, n, 0);
wxString str;
if ( len != LB_ERR && len > 0 )
{
if ( ::SendMessage
(
GetBuddyHwnd(),
LB_GETTEXT,
n,
(LPARAM)(wxChar *)wxStringBuffer(str, len)
) == LB_ERR )
{
wxLogLastError(wxT("SendMessage(LB_GETLBTEXT)"));
}
}
return str;
}
// ----------------------------------------------------------------------------
// client data
// ----------------------------------------------------------------------------
void wxChoice::DoSetItemClientData( int n, void* clientData )
{
if ( ::SendMessage(GetHwnd(), LB_SETITEMDATA,
n, (LPARAM)clientData) == LB_ERR )
{
wxLogLastError(wxT("LB_SETITEMDATA"));
}
}
void* wxChoice::DoGetItemClientData( int n ) const
{
LPARAM rc = SendMessage(GetHwnd(), LB_GETITEMDATA, n, 0);
if ( rc == LB_ERR )
{
wxLogLastError(wxT("LB_GETITEMDATA"));
// unfortunately, there is no way to return an error code to the user
rc = (LPARAM) NULL;
}
return (void *)rc;
}
void wxChoice::DoSetItemClientObject( int n, wxClientData* clientData )
{
DoSetItemClientData(n, clientData);
}
wxClientData* wxChoice::DoGetItemClientObject( int n ) const
{
return (wxClientData *)DoGetItemClientData(n);
}
// ----------------------------------------------------------------------------
// size calculations
// ----------------------------------------------------------------------------
wxSize wxChoice::DoGetBestSize() const
{
wxSize sizeBtn = GetBestSpinerSize(IsVertical(GetWindowStyle()));
sizeBtn.x += DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN;
int y;
wxGetCharSize(GetHWND(), NULL, &y, GetFont());
y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(y);
// JACS: we should always use the height calculated
// from above, because otherwise we'll get a spin control
// that's too big. So never use the height calculated
// from wxSpinButton::DoGetBestSize().
// if ( sizeBtn.y < y )
{
// make the text tall enough
sizeBtn.y = y;
}
return sizeBtn;
}
void wxChoice::DoMoveWindow(int x, int y, int width, int height)
{
int widthBtn = GetBestSpinerSize(IsVertical(GetWindowStyle())).x;
int widthText = width - widthBtn - MARGIN_BETWEEN;
if ( widthText <= 0 )
{
wxLogDebug(_T("not enough space for wxSpinCtrl!"));
}
if ( !::MoveWindow(GetBuddyHwnd(), x, y, widthText, height, TRUE) )
{
wxLogLastError(wxT("MoveWindow(buddy)"));
}
x += widthText + MARGIN_BETWEEN;
if ( !::MoveWindow(GetHwnd(), x, y, widthBtn, height, TRUE) )
{
wxLogLastError(wxT("MoveWindow"));
}
}
// get total size of the control
void wxChoice::DoGetSize(int *x, int *y) const
{
RECT spinrect, textrect, ctrlrect;
GetWindowRect(GetHwnd(), &spinrect);
GetWindowRect(GetBuddyHwnd(), &textrect);
UnionRect(&ctrlrect, &textrect, &spinrect);
if ( x )
*x = ctrlrect.right - ctrlrect.left;
if ( y )
*y = ctrlrect.bottom - ctrlrect.top;
}
void wxChoice::DoGetPosition(int *x, int *y) const
{
// hack: pretend that our HWND is the text control just for a moment
WXHWND hWnd = GetHWND();
wxConstCast(this, wxChoice)->m_hWnd = m_hwndBuddy;
wxChoiceBase::DoGetPosition(x, y);
wxConstCast(this, wxChoice)->m_hWnd = hWnd;
}
#endif // wxUSE_CHOICE && __SMARTPHONE__