1. '\n's in tooltip messages are handled (replaced by spaces anyhow, tooltip

made multiline if comctl32 supports it)
2. added wxTAB_TRAVERSAL to default wxScrolledWindow style
3. improved arrows handling in radiobox (still problems for multirow ones)
4. [Alt]-<mnemonic> works in nested panels as well now because we use
   WS_EX_CONTROLPARENT for all windows with wxTAB_TRAVERSAL style
5. tooltips for radioboxes work again, even if I'm not really satisfied with
   solution :-( but I spent 2 hours trying to make TTM_WINDOWFROMPOINT handler
   work and I don't have more time to waste on this.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@5620 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2000-01-23 23:23:46 +00:00
parent ae80f83724
commit 8614c46755
13 changed files with 360 additions and 181 deletions

View File

@ -56,6 +56,8 @@ wxMSW:
- wxTreeCtrl::IsVisible() bug fixed (thanks to Gary Chessun) - wxTreeCtrl::IsVisible() bug fixed (thanks to Gary Chessun)
- loading/saving big (> 32K) files in wxTextCtrl works - loading/saving big (> 32K) files in wxTextCtrl works
- tooltips work with wxRadioBox - tooltips work with wxRadioBox
- wxBitmap/wxIcon may be constructed from XPM included into a program, as in
Unix ports
- returning FALSE from OnPrintPage() aborts printing - returning FALSE from OnPrintPage() aborts printing
wxGTK: wxGTK:

View File

@ -1,52 +1,65 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Name: scrolwin.h // Name: wx/generic/scrolwin.h
// Purpose: wxScrolledWindow class // Purpose: wxScrolledWindow class
// Author: Julian Smart // Author: Julian Smart
// Modified by: // Modified by:
// Created: 01/02/97 // Created: 01/02/97
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) Julian Smart and Markus Holzem // Copyright: (c) Julian Smart and Markus Holzem
// Licence: wxWindows license // Licence: wxWindows license
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifndef __SCROLWINH_G__ #ifndef _WX_GENERIC_SCROLLWIN_H_
#define __SCROLWINH_G__ #define _WX_GENERIC_SCROLLWIN_H_
#ifdef __GNUG__ #ifdef __GNUG__
#pragma interface "scrolwin.h" #pragma interface "scrolwin.h"
#endif #endif
// ----------------------------------------------------------------------------
// headers and constants
// ----------------------------------------------------------------------------
#include "wx/window.h" #include "wx/window.h"
#include "wx/panel.h" #include "wx/panel.h"
WXDLLEXPORT_DATA(extern const wxChar*) wxPanelNameStr; WXDLLEXPORT_DATA(extern const wxChar*) wxPanelNameStr;
// default scrolled window style
#define wxScrolledWindowStyle (wxHSCROLL | wxVSCROLL | wxTAB_TRAVERSAL)
// ----------------------------------------------------------------------------
// wxScrolledWindow
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxScrolledWindow : public wxPanel class WXDLLEXPORT wxScrolledWindow : public wxPanel
{ {
public: public:
wxScrolledWindow(); wxScrolledWindow();
inline wxScrolledWindow(wxWindow *parent, wxWindowID id = -1, wxScrolledWindow(wxWindow *parent,
const wxPoint& pos = wxDefaultPosition, wxWindowID id = -1,
const wxSize& size = wxDefaultSize, const wxPoint& pos = wxDefaultPosition,
long style = wxHSCROLL|wxVSCROLL, const wxSize& size = wxDefaultSize,
const wxString& name = wxPanelNameStr) long style = wxScrolledWindowStyle,
const wxString& name = wxPanelNameStr)
{ {
Create(parent, id, pos, size, style, name); Create(parent, id, pos, size, style, name);
} }
~wxScrolledWindow(); ~wxScrolledWindow();
bool Create(wxWindow *parent, wxWindowID id, bool Create(wxWindow *parent,
const wxPoint& pos = wxDefaultPosition, wxWindowID id,
const wxSize& size = wxDefaultSize, const wxPoint& pos = wxDefaultPosition,
long style = wxHSCROLL|wxVSCROLL, const wxSize& size = wxDefaultSize,
const wxString& name = wxPanelNameStr); long style = wxScrolledWindowStyle,
const wxString& name = wxPanelNameStr);
// Normally the wxScrolledWindow will scroll itself, but in // Normally the wxScrolledWindow will scroll itself, but in
// some rare occasions you might want it to scroll another // some rare occasions you might want it to scroll another
// window (e.g. a child of it in order to scroll only a portion // window (e.g. a child of it in order to scroll only a portion
// the area between the scrollbars (spreadsheet: only cell area // the area between the scrollbars (spreadsheet: only cell area
// will move). // will move).
virtual void SetTargetWindow( wxWindow *target ); virtual void SetTargetWindow( wxWindow *target );
virtual wxWindow *GetTargetWindow(); virtual wxWindow *GetTargetWindow();
@ -56,21 +69,21 @@ public:
virtual void SetScrollbars(int pixelsPerUnitX, int pixelsPerUnitY, virtual void SetScrollbars(int pixelsPerUnitX, int pixelsPerUnitY,
int noUnitsX, int noUnitsY, int noUnitsX, int noUnitsY,
int xPos = 0, int yPos = 0, int xPos = 0, int yPos = 0,
bool noRefresh = FALSE ); bool noRefresh = FALSE );
// Physically scroll the window // Physically scroll the window
virtual void Scroll(int x_pos, int y_pos); virtual void Scroll(int x_pos, int y_pos);
#if WXWIN_COMPATIBILITY #if WXWIN_COMPATIBILITY
virtual void GetScrollUnitsPerPage(int *x_page, int *y_page) const; virtual void GetScrollUnitsPerPage(int *x_page, int *y_page) const;
virtual void CalcUnscrolledPosition(int x, int y, float *xx, float *yy) const ; virtual void CalcUnscrolledPosition(int x, int y, float *xx, float *yy) const;
#endif #endif
int GetScrollPageSize(int orient) const ; int GetScrollPageSize(int orient) const;
void SetScrollPageSize(int orient, int pageSize); void SetScrollPageSize(int orient, int pageSize);
virtual void GetScrollPixelsPerUnit(int *x_unit, int *y_unit) const; virtual void GetScrollPixelsPerUnit(int *x_unit, int *y_unit) const;
// Enable/disable Windows scrolling in either direction. // Enable/disable Windows scrolling in either direction.
// If TRUE, wxWindows scrolls the canvas and only a bit of // If TRUE, wxWindows scrolls the canvas and only a bit of
// the canvas is invalidated; no Clear() is necessary. // the canvas is invalidated; no Clear() is necessary.
@ -93,8 +106,8 @@ public:
double GetScaleX() const { return m_scaleX; } double GetScaleX() const { return m_scaleX; }
double GetScaleY() const { return m_scaleY; } double GetScaleY() const { return m_scaleY; }
virtual void CalcScrolledPosition(int x, int y, int *xx, int *yy) const ; virtual void CalcScrolledPosition(int x, int y, int *xx, int *yy) const;
virtual void CalcUnscrolledPosition(int x, int y, int *xx, int *yy) const ; virtual void CalcUnscrolledPosition(int x, int y, int *xx, int *yy) const;
// Adjust the scrollbars // Adjust the scrollbars
virtual void AdjustScrollbars(void); virtual void AdjustScrollbars(void);
@ -135,4 +148,4 @@ private:
}; };
#endif #endif
// __SCROLWINH_G__ // _WX_GENERIC_SCROLLWIN_H_

View File

@ -235,6 +235,15 @@ extern void PixelToHIMETRIC(LONG *x, LONG *y);
// to invert the mask each time we pass one/get one to/from Windows // to invert the mask each time we pass one/get one to/from Windows
extern HBITMAP wxInvertMask(HBITMAP hbmpMask, int w = 0, int h = 0); extern HBITMAP wxInvertMask(HBITMAP hbmpMask, int w = 0, int h = 0);
// get (x, y) from DWORD - notice that HI/LOWORD can *not* be used because they
// will fail on system with multiple monitors where the coords may be negative
//
// these macros are standard now (Win98) but some older headers don't have them
#ifndef GET_X_LPARAM
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
#endif // GET_X_LPARAM
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// small helper classes // small helper classes
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -337,6 +346,12 @@ inline bool wxStyleHasBorder(long style)
wxSUNKEN_BORDER | wxDOUBLE_BORDER)) != 0; wxSUNKEN_BORDER | wxDOUBLE_BORDER)) != 0;
} }
// find the window for HWND which is part of some wxWindow, returns just the
// corresponding wxWindow for HWND which just is one
//
// may return NULL
extern wxWindow *wxGetWindowFromHWND(WXHWND hwnd);
#endif // wxUSE_GUI #endif // wxUSE_GUI
#endif #endif

View File

@ -89,6 +89,7 @@ public:
int GetNumVer() const; int GetNumVer() const;
int GetNumHor() const; int GetNumHor() const;
// compatibility ctor
#if WXWIN_COMPATIBILITY #if WXWIN_COMPATIBILITY
wxRadioBox(wxWindow *parent, wxFunction func, const char *title, wxRadioBox(wxWindow *parent, wxFunction func, const char *title,
int x = -1, int y = -1, int width = -1, int height = -1, int x = -1, int y = -1, int width = -1, int height = -1,

View File

@ -58,6 +58,9 @@ public:
virtual bool MSWOnScroll(int orientation, WXWORD wParam, virtual bool MSWOnScroll(int orientation, WXWORD wParam,
WXWORD pos, WXHWND control); WXWORD pos, WXHWND control);
// a wxSpinButton can't do anything useful with focus, only wxSpinCtrl can
virtual bool AcceptsFocus() const { return FALSE; }
protected: protected:
virtual wxSize DoGetBestSize() const; virtual wxSize DoGetBestSize() const;

View File

@ -65,6 +65,8 @@ public:
virtual bool Enable(bool enable = TRUE); virtual bool Enable(bool enable = TRUE);
virtual bool Show(bool show = TRUE); virtual bool Show(bool show = TRUE);
virtual bool AcceptsFocus() const { return TRUE; }
protected: protected:
virtual void DoMoveWindow(int x, int y, int width, int height); virtual void DoMoveWindow(int x, int y, int width, int height);
virtual wxSize DoGetBestSize() const; virtual wxSize DoGetBestSize() const;

View File

@ -31,14 +31,19 @@ public:
// set the delay after which the tooltip appears // set the delay after which the tooltip appears
static void SetDelay(long milliseconds); static void SetDelay(long milliseconds);
// implementation // implementation only from now on
// -------------------------------
// should be called in responde to WM_MOUSEMOVE
void RelayEvent(WXMSG *msg); void RelayEvent(WXMSG *msg);
private: private:
// the one and only one tooltip control we use - never access it directly
// but use GetToolTipCtrl() which will create it when needed
static WXHWND ms_hwndTT; static WXHWND ms_hwndTT;
// create the tooltip ctrl if it doesn't exist yet and return its HWND // create the tooltip ctrl if it doesn't exist yet and return its HWND
WXHWND GetToolTipCtrl(); static WXHWND GetToolTipCtrl();
// remove this tooltip from the tooltip control // remove this tooltip from the tooltip control
void Remove(); void Remove();

View File

@ -121,11 +121,11 @@ void wxPanel::OnSize(wxSizeEvent& WXUNUSED(event))
void wxPanel::OnNavigationKey( wxNavigationKeyEvent& event ) void wxPanel::OnNavigationKey( wxNavigationKeyEvent& event )
{ {
// the event is propagated downwards if the event emitter was our parent const wxWindowList& children = GetChildren();
bool goingDown = event.GetEventObject() == GetParent();
// we're not interested in "notebook page change" events here // there is not much to do if we don't have children and we're not
if ( event.IsWindowChange() ) // interested in "notebook page change" events here
if ( !children.GetCount() || event.IsWindowChange() )
{ {
wxWindow *parent = GetParent(); wxWindow *parent = GetParent();
if ( !parent || !parent->GetEventHandler()->ProcessEvent(event) ) if ( !parent || !parent->GetEventHandler()->ProcessEvent(event) )
@ -143,7 +143,8 @@ void wxPanel::OnNavigationKey( wxNavigationKeyEvent& event )
// next acceptable child // next acceptable child
wxWindowList::Node *node, *start_node; wxWindowList::Node *node, *start_node;
const wxWindowList& children = GetChildren(); // the event is propagated downwards if the event emitter was our parent
bool goingDown = event.GetEventObject() == GetParent();
// we should start from the first/last control and not from the one which // we should start from the first/last control and not from the one which
// had focus the last time if we're propagating the event downwards because // had focus the last time if we're propagating the event downwards because

View File

@ -67,6 +67,10 @@
#include "wx/resource.h" #include "wx/resource.h"
#endif #endif
#if wxUSE_TOOLTIPS
#include "wx/tooltip.h"
#endif // wxUSE_TOOLTIPS
// OLE is used for drag-and-drop, clipboard, OLE Automation... // OLE is used for drag-and-drop, clipboard, OLE Automation...
#ifndef wxUSE_NORLANDER_HEADERS #ifndef wxUSE_NORLANDER_HEADERS
#if defined(__GNUWIN32__) || defined(__SC__) || defined(__SALFORDC__) #if defined(__GNUWIN32__) || defined(__SC__) || defined(__SALFORDC__)
@ -959,19 +963,24 @@ bool wxApp::ProcessMessage(WXMSG *wxmsg)
{ {
MSG *msg = (MSG *)wxmsg; MSG *msg = (MSG *)wxmsg;
HWND hWnd = msg->hwnd; HWND hWnd = msg->hwnd;
wxWindow *wndThis = wxFindWinFromHandle((WXHWND)hWnd), *wnd; wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hWnd);
// for some composite controls (like a combobox), wndThis might be NULL #if wxUSE_TOOLTIPS
// because the subcontrol is not a wxWindow, but only the control itself // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
// is - try to catch this case // popup the tooltip bubbles
while ( hWnd && !wndThis ) if ( wndThis && (msg->message == WM_MOUSEMOVE) )
{ {
hWnd = ::GetParent(hWnd); wxToolTip *tt = wndThis->GetToolTip();
wndThis = wxFindWinFromHandle((WXHWND)hWnd); if ( tt )
{
tt->RelayEvent(wxmsg);
}
} }
#endif // wxUSE_TOOLTIPS
// Try translations first; find the youngest window with // Try translations first; find the youngest window with
// a translation table. // a translation table.
wxWindow *wnd;
for ( wnd = wndThis; wnd; wnd = wnd->GetParent() ) for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
{ {
if ( wnd->MSWTranslateMessage(wxmsg) ) if ( wnd->MSWTranslateMessage(wxmsg) )

View File

@ -38,24 +38,36 @@
#include "wx/msw/private.h" #include "wx/msw/private.h"
#if wxUSE_TOOLTIPS #if wxUSE_TOOLTIPS
#ifndef __GNUWIN32__
#ifndef __GNUWIN32__ #include <commctrl.h>
#include <commctrl.h> #endif
#endif
#include "wx/tooltip.h" #include "wx/tooltip.h"
#endif // wxUSE_TOOLTIPS #endif // wxUSE_TOOLTIPS
IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl) IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl)
// VZ: the new behaviour is to create the radio buttons as children of the // there are two possible ways to create the radio buttons: either as children
// radiobox instead of creating them as children of the radiobox' parent. // of the radiobox or as siblings of it - allow playing with both variants for
// now, eventually we will choose the best one for our purposes
// //
// This seems more logical, more consistent with what other frameworks do // two main problems are the keyboard navigation inside the radiobox (arrows
// and allows tooltips to work with radioboxes, so there should be no // should switch between buttons, not pass focus to the next control) and the
// reason to revert to the backward compatible behaviour - but I still // tooltips - a tooltip is associated with the radiobox itself, not the
// leave this possibility just in case. // children...
//
// the problems with setting this to 1:
// a) Alt-<mnemonic of radiobox> isn't handled properly by IsDialogMessage()
// because it sets focus to the next control accepting it which is not a
// radio button but a radiobox sibling in this case - the only solution to
// this would be to handle Alt-<mnemonic> ourselves
// b) the problems with setting radiobox colours under Win98/2K were reported
// but I couldn't reproduce it so I have no idea about what causes it
//
// the problems with setting this to 0:
// a) the tooltips are not shown for the radiobox - possible solution: make
// TTM_WINDOWFROMPOS handling code in msw/tooltip.cpp work (easier said than
// done because I don't know why it doesn't work)
#define RADIOBTN_PARENT_IS_RADIOBOX 0 #define RADIOBTN_PARENT_IS_RADIOBOX 0
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -74,7 +86,7 @@ LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hWnd,
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// the pointer to standard radio button wnd proc // the pointer to standard radio button wnd proc
static WXFARPROC s_wndprocRadioBtn = (WXFARPROC)NULL; static WNDPROC s_wndprocRadioBtn = (WNDPROC)NULL;
#endif // __WIN32__ #endif // __WIN32__
@ -668,15 +680,17 @@ void wxRadioBox::Command(wxCommandEvent & event)
ProcessCommand (event); ProcessCommand (event);
} }
// NB: if this code is changed, wxGetWindowForHWND() which relies on having the
// radiobox pointer in GWL_USERDATA for radio buttons must be updated too!
void wxRadioBox::SubclassRadioButton(WXHWND hWndBtn) void wxRadioBox::SubclassRadioButton(WXHWND hWndBtn)
{ {
// No GWL_USERDATA in Win16, so omit this subclassing.
#ifdef __WIN32__ #ifdef __WIN32__
HWND hwndBtn = (HWND)hWndBtn; HWND hwndBtn = (HWND)hWndBtn;
if ( !s_wndprocRadioBtn ) if ( !s_wndprocRadioBtn )
s_wndprocRadioBtn = (WXFARPROC)::GetWindowLong(hwndBtn, GWL_WNDPROC); s_wndprocRadioBtn = (WNDPROC)::GetWindowLong(hwndBtn, GWL_WNDPROC);
// No GWL_USERDATA in Win16, so omit this subclassing.
::SetWindowLong(hwndBtn, GWL_WNDPROC, (long)wxRadioBtnWndProc); ::SetWindowLong(hwndBtn, GWL_WNDPROC, (long)wxRadioBtnWndProc);
::SetWindowLong(hwndBtn, GWL_USERDATA, (long)this); ::SetWindowLong(hwndBtn, GWL_USERDATA, (long)this);
#endif // __WIN32__ #endif // __WIN32__
@ -706,14 +720,21 @@ bool wxRadioBox::SetFont(const wxFont& font)
::SendMessage((HWND)m_radioButtons[n], WM_SETFONT, (WPARAM)hfont, 0L); ::SendMessage((HWND)m_radioButtons[n], WM_SETFONT, (WPARAM)hfont, 0L);
} }
// this is needed because otherwise the buttons are not redrawn correctly
Refresh();
return TRUE; return TRUE;
} }
// ----------------------------------------------------------------------------
// our window proc
// ----------------------------------------------------------------------------
long wxRadioBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) long wxRadioBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{ {
switch ( nMsg ) switch ( nMsg )
{ {
#ifndef __WIN16__ #ifdef __WIN32__
case WM_CTLCOLORSTATIC: case WM_CTLCOLORSTATIC:
// set the colour of the radio buttons to be the same as ours // set the colour of the radio buttons to be the same as ours
{ {
@ -727,7 +748,7 @@ long wxRadioBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
return (WXHBRUSH)brush->GetResourceHandle(); return (WXHBRUSH)brush->GetResourceHandle();
} }
#endif #endif // Win32
// This is required for the radiobox to be sensitive to mouse input, // This is required for the radiobox to be sensitive to mouse input,
// e.g. for Dialog Editor. // e.g. for Dialog Editor.
@ -743,11 +764,10 @@ long wxRadioBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
if (yPos < 10) if (yPos < 10)
return (long)HTCLIENT; return (long)HTCLIENT;
} }
// fall through break;
default:
return wxControl::MSWWindowProc(nMsg, wParam, lParam);
} }
return wxControl::MSWWindowProc(nMsg, wParam, lParam);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -757,95 +777,103 @@ long wxRadioBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
#ifdef __WIN32__ #ifdef __WIN32__
LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hwnd, LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hwnd,
UINT msg, UINT message,
WPARAM wParam, WPARAM wParam,
LPARAM lParam) LPARAM lParam)
{ {
bool processed = FALSE; switch ( message )
if ( msg == WM_KEYDOWN
#if wxUSE_TOOLTIPS
|| msg == WM_NOTIFY
#endif // wxUSE_TOOLTIPS
)
{ {
wxRadioBox *radiobox = (wxRadioBox *)::GetWindowLong(hwnd, GWL_USERDATA); case WM_GETDLGCODE:
// we must tell IsDialogMessage()/our kbd processing code that we
wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") ); // want to process arrows ourselves because neither of them is
// smart enough to handle arrows properly for us
#if wxUSE_TOOLTIPS && !defined(__GNUWIN32__)
if ( msg == WM_NOTIFY )
{
NMHDR* hdr = (NMHDR *)lParam;
if ( (int)hdr->code == TTN_NEEDTEXT )
{ {
wxToolTip *tt = radiobox->GetToolTip(); long lDlgCode = ::CallWindowProc(s_wndprocRadioBtn, hwnd,
if ( tt ) message, wParam, lParam);
{ return lDlgCode | DLGC_WANTARROWS;
TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam;
ttt->lpszText = (wxChar *)tt->GetTip().c_str();
processed = TRUE;
}
} }
}
else // msg == WM_KEYDOWN
#endif // wxUSE_TOOLTIPS
{
processed = TRUE;
int sel = radiobox->GetSelection(); #if wxUSE_TOOLTIPS
case WM_NOTIFY:
switch ( wParam )
{ {
case VK_UP: NMHDR* hdr = (NMHDR *)lParam;
sel--; if ( (int)hdr->code == TTN_NEEDTEXT )
break; {
wxRadioBox *radiobox = (wxRadioBox *)
::GetWindowLong(hwnd, GWL_USERDATA);
case VK_LEFT: wxCHECK_MSG( radiobox, 0,
sel -= radiobox->GetNumVer(); wxT("radio button without radio box?") );
break;
case VK_DOWN: wxToolTip *tooltip = radiobox->GetToolTip();
sel++; if ( tooltip )
break;
case VK_RIGHT:
sel += radiobox->GetNumVer();
break;
case VK_TAB:
{ {
wxNavigationKeyEvent event; TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam;
event.SetDirection(!(::GetKeyState(VK_SHIFT) & 0x100)); ttt->lpszText = (wxChar *)tooltip->GetTip().c_str();
event.SetWindowChange(FALSE);
event.SetEventObject(radiobox);
if ( radiobox->GetEventHandler()->ProcessEvent(event) )
return 0;
} }
// fall through
default: // processed
processed = FALSE; return 0;
} }
}
if ( processed ) break;
{ #endif // wxUSE_TOOLTIPS
if ( sel >= 0 && sel < radiobox->Number() )
{ case WM_KEYDOWN:
radiobox->SetSelection(sel); {
wxRadioBox *radiobox = (wxRadioBox *)
// emulate the button click ::GetWindowLong(hwnd, GWL_USERDATA);
radiobox->SendNotificationEvent();
wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") );
bool processed = TRUE;
int selOld = radiobox->GetSelection();
int selNew = selOld;
switch ( wParam )
{
case VK_UP:
selNew--;
break;
case VK_LEFT:
selNew -= radiobox->GetNumVer();
break;
case VK_DOWN:
selNew++;
break;
case VK_RIGHT:
selNew += radiobox->GetNumVer();
break;
default:
processed = FALSE;
}
if ( processed )
{
// ensure that selNew is in range [0..num)
int num = radiobox->Number();
selNew += num;
selNew %= num;
if ( selNew != selOld )
{
radiobox->SetSelection(selNew);
// emulate the button click
radiobox->SendNotificationEvent();
return 0;
}
} }
} }
}
} }
if ( processed ) return ::CallWindowProc(s_wndprocRadioBtn, hwnd, message, wParam, lParam);
return 0;
return ::CallWindowProc(CASTWNDPROC s_wndprocRadioBtn, hwnd, msg, wParam, lParam);
} }
#endif // __WIN32__ #endif // __WIN32__

View File

@ -893,30 +893,19 @@ void wxTextCtrl::OnChar(wxKeyEvent& event)
// ourselves the fact that we got here means that the user code // ourselves the fact that we got here means that the user code
// decided to skip processing of this TAB - probably to let it // decided to skip processing of this TAB - probably to let it
// do its default job. // do its default job.
//
// NB: Notice that Ctrl-Tab is handled elsewhere and Alt-Tab is
// handled by Windows
{ {
wxNavigationKeyEvent eventNav; wxNavigationKeyEvent eventNav;
eventNav.SetDirection(!event.ShiftDown()); eventNav.SetDirection(!event.ShiftDown());
eventNav.SetWindowChange(FALSE); eventNav.SetWindowChange(event.ControlDown());
eventNav.SetEventObject(this); eventNav.SetEventObject(this);
if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) ) if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) )
return; return;
} }
break; break;
default:
event.Skip();
return;
} }
// don't just call event.Skip() because this will cause TABs and ENTERs // no, we didn't process it
// be passed upwards and we don't always want this - instead process it
// right here
// FIXME
event.Skip(); event.Skip();
} }

View File

@ -36,14 +36,20 @@
#include <commctrl.h> #include <commctrl.h>
#endif #endif
#ifndef _WIN32_IE
// minimal set of features by default
#define _WIN32_IE 0x0200
#endif
// VZ: normally, the trick with subclassing the tooltip control and processing // VZ: normally, the trick with subclassing the tooltip control and processing
// TTM_WINDOWFROMPOINT should work but, somehow, it doesn't. I leave the // TTM_WINDOWFROMPOINT should work but, somehow, it doesn't. I leave the
// code here for now (but it's not compiled) in case we need it later. // code here for now (but it's not compiled) in case we need it later.
// //
// For now, instead of this, we just add all radiobox buttons to the // For now I use an ugly workaround and process TTN_NEEDTEXT directly in
// tooltip control as well (see SetWindow) - this is probably less // radio button wnd proc - fixing TTM_WINDOWFROMPOINT code would be nice
// efficient, but it works. // because it would then work for all controls, not only radioboxes but for
#define wxUSE_TTM_WINDOWFROMPOINT 1 // now I don't understand what's wrong with it...
#define wxUSE_TTM_WINDOWFROMPOINT 0
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// global variables // global variables
@ -83,7 +89,7 @@ public:
// version of it. So we always use the old size - if we ever start // version of it. So we always use the old size - if we ever start
// using our lParam member, we'd have to check for comctl32 version // using our lParam member, we'd have to check for comctl32 version
// during run-time // during run-time
#if defined(_WIN32_IE) && (_WIN32_IE >= 0x0300) #if _WIN32_IE >= 0x0300
cbSize = sizeof(TOOLINFO) - sizeof(LPARAM); cbSize = sizeof(TOOLINFO) - sizeof(LPARAM);
#else // old headers #else // old headers
cbSize = sizeof(TOOLINFO); cbSize = sizeof(TOOLINFO);
@ -139,27 +145,36 @@ LRESULT APIENTRY wxToolTipWndProc(HWND hwndTT,
if ( msg == TTM_WINDOWFROMPOINT ) if ( msg == TTM_WINDOWFROMPOINT )
{ {
LPPOINT ppt = (LPPOINT)lParam; LPPOINT ppt = (LPPOINT)lParam;
// is the window under control a wxWindow?
// the window on which event occured
HWND hwnd = ::WindowFromPoint(*ppt); HWND hwnd = ::WindowFromPoint(*ppt);
// return a HWND correspondign to wxWindow because only wxWindows are OutputDebugString("TTM_WINDOWFROMPOINT: ");
// associated with tooltips using TTM_ADDTOOL OutputDebugString(wxString::Format("0x%08x => ", hwnd));
while ( hwnd && !wxFindWinFromHandle((WXHWND)hwnd) )
{
hwnd = ::GetParent(hwnd);
}
if ( hwnd ) // return a HWND corresponding to a wxWindow because only wxWindows are
// associated with tooltips using TTM_ADDTOOL
wxWindow *win = wxGetWindowFromHWND((WXHWND)hwnd);
if ( win )
{ {
hwnd = GetHwndOf(win);
OutputDebugString(wxString::Format("0x%08x\r\n", hwnd));
#if 0
// modify the point too! // modify the point too!
RECT rect; RECT rect;
GetWindowRect(hwnd, &rect); GetWindowRect(hwnd, &rect);
ppt->x = rect.left; ppt->x = (rect.right - rect.left) / 2;
ppt->y = rect.top; ppt->y = (rect.bottom - rect.top) / 2;
#endif // 0
return (LRESULT)hwnd; return (LRESULT)hwnd;
} }
else
{
OutputDebugString("no window\r\n");
}
} }
return ::CallWindowProc(CASTWNDPROC gs_wndprocToolTip, hwndTT, msg, wParam, lParam); return ::CallWindowProc(CASTWNDPROC gs_wndprocToolTip, hwndTT, msg, wParam, lParam);
@ -268,6 +283,59 @@ void wxToolTip::Add(WXHWND hWnd)
{ {
wxLogDebug(_T("Failed to create the tooltip '%s'"), m_text.c_str()); wxLogDebug(_T("Failed to create the tooltip '%s'"), m_text.c_str());
} }
else
{
// check for multiline toopltip
int index = m_text.Find(_T('\n'));
if ( index != wxNOT_FOUND )
{
#if _WIN32_IE >= 0x0300
if ( wxTheApp->GetComCtl32Version() >= 470 )
{
// use TTM_SETMAXWIDTH to make tooltip multiline using the
// extent of its first line as max value
HFONT hfont = (HFONT)SendTooltipMessage(GetToolTipCtrl(),
WM_GETFONT,
0, 0);
if ( !hfont )
{
hfont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
if ( !hfont )
{
wxLogLastError("GetStockObject(DEFAULT_GUI_FONT)");
}
}
HDC hdc = CreateCompatibleDC(NULL);
if ( !hdc )
{
wxLogLastError("CreateCompatibleDC(NULL)");
}
if ( !SelectObject(hdc, hfont) )
{
wxLogLastError("SelectObject(hfont)");
}
SIZE sz;
if ( !GetTextExtentPoint(hdc, m_text, index, &sz) )
{
wxLogLastError("GetTextExtentPoint");
}
DeleteDC(hdc);
SendTooltipMessage(GetToolTipCtrl(), TTM_SETMAXTIPWIDTH,
0, (void *)sz.cx);
}
#endif // comctl32.dll >= 4.70
// replace the '\n's with spaces because otherwise they appear as
// unprintable characters in the tooltip string
m_text.Replace(_T("\n"), _T(" "));
}
}
} }
void wxToolTip::SetWindow(wxWindow *win) void wxToolTip::SetWindow(wxWindow *win)
@ -282,24 +350,30 @@ void wxToolTip::SetWindow(wxWindow *win)
Add(m_window->GetHWND()); Add(m_window->GetHWND());
} }
#if 1 //!wxUSE_TTM_WINDOWFROMPOINT
// and all of its subcontrols (e.g. radiobuttons in a radiobox) as well // and all of its subcontrols (e.g. radiobuttons in a radiobox) as well
wxControl *control = wxDynamicCast(m_window, wxControl); wxControl *control = wxDynamicCast(m_window, wxControl);
if ( control ) if ( control )
{ {
size_t count = control->GetSubcontrols().GetCount(); const wxArrayLong& subcontrols = control->GetSubcontrols();
size_t count = subcontrols.GetCount();
for ( size_t n = 0; n < count; n++ ) for ( size_t n = 0; n < count; n++ )
{ {
wxWindowID id = control->GetSubcontrols()[n]; int id = subcontrols[n];
HWND hwnd = GetDlgItem(GetHwndOf(m_window), id); HWND hwnd = GetDlgItem(GetHwndOf(m_window), id);
if ( !hwnd )
if ( hwnd )
{ {
Add((WXHWND)hwnd); // may be it's a child of parent of the control, in fact?
// (radiobuttons are subcontrols, i.e. children of the radiobox
// for wxWindows but are its siblings at Windows level)
hwnd = GetDlgItem(GetHwndOf(m_window->GetParent()), id);
} }
// must have it by now!
wxASSERT_MSG( hwnd, _T("no hwnd for subcontrol?") );
Add((WXHWND)hwnd);
} }
} }
#endif // !wxUSE_TTM_WINDOWFROMPOINT
} }
void wxToolTip::SetTip(const wxString& tip) void wxToolTip::SetTip(const wxString& tip)

View File

@ -100,16 +100,6 @@
#endif #endif
#endif #endif
// ---------------------------------------------------------------------------
// macros
// ---------------------------------------------------------------------------
// standard macros missing from some compilers headers
#ifndef GET_X_LPARAM
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
#endif // GET_X_LPARAM
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// global variables // global variables
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -2293,6 +2283,13 @@ bool wxWindow::MSWCreate(int id,
if ( width > -1 ) width1 = width; if ( width > -1 ) width1 = width;
if ( height > -1 ) height1 = height; if ( height > -1 ) height1 = height;
// if we have wxTAB_TRAVERSAL style, we want WS_EX_CONTROLPARENT or
// IsDialogMessage() won't work for us
if ( GetWindowStyleFlag() & wxTAB_TRAVERSAL )
{
extendedStyle |= WS_EX_CONTROLPARENT;
}
HWND hParent = (HWND)NULL; HWND hParent = (HWND)NULL;
if ( parent ) if ( parent )
hParent = (HWND) parent->GetHWND(); hParent = (HWND) parent->GetHWND();
@ -3631,6 +3628,45 @@ wxWindow *wxGetActiveWindow()
return NULL; return NULL;
} }
extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
{
HWND hwnd = (HWND)hWnd;
// For a radiobutton, we get the radiobox from GWL_USERDATA (which is set
// by code in msw/radiobox.cpp), for all the others we just search up the
// window hierarchy
wxWindow *win = (wxWindow *)NULL;
if ( hwnd )
{
win = wxFindWinFromHandle((WXHWND)hwnd);
if ( !win )
{
// native radiobuttons return DLGC_RADIOBUTTON here and for any
// wxWindow class which overrides WM_GETDLGCODE processing to
// do it as well, win would be already non NULL
if ( ::SendMessage((HWND)hwnd, WM_GETDLGCODE,
0, 0) & DLGC_RADIOBUTTON )
{
win = (wxWindow *)::GetWindowLong(hwnd, GWL_USERDATA);
}
else
{
// hwnd is not a wxWindow, try its parent next below
hwnd = ::GetParent(hwnd);
}
}
//else: it's a wxRadioButton, not a radiobutton from wxRadioBox
}
while ( hwnd && !win )
{
win = wxFindWinFromHandle((WXHWND)hwnd);
hwnd = ::GetParent(hwnd);
}
return win;
}
// Windows keyboard hook. Allows interception of e.g. F1, ESCAPE // Windows keyboard hook. Allows interception of e.g. F1, ESCAPE
// in active frames and dialogs, regardless of where the focus is. // in active frames and dialogs, regardless of where the focus is.
static HHOOK wxTheKeyboardHook = 0; static HHOOK wxTheKeyboardHook = 0;
@ -3646,11 +3682,12 @@ void wxSetKeyboardHook(bool doIt)
wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(), wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(),
#if defined(__WIN32__) && !defined(__TWIN32__) #if defined(__WIN32__) && !defined(__TWIN32__)
GetCurrentThreadId()); GetCurrentThreadId()
// (DWORD)GetCurrentProcess()); // This is another possibility. Which is right? // (DWORD)GetCurrentProcess()); // This is another possibility. Which is right?
#else #else
GetCurrentTask()); GetCurrentTask()
#endif #endif
);
} }
else else
{ {