more scrollbar input handling: extracted common bits to wxStdScrollBarHandler

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/wxUNIVERSAL@8174 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2000-08-24 12:12:35 +00:00
parent 46f2baf74e
commit 89196a1dab
8 changed files with 570 additions and 583 deletions

View File

@@ -50,4 +50,115 @@ public:
virtual ~wxInputHandler(); virtual ~wxInputHandler();
}; };
// ============================================================================
// The classes below provide the standard input handling for some controls so
// that the code can be reused in different themes. All of these classes chain
// to an existing input handler (which must be given to the ctor) and so allow
// custom processing of the events which they don't handle themselves.
// ============================================================================
// ----------------------------------------------------------------------------
// wxStdInputHandler is just a base class for all other "standard" handlers
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxStdInputHandler : public wxInputHandler
{
public:
wxStdInputHandler(wxInputHandler *handler) : m_handler(handler) { }
virtual wxControlActions Map(wxControl *control,
const wxKeyEvent& event,
bool pressed)
{ return m_handler->Map(control, event, pressed); }
virtual wxControlActions Map(wxControl *control,
const wxMouseEvent& event)
{ return m_handler->Map(control, event); }
virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event)
{ return m_handler->OnMouseMove(control, event); }
private:
wxInputHandler *m_handler;
};
// ----------------------------------------------------------------------------
// wxStdButtonInputHandler: translates SPACE and ENTER keys and the left mouse
// click into button press/release actions
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxStdButtonInputHandler : public wxStdInputHandler
{
public:
wxStdButtonInputHandler(wxInputHandler *inphand);
virtual wxControlActions Map(wxControl *control,
const wxKeyEvent& event,
bool pressed);
virtual wxControlActions Map(wxControl *control,
const wxMouseEvent& event);
virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event);
private:
// the window (button) which has capture or NULL and the flag telling if
// the mouse is inside the button which captured it or not
wxWindow *m_winCapture;
bool m_winHasMouse;
};
// ----------------------------------------------------------------------------
// common scrollbar input handler: it manages clicks on the standard scrollbar
// elements (line arrows, bar, thumb)
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxStdScrollBarInputHandler : public wxStdInputHandler
{
public:
// constructor takes a renderer (used for scrollbar hit testing) and the
// base handler to which all unhandled events are forwarded
wxStdScrollBarInputHandler(wxRenderer *renderer,
wxInputHandler *inphand);
virtual wxControlActions Map(wxControl *control,
const wxKeyEvent& event,
bool pressed);
virtual wxControlActions Map(wxControl *control,
const wxMouseEvent& event);
virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event);
protected:
// the methods which must be overridden in the derived class
// return TRUE to stop scrolling when the mouse leaves the scrollbar (Win32
// behaviour) or FALSE to continue (GTK+)
virtual bool OnMouseLeave() = 0;
// return TRUE if the mouse button can be used to activate scrollbar, FALSE
// if not (only left mouse button can do it under Windows, any button under
// GTK+)
virtual bool IsAllowedButton(int button) = 0;
// set or clear the specified flag on the scrollbar element corresponding
// to m_htLast
void SetElementState(wxScrollBar *scrollbar, int flag, bool doIt);
// [un]highlight the scrollbar element corresponding to m_htLast
void Highlight(wxScrollBar *scrollbar, bool doIt)
{ SetElementState(scrollbar, wxCONTROL_CURRENT, doIt); }
// [un]press the scrollbar element corresponding to m_htLast
void Press(wxScrollBar *scrollbar, bool doIt)
{ SetElementState(scrollbar, wxCONTROL_PRESSED, doIt); }
// the window (scrollbar) which has capture or NULL and the flag telling if
// the mouse is inside the element which captured it or not
wxWindow *m_winCapture;
bool m_winHasMouse;
int m_btnCapture; // the mouse button which has captured mouse
// one of wxHT_SCROLLBAR_XXX value: where has the mouse been last time?
wxHitTest m_htLast;
// the renderer (we use it only for hit testing)
wxRenderer *m_renderer;
};
#endif // _WX_UNIV_INPHAND_H_ #endif // _WX_UNIV_INPHAND_H_

View File

@@ -46,6 +46,7 @@ enum wxHitTest
wxHT_NOWHERE, wxHT_NOWHERE,
// scrollbar // scrollbar
wxHT_SCROLLBAR_FIRST = wxHT_NOWHERE,
wxHT_SCROLLBAR_ARROW_LINE_1, // left or upper arrow to scroll by line wxHT_SCROLLBAR_ARROW_LINE_1, // left or upper arrow to scroll by line
wxHT_SCROLLBAR_ARROW_LINE_2, // right or down wxHT_SCROLLBAR_ARROW_LINE_2, // right or down
wxHT_SCROLLBAR_ARROW_PAGE_1, // left or upper arrow to scroll by page wxHT_SCROLLBAR_ARROW_PAGE_1, // left or upper arrow to scroll by page
@@ -53,6 +54,7 @@ enum wxHitTest
wxHT_SCROLLBAR_THUMB, // on the thumb wxHT_SCROLLBAR_THUMB, // on the thumb
wxHT_SCROLLBAR_BAR_1, // bar to the left/above the thumb wxHT_SCROLLBAR_BAR_1, // bar to the left/above the thumb
wxHT_SCROLLBAR_BAR_2, // bar to the right/below the thumb wxHT_SCROLLBAR_BAR_2, // bar to the right/below the thumb
wxHT_SCROLLBAR_LAST,
wxHT_MAX wxHT_MAX
}; };

View File

@@ -16,6 +16,8 @@
#pragma interface "univscrolbar.h" #pragma interface "univscrolbar.h"
#endif #endif
#include "wx/univ/renderer.h" // for wxHitTest
class WXDLLEXPORT wxInputHandler; class WXDLLEXPORT wxInputHandler;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -42,15 +44,17 @@ class WXDLLEXPORT wxInputHandler;
class WXDLLEXPORT wxScrollBar : public wxScrollBarBase class WXDLLEXPORT wxScrollBar : public wxScrollBarBase
{ {
public: public:
// the parts of the scrollbar // scrollbar elements: they correspond to wxHT_SCROLLBAR_XXX constants but
// start from 0 which allows to use them as array indices
enum Element enum Element
{ {
Element_Arrow_Line_1, Element_Arrow_Line_1,
Element_Arrow_Line_2, Element_Arrow_Line_2,
Element_Arrow_Page_1, Element_Arrow_Page_1,
Element_Arrow_Page_2, Element_Arrow_Page_2,
Element_Thumb, Element_Arrow_Thumb,
Element_Bar, Element_Bar_1,
Element_Bar_2,
Element_Max Element_Max
}; };
@@ -99,10 +103,8 @@ public:
const wxEvent& event); const wxEvent& event);
// wxScrollBar sub elements state (combination of wxCONTROL_XXX) // wxScrollBar sub elements state (combination of wxCONTROL_XXX)
void SetState(Element elem, int flags) void SetState(Element which, int flags) { m_elementsState[which] = flags; }
{ m_elementsState[elem] = flags; } int GetState(Element which) const { return m_elementsState[which]; }
int GetState(Element elem) const
{ return m_elementsState[elem]; }
protected: protected:
virtual wxSize DoGetBestSize() const; virtual wxSize DoGetBestSize() const;
@@ -110,7 +112,7 @@ protected:
// SetThumbPosition() helper // SetThumbPosition() helper
void DoSetThumb(int thumbPos); void DoSetThumb(int thumbPos);
// common part of all ctors // common part of all ctors
void Init(); void Init();

View File

@@ -1015,7 +1015,7 @@ void wxWindow::OnIdle(wxIdleEvent& event)
state |= MK_MBUTTON; state |= MK_MBUTTON;
if ( GetKeyState( VK_RBUTTON ) ) if ( GetKeyState( VK_RBUTTON ) )
state |= MK_RBUTTON; state |= MK_RBUTTON;
wxMouseEvent event(wxEVT_LEAVE_WINDOW); wxMouseEvent event(wxEVT_LEAVE_WINDOW);
InitMouseEvent(event, pt.x, pt.y, state); InitMouseEvent(event, pt.x, pt.y, state);
@@ -3273,13 +3273,22 @@ bool wxWindow::HandleMouseMove(int x, int y, WXUINT flags)
{ {
if ( !m_mouseInWindow ) if ( !m_mouseInWindow )
{ {
// Generate an ENTER event // it would be wrogn to assume that just because we get a mouse move
m_mouseInWindow = TRUE; // event the mouse is inside the window: although this is usually true,
// it is not if we had captured the mouse, so we need to check the
// mouse coordinates here
POINT pt;
::GetCursorPos(&pt);
if ( ::WindowFromPoint(pt) == GetHwnd() )
{
// Generate an ENTER event
m_mouseInWindow = TRUE;
wxMouseEvent event(wxEVT_ENTER_WINDOW); wxMouseEvent event(wxEVT_ENTER_WINDOW);
InitMouseEvent(event, x, y, flags); InitMouseEvent(event, x, y, flags);
(void)GetEventHandler()->ProcessEvent(event); (void)GetEventHandler()->ProcessEvent(event);
}
} }
#if wxUSE_MOUSEEVENT_HACK #if wxUSE_MOUSEEVENT_HACK

View File

@@ -37,6 +37,10 @@
// implementation // implementation
// ============================================================================ // ============================================================================
// ----------------------------------------------------------------------------
// wxInputHandler
// ----------------------------------------------------------------------------
bool wxInputHandler::OnMouseMove(wxControl * WXUNUSED(control), bool wxInputHandler::OnMouseMove(wxControl * WXUNUSED(control),
const wxMouseEvent& WXUNUSED(event)) const wxMouseEvent& WXUNUSED(event))
{ {
@@ -46,3 +50,308 @@ bool wxInputHandler::OnMouseMove(wxControl * WXUNUSED(control),
wxInputHandler::~wxInputHandler() wxInputHandler::~wxInputHandler()
{ {
} }
// ----------------------------------------------------------------------------
// wxStdButtonInputHandler
// ----------------------------------------------------------------------------
wxStdButtonInputHandler::wxStdButtonInputHandler(wxInputHandler *handler)
: wxStdInputHandler(handler)
{
m_winCapture = NULL;
}
wxControlActions wxStdButtonInputHandler::Map(wxControl *control,
const wxKeyEvent& event,
bool pressed)
{
int keycode = event.GetKeyCode();
if ( keycode == WXK_SPACE || keycode == WXK_RETURN )
{
return wxACTION_BUTTON_TOGGLE;
}
return wxStdInputHandler::Map(control, event, pressed);
}
wxControlActions wxStdButtonInputHandler::Map(wxControl *control,
const wxMouseEvent& event)
{
// the button has 2 states: pressed and normal with the following
// transitions between them:
//
// normal -> left down -> capture mouse and go to pressed state
// pressed -> left up inside -> generate click -> go to normal
// outside ------------------>
//
// the other mouse buttons are ignored
if ( event.Button(1) )
{
if ( event.ButtonDown(1) )
{
m_winCapture = control;
m_winCapture->CaptureMouse();
m_winHasMouse = TRUE;
return wxACTION_BUTTON_PRESS;
}
else // up
{
m_winCapture->ReleaseMouse();
m_winCapture = NULL;
if ( m_winHasMouse )
{
// this will generate a click event
return wxACTION_BUTTON_TOGGLE;
}
//else: the mouse was released outside the window, this doesn't
// count as a click
}
}
return wxStdInputHandler::Map(control, event);
}
bool wxStdButtonInputHandler::OnMouseMove(wxControl *control,
const wxMouseEvent& event)
{
// we only have to do soemthing when the mouse leaves/enters the pressed
// button and don't care about the other ones
if ( event.GetEventObject() == m_winCapture )
{
// leaving the button should remove its pressed state
if ( event.Leaving() )
{
// remember that the mouse is now outside
m_winHasMouse = FALSE;
// we do have a pressed button, so release it
if ( control->PerformAction(wxACTION_BUTTON_RELEASE, event) )
{
// the button state changed, refresh needed
return TRUE;
}
}
// and entering it back should make it pressed again if it had been
// pressed
else if ( event.Entering() )
{
// the mouse is (back) inside the button
m_winHasMouse = TRUE;
// we did have a pressed button which we released when leaving the
// window, press it again
if ( control->PerformAction(wxACTION_BUTTON_PRESS, event) )
{
return TRUE;
}
}
}
return wxStdInputHandler::OnMouseMove(control, event);
}
// ----------------------------------------------------------------------------
// wxStdScrollBarInputHandler
// ----------------------------------------------------------------------------
wxStdScrollBarInputHandler::wxStdScrollBarInputHandler(wxRenderer *renderer,
wxInputHandler *handler)
: wxStdInputHandler(handler)
{
m_renderer = renderer;
m_winCapture = NULL;
m_htLast = wxHT_NOWHERE;
}
void wxStdScrollBarInputHandler::SetElementState(wxScrollBar *control,
int flag,
bool doIt)
{
if ( m_htLast > wxHT_SCROLLBAR_FIRST && m_htLast < wxHT_SCROLLBAR_LAST )
{
wxScrollBar::Element
elem = (wxScrollBar::Element)(m_htLast - wxHT_SCROLLBAR_FIRST - 1);
int flags = control->GetState(elem);
if ( doIt )
flags |= flag;
else
flags &= ~flag;
control->SetState(elem, flags);
}
}
wxControlActions wxStdScrollBarInputHandler::Map(wxControl *control,
const wxKeyEvent& event,
bool pressed)
{
// we only react to the key presses here
if ( pressed )
{
switch ( event.GetKeyCode() )
{
case WXK_DOWN:
case WXK_RIGHT: return wxACTION_SCROLL_LINE_DOWN;
case WXK_UP:
case WXK_LEFT: return wxACTION_SCROLL_LINE_UP;
case WXK_HOME: return wxACTION_SCROLL_START;
case WXK_END: return wxACTION_SCROLL_END;
case WXK_PRIOR: return wxACTION_SCROLL_PAGE_UP;
case WXK_NEXT: return wxACTION_SCROLL_PAGE_DOWN;
}
}
return wxStdInputHandler::Map(control, event, pressed);
}
wxControlActions wxStdScrollBarInputHandler::Map(wxControl *control,
const wxMouseEvent& event)
{
// is this a click event from an acceptable button?
int btn = -1;
if ( event.IsButton() )
{
for ( int i = 1; i <= 3; i++ )
{
if ( event.Button(i) )
{
btn = i;
break;
}
}
wxASSERT_MSG( btn != -1, _T("unknown mouse button") );
}
if ( (btn != -1) && IsAllowedButton(btn) )
{
// determine which part of the window mouse is in
wxScrollBar *scrollbar = wxStaticCast(control, wxScrollBar);
wxHitTest ht = m_renderer->HitTestScrollbar
(
scrollbar,
event.GetPosition()
);
// when the mouse is pressed on any scrollbar element, we capture it
// and hold capture until the same mouse button is released
if ( event.ButtonDown() )
{
if ( !m_winCapture )
{
m_btnCapture = btn;
m_winCapture = control;
m_winCapture->CaptureMouse();
// generate the command
bool hasAction = TRUE;
wxControlAction action;
switch ( ht )
{
case wxHT_SCROLLBAR_ARROW_LINE_1:
action = wxACTION_SCROLL_LINE_UP;
break;
case wxHT_SCROLLBAR_ARROW_LINE_2:
action = wxACTION_SCROLL_LINE_DOWN;
break;
case wxHT_SCROLLBAR_BAR_1:
action = wxACTION_SCROLL_PAGE_UP;
break;
case wxHT_SCROLLBAR_BAR_2:
action = wxACTION_SCROLL_PAGE_DOWN;
break;
default:
hasAction = FALSE;
}
if ( hasAction )
{
control->PerformAction(action, event);
}
// remove highlighting and press the arrow instead
Highlight(scrollbar, FALSE);
m_htLast = ht;
Press(scrollbar, TRUE);
control->Refresh();
}
//else: mouse already captured, nothing to do
}
// release mouse if the *same* button went up
else if ( btn == m_btnCapture )
{
if ( m_winCapture )
{
m_winCapture->ReleaseMouse();
m_winCapture = NULL;
m_btnCapture = -1;
// unpress the arrow and highlight the current element
Press(scrollbar, FALSE);
m_htLast = ht;
Highlight(scrollbar, TRUE);
control->Refresh();
}
else
{
// this is not supposed to happen as the button can't go up
// without going down previously and then we'd have
// m_winCapture by now
wxFAIL_MSG( _T("logic error in mouse capturing code") );
}
}
}
return wxStdInputHandler::Map(control, event);
}
bool wxStdScrollBarInputHandler::OnMouseMove(wxControl *control,
const wxMouseEvent& event)
{
if ( m_winCapture )
{
// everything is locked while the mouse is captured, so don't do
// anything
return FALSE;
}
wxScrollBar *scrollbar = wxStaticCast(control, wxScrollBar);
if ( event.Moving() )
{
wxHitTest ht = m_renderer->HitTestScrollbar
(
scrollbar,
event.GetPosition()
);
if ( ht == m_htLast )
{
// nothing changed
return FALSE;
}
#ifdef DEBUG_MOUSE
wxLogDebug("Scrollbar::OnMouseMove: ht = %d", ht);
#endif // DEBUG_MOUSE
Highlight(scrollbar, FALSE);
m_htLast = ht;
Highlight(scrollbar, TRUE);
}
else if ( event.Leaving() )
{
Highlight(scrollbar, FALSE);
m_htLast = wxHT_NOWHERE;
}
// highlighting changed
return TRUE;
}

View File

@@ -56,7 +56,7 @@ void wxScrollBar::Init()
m_thumbPos = m_thumbPos =
m_pageSize = 0; m_pageSize = 0;
for ( size_t n = 0; n < Element_Max; n++ ) for ( size_t n = 0; n < WXSIZEOF(m_elementsState); n++ )
{ {
m_elementsState[n] = 0; m_elementsState[n] = 0;
} }

View File

@@ -162,53 +162,15 @@ protected:
wxGTKRenderer *m_renderer; wxGTKRenderer *m_renderer;
}; };
class wxGTKButtonInputHandler : public wxGTKInputHandler class wxGTKScrollBarInputHandler : public wxStdScrollBarInputHandler
{ {
public: public:
wxGTKButtonInputHandler(wxGTKRenderer *renderer); wxGTKScrollBarInputHandler(wxRenderer *renderer, wxInputHandler *handler)
: wxStdScrollBarInputHandler(renderer, handler) { }
virtual wxControlActions Map(wxControl *control, protected:
const wxKeyEvent& event, virtual bool OnMouseLeave() { return FALSE; }
bool pressed); virtual bool IsAllowedButton(int WXUNUSED(button)) { return TRUE; }
virtual wxControlActions Map(wxControl *control,
const wxMouseEvent& event);
virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event);
private:
wxWindow *m_winCapture;
bool m_winHasMouse;
};
class wxGTKScrollBarInputHandler : public wxGTKInputHandler
{
public:
wxGTKScrollBarInputHandler(wxGTKRenderer *renderer);
virtual wxControlActions Map(wxControl *control,
const wxKeyEvent& event,
bool pressed);
virtual wxControlActions Map(wxControl *control,
const wxMouseEvent& event);
virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event);
private:
// set or clear the specified flag on the scrollbar element corresponding
// to m_htLast
void SetElementState(wxScrollBar *scrollbar, int flag, bool doIt);
// [un]highlight the scrollbar element corresponding to m_htLast
void Highlight(wxScrollBar *scrollbar, bool doIt)
{ SetElementState(scrollbar, wxCONTROL_CURRENT, doIt); }
// [un]press the scrollbar element corresponding to m_htLast
void Press(wxScrollBar *scrollbar, bool doIt)
{ SetElementState(scrollbar, wxCONTROL_PRESSED, doIt); }
wxWindow *m_winCapture;
int m_btnCapture; // the mouse button which was captured mouse
bool m_winHasMouse;
wxHitTest m_htLast;
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -282,9 +244,10 @@ wxInputHandler *wxGTKTheme::GetInputHandler(const wxString& control)
n = m_handlerNames.Add(control); n = m_handlerNames.Add(control);
if ( control == _T("wxButton") ) if ( control == _T("wxButton") )
handler = new wxGTKButtonInputHandler(m_renderer); handler = new wxStdButtonInputHandler(GetInputHandler(_T("wxControl")));
else if ( control == _T("wxScrollBar") ) else if ( control == _T("wxScrollBar") )
handler = new wxGTKScrollBarInputHandler(m_renderer); handler = new wxGTKScrollBarInputHandler(m_renderer,
GetInputHandler(_T("wxControl")));
else else
handler = new wxGTKInputHandler(m_renderer); handler = new wxGTKInputHandler(m_renderer);
@@ -810,9 +773,9 @@ void wxGTKRenderer::DrawScrollbar(wxDC& dc,
"\tthumb: 0x%04x\n" "\tthumb: 0x%04x\n"
"\tthumb from %d to %d", "\tthumb from %d to %d",
orient == wxVERTICAL ? "vertical" : "horizontal", orient == wxVERTICAL ? "vertical" : "horizontal",
flags[wxScrollBar::Element_Arrow_Line_1], flags[wxHT_SCROLLBAR_ARROW_LINE_1],
flags[wxScrollBar::Element_Arrow_Line_2], flags[wxHT_SCROLLBAR_ARROW_LINE_2],
flags[wxScrollBar::Element_Thumb], flags[wxHT_SCROLLBAR_THUMB],
thumbPosStart, thumbPosEnd); thumbPosStart, thumbPosEnd);
#endif // DEBUG_MOUSE #endif // DEBUG_MOUSE
@@ -850,7 +813,7 @@ void wxGTKRenderer::DrawScrollbar(wxDC& dc,
for ( size_t nArrow = 0; nArrow < 2; nArrow++ ) for ( size_t nArrow = 0; nArrow < 2; nArrow++ )
{ {
DrawArrow(dc, arrowDir[nArrow], rectArrow[nArrow], DrawArrow(dc, arrowDir[nArrow], rectArrow[nArrow],
flags[wxScrollBar::Element_Arrow_Line_1 + nArrow]); flags[wxHT_SCROLLBAR_ARROW_LINE_1 + nArrow]);
} }
// and, finally, the thumb, if any // and, finally, the thumb, if any
@@ -874,7 +837,7 @@ void wxGTKRenderer::DrawScrollbar(wxDC& dc,
// the thumb is never pressed never has focus border under GTK and the // the thumb is never pressed never has focus border under GTK and the
// scrollbar background never changes at all // scrollbar background never changes at all
int flagsThumb = flags[wxScrollBar::Element_Thumb] & int flagsThumb = flags[wxHT_SCROLLBAR_THUMB] &
~(wxCONTROL_PRESSED | wxCONTROL_FOCUSED); ~(wxCONTROL_PRESSED | wxCONTROL_FOCUSED);
DrawButtonBorder(dc, rectThumb, flagsThumb, &rectThumb); DrawButtonBorder(dc, rectThumb, flagsThumb, &rectThumb);
DrawBackground(dc, rectThumb, flagsThumb); DrawBackground(dc, rectThumb, flagsThumb);
@@ -995,300 +958,3 @@ bool wxGTKInputHandler::OnMouseMove(wxControl *control,
return TRUE; return TRUE;
} }
// ----------------------------------------------------------------------------
// wxGTKButtonInputHandler
// ----------------------------------------------------------------------------
wxGTKButtonInputHandler::wxGTKButtonInputHandler(wxGTKRenderer *renderer)
: wxGTKInputHandler(renderer)
{
m_winCapture = NULL;
}
wxControlActions wxGTKButtonInputHandler::Map(wxControl *control,
const wxKeyEvent& event,
bool pressed)
{
int keycode = event.GetKeyCode();
if ( keycode == WXK_SPACE || keycode == WXK_RETURN )
{
return wxACTION_BUTTON_TOGGLE;
}
return wxGTKInputHandler::Map(control, event, pressed);
}
wxControlActions wxGTKButtonInputHandler::Map(wxControl *control,
const wxMouseEvent& event)
{
// the button has 2 states: pressed and normal with the following
// transitions between them:
//
// normal -> left down -> capture mouse and go to pressed state
// pressed -> left up inside -> generate click -> go to normal
// outside ------------------>
//
// the other mouse buttons are ignored
if ( event.Button(1) )
{
if ( event.ButtonDown(1) )
{
m_winCapture = control;
m_winCapture->CaptureMouse();
m_winHasMouse = TRUE;
return wxACTION_BUTTON_PRESS;
}
else // up
{
m_winCapture->ReleaseMouse();
m_winCapture = NULL;
if ( m_winHasMouse )
{
// this will generate a click event
return wxACTION_BUTTON_TOGGLE;
}
//else: the mouse was released outside the window, this doesn't
// count as a click
}
}
return wxGTKInputHandler::Map(control, event);
}
bool wxGTKButtonInputHandler::OnMouseMove(wxControl *control,
const wxMouseEvent& event)
{
// leaving the button should remove its pressed state
if ( event.Leaving() )
{
if ( m_winCapture )
{
// we do have a pressed button, so release it
control->PerformAction(wxACTION_BUTTON_RELEASE, event);
// remember that the mouse is now outside
m_winHasMouse = FALSE;
}
}
// and entering it back should make it pressed again if it had been
// pressed
else if ( event.Entering() )
{
if ( m_winCapture )
{
// we did have a pressed button which we released when leaving the
// window, press it again
control->PerformAction(wxACTION_BUTTON_PRESS, event);
// and the mouse is (back) inside it
m_winHasMouse = TRUE;
}
}
return wxGTKInputHandler::OnMouseMove(control, event);
}
// ----------------------------------------------------------------------------
// wxGTKScrollBarInputHandler
// ----------------------------------------------------------------------------
wxGTKScrollBarInputHandler::wxGTKScrollBarInputHandler(wxGTKRenderer *renderer)
: wxGTKInputHandler(renderer)
{
m_winCapture = NULL;
m_htLast = wxHT_NOWHERE;
}
void wxGTKScrollBarInputHandler::SetElementState(wxScrollBar *control,
int flag,
bool doIt)
{
wxScrollBar::Element elem;
switch ( m_htLast )
{
case wxHT_SCROLLBAR_ARROW_LINE_1:
elem = wxScrollBar::Element_Arrow_Line_1;
break;
case wxHT_SCROLLBAR_ARROW_LINE_2:
elem = wxScrollBar::Element_Arrow_Line_2;
break;
case wxHT_SCROLLBAR_THUMB:
elem = wxScrollBar::Element_Thumb;
break;
/*
we don't highlight nor press the bar
case wxHT_SCROLLBAR_BAR_1:
case wxHT_SCROLLBAR_BAR_2:
*/
default:
elem = wxScrollBar::Element_Max;
}
if ( elem != wxScrollBar::Element_Max )
{
int flags = control->GetState(elem);
if ( doIt )
flags |= flag;
else
flags &= ~flag;
control->SetState(elem, flags);
}
}
wxControlActions wxGTKScrollBarInputHandler::Map(wxControl *control,
const wxKeyEvent& event,
bool pressed)
{
// weirdly enough, GTK+ scrollbars don't have keyboard support - maybe we
// should still have it though (TODO)?
return wxGTKInputHandler::Map(control, event, pressed);
}
wxControlActions wxGTKScrollBarInputHandler::Map(wxControl *control,
const wxMouseEvent& event)
{
if ( event.IsButton() )
{
// determine which part of the window mouse is in
wxScrollBar *scrollbar = wxStaticCast(control, wxScrollBar);
wxHitTest ht = m_renderer->HitTestScrollbar
(
scrollbar,
event.GetPosition()
);
// when the mouse is pressed on any scrollbar element, we capture it
// and hold capture until the same mouse button is released
if ( event.ButtonDown() )
{
if ( !m_winCapture )
{
m_btnCapture = -1;
for ( int i = 1; i <= 3; i++ )
{
if ( event.ButtonDown(i) )
{
m_btnCapture = i;
break;
}
}
wxASSERT_MSG( m_btnCapture != -1, _T("unknown mouse button") );
m_winCapture = control;
m_winCapture->CaptureMouse();
// generate the command
bool hasAction = TRUE;
wxControlAction action;
switch ( ht )
{
case wxHT_SCROLLBAR_ARROW_LINE_1:
action = wxACTION_SCROLL_LINE_UP;
break;
case wxHT_SCROLLBAR_ARROW_LINE_2:
action = wxACTION_SCROLL_LINE_DOWN;
break;
case wxHT_SCROLLBAR_BAR_1:
action = wxACTION_SCROLL_PAGE_UP;
break;
case wxHT_SCROLLBAR_BAR_2:
action = wxACTION_SCROLL_PAGE_DOWN;
break;
default:
hasAction = FALSE;
}
if ( hasAction )
{
control->PerformAction(action, event);
}
// remove highlighting and press the arrow instead
Highlight(scrollbar, FALSE);
m_htLast = ht;
Press(scrollbar, TRUE);
}
//else: mouse already captured, nothing to do
}
// release mouse if the *same* button went up
else if ( event.ButtonUp(m_btnCapture) )
{
if ( m_winCapture )
{
m_winCapture->ReleaseMouse();
m_winCapture = NULL;
// unpress the arrow and highlight the current element
Press(scrollbar, TRUE);
m_htLast = ht;
Highlight(scrollbar, TRUE);
control->Refresh();
}
else
{
// this is not supposed to happen as the button can't go up
// without going down previously and then we'd have
// m_winCapture by now
wxFAIL_MSG( _T("logic error in mouse capturing code") );
}
}
}
return wxGTKInputHandler::Map(control, event);
}
bool wxGTKScrollBarInputHandler::OnMouseMove(wxControl *control,
const wxMouseEvent& event)
{
if ( m_winCapture )
{
// everything is locked while the mouse is captured, so don't do
// anything
return FALSE;
}
wxScrollBar *scrollbar = wxStaticCast(control, wxScrollBar);
if ( event.Moving() )
{
wxHitTest ht = m_renderer->HitTestScrollbar
(
scrollbar,
event.GetPosition()
);
if ( ht == m_htLast )
{
// nothing changed
return FALSE;
}
#ifdef DEBUG_MOUSE
wxLogDebug("Scrollbar::OnMouseMove: ht = %d", ht);
#endif // DEBUG_MOUSE
Highlight(scrollbar, FALSE);
m_htLast = ht;
Highlight(scrollbar, TRUE);
}
else if ( event.Leaving() )
{
Highlight(scrollbar, FALSE);
m_htLast = wxHT_NOWHERE;
}
// highlighting changed
return TRUE;
}

View File

@@ -61,6 +61,7 @@ public:
{ {
Arrow_Normal, Arrow_Normal,
Arrow_Disabled, Arrow_Disabled,
Arrow_Pressed,
Arrow_StateMax Arrow_StateMax
}; };
@@ -132,7 +133,7 @@ protected:
void DrawRaisedBorder(wxDC& dc, wxRect *rect); void DrawRaisedBorder(wxDC& dc, wxRect *rect);
// draw the border used for scrollbar arrows // draw the border used for scrollbar arrows
void DrawArrowBorder(wxDC& dc, wxRect *rect); void DrawArrowBorder(wxDC& dc, wxRect *rect, bool isPressed = FALSE);
// public DrawArrow()s helper // public DrawArrow()s helper
void DrawArrow(wxDC& dc, const wxRect& rect, void DrawArrow(wxDC& dc, const wxRect& rect,
@@ -182,38 +183,26 @@ protected:
wxWin32Renderer *m_renderer; wxWin32Renderer *m_renderer;
}; };
class wxWin32ButtonInputHandler : public wxWin32InputHandler class wxWin32ScrollBarInputHandler : public wxStdScrollBarInputHandler
{ {
public: public:
wxWin32ButtonInputHandler(wxWin32Renderer *renderer); wxWin32ScrollBarInputHandler(wxWin32Renderer *renderer,
wxInputHandler *handler)
: wxStdScrollBarInputHandler(renderer, handler) { }
virtual wxControlActions Map(wxControl *control, // we don't highlight scrollbar elements, so there is no need to process
const wxKeyEvent& event, // mouse move events
bool pressed); virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event)
virtual wxControlActions Map(wxControl *control, {
const wxMouseEvent& event); if ( event.Moving() )
return FALSE;
private: return wxStdScrollBarInputHandler::OnMouseMove(control, event);
wxWindow *m_winCapture; }
};
class wxWin32ScrollBarInputHandler : public wxWin32InputHandler protected:
{ virtual bool OnMouseLeave() { return TRUE; }
public: virtual bool IsAllowedButton(int button) { return button == 1; }
wxWin32ScrollBarInputHandler(wxWin32Renderer *renderer);
virtual wxControlActions Map(wxControl *control,
const wxKeyEvent& event,
bool pressed);
virtual wxControlActions Map(wxControl *control,
const wxMouseEvent& event);
private:
void Press(wxScrollBar *scrollbar, bool doIt) { }
wxWindow *m_winCapture;
int m_btnCapture;
wxHitTest m_htLast;
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -289,9 +278,10 @@ wxInputHandler *wxWin32Theme::GetInputHandler(const wxString& control)
n = m_handlerNames.Add(control); n = m_handlerNames.Add(control);
if ( control == _T("wxButton") ) if ( control == _T("wxButton") )
handler = new wxWin32ButtonInputHandler(m_renderer); handler = new wxStdButtonInputHandler(GetInputHandler(_T("wxControl")));
else if ( control == _T("wxScrollBar") ) else if ( control == _T("wxScrollBar") )
handler = new wxWin32ScrollBarInputHandler(m_renderer); handler = new wxWin32ScrollBarInputHandler(m_renderer,
GetInputHandler(_T("wxControl")));
else else
handler = new wxWin32InputHandler(m_renderer); handler = new wxWin32InputHandler(m_renderer);
@@ -322,6 +312,10 @@ wxColour wxWin32ColourScheme::Get(wxWin32ColourScheme::StdColour col,
{ {
case CONTROL: return wxColour(0xc0c0c0); case CONTROL: return wxColour(0xc0c0c0);
case CONTROL_TEXT: return *wxBLACK; case CONTROL_TEXT: return *wxBLACK;
case SCROLLBAR: if ( flags & wxCONTROL_PRESSED )
return *wxBLACK;
else
return wxColour(0xe0e0e0);
case HIGHLIGHT: return wxColour(0x800000); case HIGHLIGHT: return wxColour(0x800000);
case HIGHLIGHT_TEXT: return wxColour(0xffffff); case HIGHLIGHT_TEXT: return wxColour(0xffffff);
@@ -500,6 +494,8 @@ wxWin32Renderer::wxWin32Renderer(const wxColourScheme *scheme)
m_bmpArrows[Arrow_Normal][n].SetMask(mask); m_bmpArrows[Arrow_Normal][n].SetMask(mask);
mask = new wxMask(m_bmpArrows[Arrow_Disabled][n], *wxWHITE); mask = new wxMask(m_bmpArrows[Arrow_Disabled][n], *wxWHITE);
m_bmpArrows[Arrow_Disabled][n].SetMask(mask); m_bmpArrows[Arrow_Disabled][n].SetMask(mask);
m_bmpArrows[Arrow_Pressed][n] = m_bmpArrows[Arrow_Normal][n];
} }
} }
@@ -624,10 +620,25 @@ void wxWin32Renderer::DrawRaisedBorder(wxDC& dc, wxRect *rect)
DrawShadedRect(dc, rect, m_penLightGrey, m_penDarkGrey); DrawShadedRect(dc, rect, m_penLightGrey, m_penDarkGrey);
} }
void wxWin32Renderer::DrawArrowBorder(wxDC& dc, wxRect *rect) void wxWin32Renderer::DrawArrowBorder(wxDC& dc, wxRect *rect, bool isPressed)
{ {
DrawShadedRect(dc, rect, m_penLightGrey, m_penBlack); if ( isPressed )
DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey); {
DrawRect(dc, rect, m_penDarkGrey);
// the arrow is usually drawn inside border of width 2 and is offset by
// another pixel in both directions when it's pressed - as the border
// in this case is more narrow as well, we have to adjust rect like
// this:
rect->Inflate(-1);
rect->x++;
rect->y++;
}
else
{
DrawShadedRect(dc, rect, m_penLightGrey, m_penBlack);
DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
}
} }
void wxWin32Renderer::DrawBorder(wxDC& dc, void wxWin32Renderer::DrawBorder(wxDC& dc,
@@ -912,7 +923,7 @@ void wxWin32Renderer::DrawArrowButton(wxDC& dc,
wxArrowStyle arrowStyle) wxArrowStyle arrowStyle)
{ {
wxRect rect = rectAll; wxRect rect = rectAll;
DrawArrowBorder(dc, &rect); DrawArrowBorder(dc, &rect, arrowStyle == Arrow_Pressed);
DrawArrow(dc, rect, arrowDir, arrowStyle); DrawArrow(dc, rect, arrowDir, arrowStyle);
} }
@@ -923,10 +934,6 @@ void wxWin32Renderer::DrawScrollbar(wxDC& dc,
const wxRect& rect, const wxRect& rect,
const int *flags) const int *flags)
{ {
int flagsSb = flags ? flags[0] : 0;
wxArrowStyle arrowStyle = flagsSb & wxCONTROL_DISABLED ? Arrow_Disabled
: Arrow_Normal;
// first, draw the arrows at the ends // first, draw the arrows at the ends
wxRect rectArrow[2]; wxRect rectArrow[2];
wxArrowDirection arrowDir[2]; wxArrowDirection arrowDir[2];
@@ -952,24 +959,34 @@ void wxWin32Renderer::DrawScrollbar(wxDC& dc,
arrowDir[1] = Arrow_Right; arrowDir[1] = Arrow_Right;
} }
wxArrowStyle arrowStyle;
for ( size_t nArrow = 0; nArrow < 2; nArrow++ ) for ( size_t nArrow = 0; nArrow < 2; nArrow++ )
{ {
int flagsArrow = flags[wxScrollBar::Element_Arrow_Line_1 + nArrow];
if ( flagsArrow & wxCONTROL_PRESSED )
arrowStyle = Arrow_Pressed;
else if ( flagsArrow & wxCONTROL_DISABLED )
arrowStyle = Arrow_Disabled;
else
arrowStyle = Arrow_Normal;
DrawArrowButton(dc, rectArrow[nArrow], arrowDir[nArrow], arrowStyle); DrawArrowButton(dc, rectArrow[nArrow], arrowDir[nArrow], arrowStyle);
} }
// next draw the scrollbar area // next draw the scrollbar area: in a normal state, we draw it all in one
// call to DoDrawBackground(), but when either part of the bar is pressed,
// we paint them separately
wxRect rectBar = rect; wxRect rectBar = rect;
if ( orient == wxVERTICAL ) if ( orient == wxVERTICAL )
rectBar.Inflate(0, -m_sizeScrollbarArrow.y); rectBar.Inflate(0, -(m_sizeScrollbarArrow.y + 1));
else else
rectBar.Inflate(-m_sizeScrollbarArrow.x, 0); rectBar.Inflate(-(m_sizeScrollbarArrow.x + 1), 0);
DoDrawBackground(dc, m_colHighlight, rectBar); // calculate the thumb position
wxRect rectThumb;
// and, finally, the thumb, if any
if ( thumbPosStart < thumbPosEnd ) if ( thumbPosStart < thumbPosEnd )
{ {
wxRect rectThumb = rectBar; rectThumb = rectBar;
if ( orient == wxVERTICAL ) if ( orient == wxVERTICAL )
{ {
rectThumb.y += (rectBar.height*thumbPosStart)/100; rectThumb.y += (rectBar.height*thumbPosStart)/100;
@@ -980,7 +997,53 @@ void wxWin32Renderer::DrawScrollbar(wxDC& dc,
rectThumb.x += (rectBar.width*thumbPosStart)/100; rectThumb.x += (rectBar.width*thumbPosStart)/100;
rectThumb.width = (rectBar.width*(thumbPosEnd - thumbPosStart))/100; rectThumb.width = (rectBar.width*(thumbPosEnd - thumbPosStart))/100;
} }
}
//else: no thumb
if ( (flags[wxScrollBar::Element_Bar_1] & wxCONTROL_PRESSED) ||
(flags[wxScrollBar::Element_Bar_2] & wxCONTROL_PRESSED) )
{
// calculate the bounding boxes for each of 2 bar parts
wxRect rectBars[2];
rectBars[0] =
rectBars[1] = rectBar;
if ( orient == wxVERTICAL )
{
rectBars[0].SetTop(m_sizeScrollbarArrow.y);
rectBars[0].SetBottom(rectThumb.GetTop() - 1);
rectBars[1].SetTop(rectThumb.GetBottom() + 1);
rectBars[1].SetBottom(rectBar.GetBottom());
}
else // horizontal
{
rectBars[0].SetLeft(m_sizeScrollbarArrow.x);
rectBars[0].SetRight(rectThumb.GetLeft() - 1);
rectBars[1].SetLeft(rectThumb.GetRight() + 1);
rectBars[1].SetRight(rectBar.GetRight());
}
for ( size_t nBar = 0; nBar < 2; nBar++ )
{
DoDrawBackground(
dc,
m_scheme->Get
(
wxColourScheme::SCROLLBAR,
flags[wxScrollBar::Element_Bar_1 + nBar]
),
rectBars[nBar]
);
}
}
else // nothing is pressed
{
DoDrawBackground(dc, m_scheme->Get(wxColourScheme::SCROLLBAR), rectBar);
}
// and, finally, the thumb, if any
if ( thumbPosStart < thumbPosEnd )
{
// we don't use the flags, the thumb never changes appearance
DrawArrowBorder(dc, &rectThumb); DrawArrowBorder(dc, &rectThumb);
DrawBackground(dc, rectThumb); DrawBackground(dc, rectThumb);
} }
@@ -1072,178 +1135,3 @@ wxControlActions wxWin32InputHandler::Map(wxControl *control,
{ {
return wxACTION_NONE; return wxACTION_NONE;
} }
// ----------------------------------------------------------------------------
// wxWin32ButtonInputHandler
// ----------------------------------------------------------------------------
wxWin32ButtonInputHandler::wxWin32ButtonInputHandler(wxWin32Renderer *renderer)
: wxWin32InputHandler(renderer)
{
m_winCapture = NULL;
}
wxControlActions wxWin32ButtonInputHandler::Map(wxControl *control,
const wxKeyEvent& event,
bool pressed)
{
int keycode = event.GetKeyCode();
if ( keycode == WXK_SPACE || keycode == WXK_RETURN )
{
return wxACTION_BUTTON_TOGGLE;
}
return wxWin32InputHandler::Map(control, event, pressed);
}
wxControlActions wxWin32ButtonInputHandler::Map(wxControl *control,
const wxMouseEvent& event)
{
if ( event.IsButton() )
{
if ( event.ButtonDown() )
{
m_winCapture = wxWindow::FindFocus();
m_winCapture->CaptureMouse();
}
else // up
{
m_winCapture->ReleaseMouse();
}
return wxACTION_BUTTON_TOGGLE;
}
return wxWin32InputHandler::Map(control, event);
}
// ----------------------------------------------------------------------------
// wxWin32ScrollBarInputHandler
// ----------------------------------------------------------------------------
wxWin32ScrollBarInputHandler::wxWin32ScrollBarInputHandler(wxWin32Renderer *renderer)
: wxWin32InputHandler(renderer)
{
m_winCapture = NULL;
m_htLast = wxHT_NOWHERE;
}
wxControlActions wxWin32ScrollBarInputHandler::Map(wxControl *control,
const wxKeyEvent& event,
bool pressed)
{
// we only react to the key presses here
if ( pressed )
{
switch ( event.GetKeyCode() )
{
case WXK_DOWN:
case WXK_RIGHT: return wxACTION_SCROLL_LINE_DOWN;
case WXK_UP:
case WXK_LEFT: return wxACTION_SCROLL_LINE_UP;
case WXK_HOME: return wxACTION_SCROLL_START;
case WXK_END: return wxACTION_SCROLL_END;
case WXK_PRIOR: return wxACTION_SCROLL_PAGE_UP;
case WXK_NEXT: return wxACTION_SCROLL_PAGE_DOWN;
}
}
return wxWin32InputHandler::Map(control, event, pressed);
}
wxControlActions wxWin32ScrollBarInputHandler::Map(wxControl *control,
const wxMouseEvent& event)
{
if ( event.IsButton() )
{
// determine which part of the window mouse is in
wxScrollBar *scrollbar = wxStaticCast(control, wxScrollBar);
wxHitTest ht = m_renderer->HitTestScrollbar
(
scrollbar,
event.GetPosition()
);
// when the mouse is pressed on any scrollbar element, we capture it
// and hold capture until the same mouse button is released
if ( event.ButtonDown() )
{
if ( !m_winCapture )
{
m_btnCapture = -1;
for ( int i = 1; i <= 3; i++ )
{
if ( event.ButtonDown(i) )
{
m_btnCapture = i;
break;
}
}
wxASSERT_MSG( m_btnCapture != -1, _T("unknown mouse button") );
m_winCapture = control;
m_winCapture->CaptureMouse();
// generate the command
bool hasAction = TRUE;
wxControlAction action;
switch ( ht )
{
case wxHT_SCROLLBAR_ARROW_LINE_1:
action = wxACTION_SCROLL_LINE_UP;
break;
case wxHT_SCROLLBAR_ARROW_LINE_2:
action = wxACTION_SCROLL_LINE_DOWN;
break;
case wxHT_SCROLLBAR_BAR_1:
action = wxACTION_SCROLL_PAGE_UP;
break;
case wxHT_SCROLLBAR_BAR_2:
action = wxACTION_SCROLL_PAGE_DOWN;
break;
default:
hasAction = FALSE;
}
if ( hasAction )
{
control->PerformAction(action, event);
}
// remove highlighting and press the arrow instead
m_htLast = ht;
Press(scrollbar, TRUE);
}
//else: mouse already captured, nothing to do
}
// release mouse if the *same* button went up
else if ( event.ButtonUp(m_btnCapture) )
{
if ( m_winCapture )
{
m_winCapture->ReleaseMouse();
m_winCapture = NULL;
// unpress the arrow and highlight the current element
Press(scrollbar, TRUE);
m_htLast = ht;
control->Refresh();
}
else
{
// this is not supposed to happen as the button can't go up
// without going down previously and then we'd have
// m_winCapture by now
wxFAIL_MSG( _T("logic error in mouse capturing code") );
}
}
}
return wxWin32InputHandler::Map(control, event);
}