diff --git a/include/wx/dc.h b/include/wx/dc.h index dd3f71e69d..6104ec6f3c 100644 --- a/include/wx/dc.h +++ b/include/wx/dc.h @@ -256,14 +256,22 @@ public: void DrawRotatedText(const wxString& text, const wxPoint& pt, double angle) { DoDrawRotatedText(text, pt.x, pt.y, angle); } - // this verson puts text into the given rectangle and aligns is as - // specified by alignment parameter; it also will emphasize the character - // with the given index if it is != -1 and return the boundign rectangle - virtual void DrawLabel(const wxString& text, const wxRect& rect, + // this verson puts both optional bitmap and the text into the given + // rectangle and aligns is as specified by alignment parameter; it also + // will emphasize the character with the given index if it is != -1 and + // return the bounding rectangle if required + virtual void DrawLabel(const wxString& text, + const wxBitmap& image, + const wxRect& rect, int alignment = wxALIGN_LEFT | wxALIGN_TOP, int indexAccel = -1, wxRect *rectBounding = NULL); + void DrawLabel(const wxString& text, const wxRect& rect, + int alignment = wxALIGN_LEFT | wxALIGN_TOP, + int indexAccel = -1) + { DrawLabel(text, wxNullBitmap, rect, alignment, indexAccel); } + bool Blit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, wxDC *source, wxCoord xsrc, wxCoord ysrc, int rop = wxCOPY, bool useMask = FALSE) diff --git a/include/wx/msw/setup0.h b/include/wx/msw/setup0.h index cd0e2bdde1..13d7141c2f 100644 --- a/include/wx/msw/setup0.h +++ b/include/wx/msw/setup0.h @@ -377,7 +377,10 @@ #define wxUSE_SLIDER 1 #define wxUSE_SPINBTN 1 #define wxUSE_SPINCTRL 1 +#define wxUSE_STATBMP 1 +#define wxUSE_STATBOX 1 #define wxUSE_STATLINE 1 +#define wxUSE_STATTEXT 1 #define wxUSE_STATUSBAR 1 #define wxUSE_TOOLTIPS 1 // wxToolTip and wxWindow::SetToolTip() diff --git a/include/wx/scrolbar.h b/include/wx/scrolbar.h index 066dd0659f..2a23f9aa88 100644 --- a/include/wx/scrolbar.h +++ b/include/wx/scrolbar.h @@ -29,6 +29,8 @@ public: virtual int GetPageSize() const = 0; virtual int GetRange() const = 0; + bool IsVertical() const { return m_windowStyle & wxVERTICAL != 0; } + // operations virtual void SetThumbPosition(int viewStart) = 0; virtual void SetScrollbar(int position, int thumbSize, diff --git a/include/wx/univ/control.h b/include/wx/univ/control.h index 502e981933..f507adc6b8 100644 --- a/include/wx/univ/control.h +++ b/include/wx/univ/control.h @@ -70,8 +70,7 @@ public: // the list of actions which apply to all controls (other actions are defined // in the controls headers) -#define wxACTION_NONE _T("") // no action to perform -#define wxACTION_FOCUS _T("focus") // make control focused +#define wxACTION_NONE _T("") // no action to perform // ---------------------------------------------------------------------------- // wxControl: the base class for all GUI controls diff --git a/include/wx/univ/inphand.h b/include/wx/univ/inphand.h index bb846f621f..5534674dff 100644 --- a/include/wx/univ/inphand.h +++ b/include/wx/univ/inphand.h @@ -49,6 +49,13 @@ public: // return TRUE to refresh the control, FALSE otherwise virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event); + // do something with focus set/kill event: this is different from + // OnMouseMove() as the mouse maybe over the control without it having + // focus + // + // return TRUE to refresh the control, FALSE otherwise + virtual bool OnFocus(wxControl *control, const wxFocusEvent& event); + // virtual dtor for any base class virtual ~wxInputHandler(); }; @@ -78,6 +85,8 @@ public: { return m_handler->Map(control, event); } virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event) { return m_handler->OnMouseMove(control, event); } + virtual bool OnFocus(wxControl *control, const wxFocusEvent& event) + { return m_handler->OnFocus(control, event); } private: wxInputHandler *m_handler; @@ -99,6 +108,7 @@ public: virtual wxControlActions Map(wxControl *control, const wxMouseEvent& event); virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event); + virtual bool OnFocus(wxControl *control, const wxFocusEvent& event); private: // the window (button) which has capture or NULL and the flag telling if @@ -129,13 +139,16 @@ public: virtual ~wxStdScrollBarInputHandler(); + // this method is called by wxScrollBarTimer only and may be overridden + // + // return TRUE to continue scrolling, FALSE to stop the timer + virtual bool OnScrollTimer(wxScrollBar *scrollbar, + const wxControlAction& action, + 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+) @@ -153,12 +166,18 @@ protected: void Press(wxScrollBar *scrollbar, bool doIt) { SetElementState(scrollbar, wxCONTROL_PRESSED, doIt); } + // stop scrolling because we reached the end point + void StopScrolling(wxScrollBar *scrollbar); + // 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 + // the position where we started scrolling by page + wxPoint m_ptStartScrolling; + // one of wxHT_SCROLLBAR_XXX value: where has the mouse been last time? wxHitTest m_htLast; @@ -167,7 +186,7 @@ protected: // the timer for generating scroll events when the mouse stays pressed on // a scrollbar - class wxScrollBarTimer *m_timerScroll; + class wxTimer *m_timerScroll; }; #endif // _WX_UNIV_INPHAND_H_ diff --git a/include/wx/univ/renderer.h b/include/wx/univ/renderer.h index d9734c02d3..42a8261271 100644 --- a/include/wx/univ/renderer.h +++ b/include/wx/univ/renderer.h @@ -78,10 +78,12 @@ public: // and optionally emphasize the character with the given index virtual void DrawLabel(wxDC& dc, const wxString& label, + const wxBitmap& image, const wxRect& rect, int flags = 0, int alignment = wxALIGN_LEFT | wxALIGN_TOP, - int indexAccel = -1) = 0; + int indexAccel = -1, + wxRect *rectBounds = NULL) = 0; // draw the border and optionally return the rectangle containing the // region inside the border @@ -188,11 +190,14 @@ public: { m_renderer->DrawBackground(dc, rect, flags); } virtual void DrawLabel(wxDC& dc, const wxString& label, + const wxBitmap& image, const wxRect& rect, int flags = 0, int align = wxALIGN_LEFT | wxALIGN_TOP, - int indexAccel = -1) - { m_renderer->DrawLabel(dc, label, rect, flags, align, indexAccel); } + int indexAccel = -1, + wxRect *rectBounds = NULL) + { m_renderer->DrawLabel(dc, label, image, rect, + flags, align, indexAccel, rectBounds); } virtual void DrawBorder(wxDC& dc, wxBorder border, const wxRect& rect, diff --git a/include/wx/univ/setup.h b/include/wx/univ/setup.h index c6029b1511..71ac6609f9 100644 --- a/include/wx/univ/setup.h +++ b/include/wx/univ/setup.h @@ -35,7 +35,7 @@ #define wxUSE_STD_IOSTREAM 0 #define wxUSE_SERIAL 0 #define wxUSE_LONGLONG 0 -#define wxUSE_TIMER 0 +#define wxUSE_TIMER 1 #define wxUSE_TIMEDATE 0 #define wxUSE_DATETIME 0 #define wxUSE_CONFIG 0 @@ -67,7 +67,7 @@ #define wxUSE_CONTROLS 1 #define wxUSE_BUTTON 1 -#define wxUSE_BMPBUTTON 0 +#define wxUSE_BMPBUTTON 1 #define wxUSE_CARET 0 #define wxUSE_CHECKBOX 0 #define wxUSE_CHECKLISTBOX 0 @@ -84,9 +84,9 @@ #define wxUSE_SPINBTN 0 #define wxUSE_SPINCTRL 0 #define wxUSE_STATBOX 1 -#define wxUSE_STATLINE 0 +#define wxUSE_STATLINE 1 #define wxUSE_STATTEXT 1 -#define wxUSE_STATLBMP 0 +#define wxUSE_STATBMP 1 #define wxUSE_STATUSBAR 0 #define wxUSE_TOOLTIPS 0 #define wxUSE_TREECTRL 0 diff --git a/include/wx/univ/theme.h b/include/wx/univ/theme.h index 4a5840e645..39b7c83c4c 100644 --- a/include/wx/univ/theme.h +++ b/include/wx/univ/theme.h @@ -25,6 +25,7 @@ class WXDLLEXPORT wxRenderer; class WXDLLEXPORT wxInputHandler; class WXDLLEXPORT wxColourScheme; +struct WXDLLEXPORT wxThemeInfo; class WXDLLEXPORT wxTheme { @@ -62,24 +63,6 @@ public: virtual ~wxTheme(); - // dynamic creation helpers - typedef wxTheme *(*Constructor)(); - - struct wxThemeInfo - { - // theme name and (user readable) description - wxString name, desc; - - // the function to create a theme object - Constructor ctor; - - // next node in the linked list or NULL - wxThemeInfo *next; - - // constructor for the struct itself - wxThemeInfo(Constructor ctor, const wxChar *name, const wxChar *desc); - }; - private: // the list of descriptions of all known themes static wxThemeInfo *ms_allThemes; @@ -91,17 +74,34 @@ private: }; // ---------------------------------------------------------------------------- -// macros +// dynamic theme creation helpers // ---------------------------------------------------------------------------- +struct WXDLLEXPORT wxThemeInfo +{ + typedef wxTheme *(*Constructor)(); + + // theme name and (user readable) description + wxString name, desc; + + // the function to create a theme object + Constructor ctor; + + // next node in the linked list or NULL + wxThemeInfo *next; + + // constructor for the struct itself + wxThemeInfo(Constructor ctor, const wxChar *name, const wxChar *desc); +}; + // to declare a new theme, this macro must be used in the class declaration #define WX_DECLARE_THEME() static wxThemeInfo ms_info // and this one must be inserted in the source file #define WX_IMPLEMENT_THEME(classname, themename, themedesc) \ wxTheme *wxCtorFor##themename() { return new classname; } \ - wxTheme::wxThemeInfo classname::ms_info(wxCtorFor##themename, \ - #themename, themedesc) + wxThemeInfo classname::ms_info(wxCtorFor##themename, \ + #themename, themedesc) #endif // _WX_UNIV_THEME_H_ diff --git a/samples/univ/open.bmp b/samples/univ/open.bmp new file mode 100644 index 0000000000..1e3ffac41d Binary files /dev/null and b/samples/univ/open.bmp differ diff --git a/samples/univ/tip.bmp b/samples/univ/tip.bmp new file mode 100644 index 0000000000..db64212f0e Binary files /dev/null and b/samples/univ/tip.bmp differ diff --git a/samples/univ/univ.cpp b/samples/univ/univ.cpp index 2baec4b40e..98d42e09a0 100644 --- a/samples/univ/univ.cpp +++ b/samples/univ/univ.cpp @@ -37,17 +37,20 @@ #include "wx/bmpbuttn.h" #include "wx/button.h" #include "wx/scrolbar.h" - #include "wx/statbmp.h" #include "wx/statbox.h" - #include "wx/statline.h" #include "wx/stattext.h" #endif +#include "wx/statbmp.h" +#include "wx/statline.h" + +#include "wx/univ/theme.h" + // ---------------------------------------------------------------------------- // resources // ---------------------------------------------------------------------------- -#include "wx/generic/tip.xpm" +#include "tip.xpm" #include "open.xpm" // ---------------------------------------------------------------------------- @@ -72,10 +75,20 @@ public: // override base class virtuals // ---------------------------- + // this method is called when wxWindows is initializing and should be used + // for the earliest initialization possible + virtual bool OnInitGui(); + // this one is called on application startup and is a good place for the app // initialization (doing it here and not in the ctor allows to have an error // return: if OnInit() returns false, the application terminates) virtual bool OnInit(); + + // get the standard bg colour + const wxColour& GetBgColour() const { return m_colourBg; } + +protected: + wxColour m_colourBg; }; // Define a new frame type: this is going to be our main frame @@ -115,6 +128,28 @@ END_EVENT_TABLE() // app class // ---------------------------------------------------------------------------- +bool MyUnivApp::OnInitGui() +{ + m_colourBg = *wxLIGHT_GREY; + + if ( argc > 1 ) + { + wxString themeName = argv[1]; + wxTheme *theme = wxTheme::Create(themeName); + if ( theme ) + { + // HACK: this will be done by wxTheme itself later, but for now + // manually use the right colours + if ( themeName == _T("gtk") ) + m_colourBg = wxColour(0xd6d6d6); + + wxTheme::Set(theme); + } + } + + return wxApp::OnInitGui(); +} + bool MyUnivApp::OnInit() { wxFrame *frame = new MyUnivFrame(_T("wxUniversal demo")); @@ -130,11 +165,7 @@ bool MyUnivApp::OnInit() MyUnivFrame::MyUnivFrame(const wxString& title) : wxFrame(NULL, -1, title, wxDefaultPosition, wxSize(600, 600)) { -#ifdef __WXMSW__ - SetBackgroundColour(*wxLIGHT_GREY); -#else - SetBackgroundColour(0xd6d6d6); -#endif + SetBackgroundColour(wxGetApp().GetBgColour()); wxStaticText *text; @@ -173,7 +204,7 @@ MyUnivFrame::MyUnivFrame(const wxString& title) wxPoint(10, 150), wxSize(500, 120)); box->SetForegroundColour(*wxRED); - box->SetBackground(wxBitmap("bricks.bmp", wxBITMAP_TYPE_BMP), 0, wxTILE); + box->SetBackground(wxBITMAP(bricks), 0, wxTILE); x = 15; #define CREATE_STATIC_ALIGN_DEMO(align) \ @@ -194,8 +225,8 @@ MyUnivFrame::MyUnivFrame(const wxString& title) new wxButton(this, Univ_Button1, _T("&Press me"), wxPoint(10, 300)); new wxButton(this, Univ_Button2, _T("&And me"), wxPoint(100, 300)); - new wxStaticBitmap(this, wxBitmap(tipIcon), wxPoint(10, 350)); - new wxStaticBitmap(this, -1, wxBitmap(tipIcon), wxPoint(50, 350), + new wxStaticBitmap(this, wxBITMAP(tip), wxPoint(10, 350)); + new wxStaticBitmap(this, -1, wxBITMAP(tip), wxPoint(50, 350), wxDefaultSize, wxSUNKEN_BORDER); wxScrollBar *sb; @@ -204,7 +235,7 @@ MyUnivFrame::MyUnivFrame(const wxString& title) sb = new wxScrollBar(this, -1, wxPoint(200, 330), wxSize(-1, 150), wxSB_VERTICAL); sb->SetScrollbar(50, 50, 100, 10); - new wxButton(this, -1, wxBitmap(open_xpm), _T("&Open..."), wxPoint(10, 420)); + new wxButton(this, -1, wxBITMAP(open), _T("&Open..."), wxPoint(10, 420)); wxBitmap bmp1(wxTheApp->GetStdIcon(wxICON_INFORMATION)), bmp2(wxTheApp->GetStdIcon(wxICON_WARNING)), diff --git a/src/common/dcbase.cpp b/src/common/dcbase.cpp index bb79e97b6d..f1f40bcea6 100644 --- a/src/common/dcbase.cpp +++ b/src/common/dcbase.cpp @@ -227,14 +227,26 @@ void wxDCBase::GetMultiLineTextExtent(const wxString& text, } void wxDCBase::DrawLabel(const wxString& text, + const wxBitmap& bitmap, const wxRect& rect, int alignment, int indexAccel, wxRect *rectBounding) { // find the text position - wxCoord width, height, heightLine; - GetMultiLineTextExtent(text, &width, &height, &heightLine); + wxCoord width, heightText, heightLine; + GetMultiLineTextExtent(text, &width, &heightText, &heightLine); + + wxCoord height; + if ( bitmap.Ok() ) + { + width += bitmap.GetWidth(); + height = bitmap.GetHeight(); + } + else + { + height = heightText; + } wxCoord x, y; if ( alignment & wxALIGN_RIGHT ) @@ -243,7 +255,7 @@ void wxDCBase::DrawLabel(const wxString& text, } else if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) { - x = (rect.GetLeft() + rect.GetRight() - width) / 2; + x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2; } else // alignment & wxALIGN_LEFT { @@ -256,14 +268,22 @@ void wxDCBase::DrawLabel(const wxString& text, } else if ( alignment & wxALIGN_CENTRE_VERTICAL ) { - y = (rect.GetTop() + rect.GetBottom() - height) / 2; + y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2; } else // alignment & wxALIGN_TOP { y = rect.GetTop(); } - // we will darw the underscore under the accel char later + // draw the bitmap first + if ( bitmap.Ok() ) + { + DrawBitmap(bitmap, x, y, TRUE /* use mask */); + x += bitmap.GetWidth() + 4; + y += (height - heightText) / 2; + } + + // we will draw the underscore under the accel char later wxCoord startUnderscore = 0, endUnderscore = 0, yUnderscore = 0; diff --git a/src/univ/bmpbuttn.cpp b/src/univ/bmpbuttn.cpp index 7698bddd72..7ac4604ffd 100644 --- a/src/univ/bmpbuttn.cpp +++ b/src/univ/bmpbuttn.cpp @@ -41,7 +41,7 @@ // implementation // ============================================================================ -IMPLEMENT_DYNAMIC_CLASS(wxBitmapButton, wxControl) +IMPLEMENT_DYNAMIC_CLASS(wxBitmapButton, wxButton) BEGIN_EVENT_TABLE(wxBitmapButton, wxButton) EVT_SET_FOCUS(wxBitmapButton::OnSetFocus) @@ -126,7 +126,7 @@ void wxBitmapButton::Press() void wxBitmapButton::Release() { - ChangeBitmap(m_bmpNormal); + ChangeBitmap(IsFocused() ? m_bmpFocus : m_bmpNormal); wxButton::Release(); } diff --git a/src/univ/button.cpp b/src/univ/button.cpp index aadcbde566..eff9ab78b4 100644 --- a/src/univ/button.cpp +++ b/src/univ/button.cpp @@ -44,8 +44,8 @@ // ---------------------------------------------------------------------------- // default margins around the image -static const wxCoord DEFAULT_BTN_MARGIN_X = 6; -static const wxCoord DEFAULT_BTN_MARGIN_Y = 3; +static const wxCoord DEFAULT_BTN_MARGIN_X = 0; +static const wxCoord DEFAULT_BTN_MARGIN_Y = 0; // ============================================================================ // implementation @@ -76,18 +76,7 @@ bool wxButton::Create(wxWindow *parent, // center label by default if ( !(style & wxALIGN_MASK) ) { - style |= wxALIGN_CENTRE_VERTICAL; - - // normally, buttons are centered, but it looks better to put them - // near the image for the buttons which have one - if ( bitmap.Ok() ) - { - style |= wxALIGN_LEFT; - } - else - { - style |= wxALIGN_CENTRE_HORIZONTAL; - } + style |= wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL; } if ( !wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name) ) diff --git a/src/univ/control.cpp b/src/univ/control.cpp index b747e71a7e..5419a3fd96 100644 --- a/src/univ/control.cpp +++ b/src/univ/control.cpp @@ -278,8 +278,8 @@ void wxControl::DoDraw(wxControlRenderer *renderer) void wxControl::OnFocus(wxFocusEvent& event) { - // do nothing here for now... - event.Skip(); + if ( m_handler->OnFocus(this, event) ) + Refresh(); } // ---------------------------------------------------------------------------- @@ -338,13 +338,6 @@ void wxControl::PerformActions(const wxControlActions& actions, bool wxControl::PerformAction(const wxControlAction& action, const wxEvent& event) { - if ( (action == wxACTION_FOCUS) && AcceptsFocus() ) - { - SetFocus(); - - return TRUE; - } - return FALSE; } diff --git a/src/univ/inphand.cpp b/src/univ/inphand.cpp index 9f0571aef8..6693f04c18 100644 --- a/src/univ/inphand.cpp +++ b/src/univ/inphand.cpp @@ -47,16 +47,18 @@ class wxScrollBarTimer : public wxTimer { public: - wxScrollBarTimer(const wxControlAction& action, + wxScrollBarTimer(wxStdScrollBarInputHandler *handler, + const wxControlAction& action, const wxMouseEvent& event, - wxControl *control); + wxScrollBar *control); virtual void Notify(); private: + wxStdScrollBarInputHandler *m_handler; wxControlAction m_action; wxMouseEvent m_event; - wxControl *m_control; + wxScrollBar *m_control; }; // ============================================================================ @@ -67,11 +69,13 @@ private: // wxScrollBarTimer // ---------------------------------------------------------------------------- -wxScrollBarTimer::wxScrollBarTimer(const wxControlAction& action, +wxScrollBarTimer::wxScrollBarTimer(wxStdScrollBarInputHandler *handler, + const wxControlAction& action, const wxMouseEvent& event, - wxControl *control) + wxScrollBar *control) : m_event(event) { + m_handler = handler; m_action = action; m_control = control; @@ -79,21 +83,16 @@ wxScrollBarTimer::wxScrollBarTimer(const wxControlAction& action, Notify(); // and continue it later - Start(100); // FIXME make this delay configurable + Start(50); // FIXME make this delay configurable } void wxScrollBarTimer::Notify() { - if ( m_control->PerformAction(m_action, m_event) ) + if ( m_handler->OnScrollTimer(m_control, m_action, m_event) ) { // keep scrolling m_control->Refresh(); } - else - { - // we scrolled till the end - Stop(); - } } // ---------------------------------------------------------------------------- @@ -106,6 +105,11 @@ bool wxInputHandler::OnMouseMove(wxControl * WXUNUSED(control), return FALSE; } +bool wxInputHandler::OnFocus(wxControl *control, const wxFocusEvent& event) +{ + return FALSE; +} + wxInputHandler::~wxInputHandler() { } @@ -214,6 +218,13 @@ bool wxStdButtonInputHandler::OnMouseMove(wxControl *control, return wxStdInputHandler::OnMouseMove(control, event); } +bool wxStdButtonInputHandler::OnFocus(wxControl *control, + const wxFocusEvent& event) +{ + // buttons chaneg appearance when they get/lose focus + return TRUE; +} + // ---------------------------------------------------------------------------- // wxStdScrollBarInputHandler // ---------------------------------------------------------------------------- @@ -253,6 +264,40 @@ void wxStdScrollBarInputHandler::SetElementState(wxScrollBar *control, } } +bool wxStdScrollBarInputHandler::OnScrollTimer(wxScrollBar *scrollbar, + const wxControlAction& action, + const wxMouseEvent& event) +{ + if ( scrollbar->PerformAction(action, event) ) + return TRUE; + + // we scrolled till the end + m_timerScroll->Stop(); + + return FALSE; +} + +void wxStdScrollBarInputHandler::StopScrolling(wxScrollBar *control) +{ + // return everything to the normal state + if ( m_winCapture ) + { + m_winCapture->ReleaseMouse(); + m_winCapture = NULL; + } + + m_btnCapture = -1; + + if ( m_timerScroll ) + { + delete m_timerScroll; + m_timerScroll = NULL; + } + + // unpress the arrow and highlight the current element + Press(control, FALSE); +} + wxControlActions wxStdScrollBarInputHandler::Map(wxControl *control, const wxKeyEvent& event, bool pressed) @@ -307,7 +352,7 @@ wxControlActions wxStdScrollBarInputHandler::Map(wxControl *control, // 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 ( event.ButtonDown() || event.ButtonDClick() ) { if ( !m_winCapture ) { @@ -330,10 +375,12 @@ wxControlActions wxStdScrollBarInputHandler::Map(wxControl *control, case wxHT_SCROLLBAR_BAR_1: action = wxACTION_SCROLL_PAGE_UP; + m_ptStartScrolling = event.GetPosition(); break; case wxHT_SCROLLBAR_BAR_2: action = wxACTION_SCROLL_PAGE_DOWN; + m_ptStartScrolling = event.GetPosition(); break; case wxHT_SCROLLBAR_THUMB: @@ -357,7 +404,10 @@ wxControlActions wxStdScrollBarInputHandler::Map(wxControl *control, // start dragging if ( hasAction ) { - m_timerScroll = new wxScrollBarTimer(action, event, control); + m_timerScroll = new wxScrollBarTimer(this, + action, + event, + scrollbar); } else // no (immediate) action { @@ -373,25 +423,14 @@ wxControlActions wxStdScrollBarInputHandler::Map(wxControl *control, { if ( m_winCapture ) { - // return everything to the normal state - m_winCapture->ReleaseMouse(); - m_winCapture = NULL; - m_btnCapture = -1; - - if ( m_timerScroll ) - { - delete m_timerScroll; - m_timerScroll = NULL; - } + StopScrolling(scrollbar); // if we were dragging the thumb, send the last event if ( m_htLast == wxHT_SCROLLBAR_THUMB ) { - control->PerformAction(wxACTION_SCROLL_THUMB_RELEASE, event); + scrollbar->PerformAction(wxACTION_SCROLL_THUMB_RELEASE, event); } - // unpress the arrow and highlight the current element - Press(scrollbar, FALSE); m_htLast = ht; Highlight(scrollbar, TRUE); @@ -454,6 +493,11 @@ bool wxStdScrollBarInputHandler::OnMouseMove(wxControl *control, Highlight(scrollbar, FALSE); m_htLast = wxHT_NOWHERE; } + else + { + // don't refresh + return FALSE; + } // highlighting changed return TRUE; diff --git a/src/univ/renderer.cpp b/src/univ/renderer.cpp index 8120fa1ef7..81ed774cca 100644 --- a/src/univ/renderer.cpp +++ b/src/univ/renderer.cpp @@ -78,7 +78,8 @@ wxCoord wxRenderer::StandardScrollbarToPixel(const wxScrollBar *scrollbar, } return ( scrollbar->GetThumbPosition() * - StandardScrollBarSize(scrollbar, sizeArrow) ) / range; + StandardScrollBarSize(scrollbar, sizeArrow) ) / range + + (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x); } /* static */ @@ -86,8 +87,9 @@ int wxRenderer::StandardPixelToScrollbar(const wxScrollBar *scrollbar, wxCoord coord, const wxSize& sizeArrow) { - return ( coord * scrollbar->GetRange() ) - / StandardScrollBarSize(scrollbar, sizeArrow); + return ( (coord - (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x)) * + scrollbar->GetRange() ) / + StandardScrollBarSize(scrollbar, sizeArrow); } /* static */ @@ -95,24 +97,36 @@ wxHitTest wxRenderer::StandardHitTestScrollbar(const wxScrollBar *scrollbar, const wxPoint& pt, const wxSize& sizeArrowSB) { - // we only need to work with tiehr x or y coord depending on the - // orientation, choose one + // we only need to work with either x or y coord depending on the + // orientation, choose one (but still check the other one to verify if the + // mouse is in the window at all) wxCoord coord, sizeArrow, sizeTotal; + wxSize size = scrollbar->GetSize(); if ( scrollbar->GetWindowStyle() & wxVERTICAL ) { + if ( pt.x < 0 || pt.x > size.x ) + return wxHT_NOWHERE; + coord = pt.y; sizeArrow = sizeArrowSB.y; - sizeTotal = scrollbar->GetSize().y; + sizeTotal = size.y; } else // horizontal { + if ( pt.y < 0 || pt.y > size.y ) + return wxHT_NOWHERE; + coord = pt.x; sizeArrow = sizeArrowSB.x; - sizeTotal = scrollbar->GetSize().x; + sizeTotal = size.x; } // test for the arrows first as it's faster - if ( coord < sizeArrow ) + if ( coord < 0 || coord > sizeTotal ) + { + return wxHT_NOWHERE; + } + else if ( coord < sizeArrow ) { return wxHT_SCROLLBAR_ARROW_LINE_1; } @@ -192,28 +206,18 @@ void wxControlRenderer::DrawLabel(const wxBitmap& bitmap, m_dc.SetFont(m_ctrl->GetFont()); m_dc.SetTextForeground(m_ctrl->GetForegroundColour()); - wxRect rectLabel = m_rect; - if ( bitmap.Ok() ) - { - wxRect rectBmp; - int width = bitmap.GetWidth(); - rectBmp.x = m_rect.x + marginX; - rectBmp.y = m_rect.y + marginY; - rectBmp.width = width; - rectBmp.height = m_rect.height - marginY; - - DrawBitmap(bitmap, rectBmp, wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL); - - width += 2*marginX; - rectLabel.x += width; - rectLabel.width -= width; - } - wxString label = m_ctrl->GetLabel(); - if ( !label.empty() ) + if ( !label.empty() || bitmap.Ok() ) { + wxRect rectLabel = m_rect; + if ( bitmap.Ok() ) + { + rectLabel.Inflate(-marginX, -marginY); + } + m_renderer->DrawLabel(m_dc, label, + bitmap, rectLabel, m_ctrl->GetStateFlags(), m_ctrl->GetAlignment(), diff --git a/src/univ/statline.cpp b/src/univ/statline.cpp index 4cdd84a6c5..fa592a0dbd 100644 --- a/src/univ/statline.cpp +++ b/src/univ/statline.cpp @@ -31,10 +31,11 @@ #ifndef WX_PRECOMP #include "wx/dc.h" - #include "wx/statline.h" #include "wx/validate.h" #endif +#include "wx/statline.h" + #include "wx/univ/renderer.h" // ============================================================================ diff --git a/src/univ/theme.cpp b/src/univ/theme.cpp index 6d7be99f04..71d37bec50 100644 --- a/src/univ/theme.cpp +++ b/src/univ/theme.cpp @@ -41,21 +41,21 @@ // implementation // ============================================================================ -wxTheme::wxThemeInfo *wxTheme::ms_allThemes = (wxTheme::wxThemeInfo *)NULL; +wxThemeInfo *wxTheme::ms_allThemes = (wxThemeInfo *)NULL; wxTheme *wxTheme::ms_theme = (wxTheme *)NULL; // ---------------------------------------------------------------------------- // "dynamic" theme creation // ---------------------------------------------------------------------------- -wxTheme::wxThemeInfo::wxThemeInfo(wxTheme::Constructor c, - const wxChar *n, - const wxChar *d) - : name(n), desc(d), ctor(c) +wxThemeInfo::wxThemeInfo(wxThemeInfo::Constructor c, + const wxChar *n, + const wxChar *d) + : name(n), desc(d), ctor(c) { // insert us (in the head of) the linked list - next = ms_allThemes; - ms_allThemes = this; + next = wxTheme::ms_allThemes; + wxTheme::ms_allThemes = this; } /* static */ wxTheme *wxTheme::Create(const wxString& name) @@ -81,7 +81,11 @@ wxTheme::wxThemeInfo::wxThemeInfo(wxTheme::Constructor c, /* static */ bool wxTheme::CreateDefault() { - wxCHECK_MSG( !ms_theme, TRUE, _T("we already have a theme") ); + if ( ms_theme ) + { + // we already have a theme + return TRUE; + } #if defined(__WXMSW__) ms_theme = Create(_T("win32")); diff --git a/src/univ/themes/gtk.cpp b/src/univ/themes/gtk.cpp index 85487d6355..853392d709 100644 --- a/src/univ/themes/gtk.cpp +++ b/src/univ/themes/gtk.cpp @@ -57,10 +57,12 @@ public: int flags = 0); virtual void DrawLabel(wxDC& dc, const wxString& label, + const wxBitmap& image, const wxRect& rect, int flags = 0, int alignment = wxALIGN_LEFT | wxALIGN_TOP, - int indexAccel = -1); + int indexAccel = -1, + wxRect *rectBounds = NULL); virtual void DrawBorder(wxDC& dc, wxBorder border, const wxRect& rect, @@ -175,7 +177,6 @@ public: : wxStdScrollBarInputHandler(renderer, handler) { } protected: - virtual bool OnMouseLeave() { return FALSE; } virtual bool IsAllowedButton(int WXUNUSED(button)) { return TRUE; } }; @@ -247,8 +248,6 @@ wxInputHandler *wxGTKTheme::GetInputHandler(const wxString& control) if ( n == wxNOT_FOUND ) { // create a new handler - n = m_handlerNames.Add(control); - if ( control.Matches(_T("wx*Button")) ) handler = new wxStdButtonInputHandler(GetInputHandler(_T("wxControl"))); else if ( control == _T("wxScrollBar") ) @@ -257,6 +256,7 @@ wxInputHandler *wxGTKTheme::GetInputHandler(const wxString& control) else handler = new wxGTKInputHandler(m_renderer); + n = m_handlerNames.Add(control); m_handlers.Insert(handler, n); } else // we already have it @@ -553,7 +553,8 @@ void wxGTKRenderer::DrawFrame(wxDC& dc, rectText.height = height; dc.SetBackgroundMode(wxSOLID); - DrawLabel(dc, label, rectText, flags, alignment, indexAccel); + DrawLabel(dc, label, wxNullBitmap, rectText, + flags, alignment, indexAccel); dc.SetBackgroundMode(wxTRANSPARENT); // GTK+ does this - don't know if this is intentional or not @@ -568,11 +569,13 @@ void wxGTKRenderer::DrawFrame(wxDC& dc, // ---------------------------------------------------------------------------- void wxGTKRenderer::DrawLabel(wxDC& dc, - const wxString& label, - const wxRect& rect, - int flags, - int alignment, - int indexAccel) + const wxString& label, + const wxBitmap& image, + const wxRect& rect, + int flags, + int alignment, + int indexAccel, + wxRect *rectBounds) { if ( flags & wxCONTROL_DISABLED ) { @@ -585,7 +588,7 @@ void wxGTKRenderer::DrawLabel(wxDC& dc, dc.SetTextForeground(0x7f7f7f); } - dc.DrawLabel(label, rect, alignment, indexAccel); + dc.DrawLabel(label, image, rect, alignment, indexAccel, rectBounds); } // ---------------------------------------------------------------------------- @@ -971,7 +974,7 @@ wxControlActions wxGTKInputHandler::Map(wxControl *control, // clicking on the control gives it focus if ( event.ButtonDown() ) { - return wxACTION_FOCUS; + control->SetFocus(); } return wxACTION_NONE; diff --git a/src/univ/themes/win32.cpp b/src/univ/themes/win32.cpp index ec20b897e5..546aa74f20 100644 --- a/src/univ/themes/win32.cpp +++ b/src/univ/themes/win32.cpp @@ -74,10 +74,12 @@ public: int flags = 0); virtual void DrawLabel(wxDC& dc, const wxString& label, + const wxBitmap& image, const wxRect& rect, int flags = 0, int alignment = wxALIGN_LEFT | wxALIGN_TOP, - int indexAccel = -1); + int indexAccel = -1, + wxRect *rectBounds = NULL); virtual void DrawBorder(wxDC& dc, wxBorder border, const wxRect& rect, @@ -193,22 +195,27 @@ class wxWin32ScrollBarInputHandler : public wxStdScrollBarInputHandler { public: wxWin32ScrollBarInputHandler(wxWin32Renderer *renderer, - wxInputHandler *handler) - : wxStdScrollBarInputHandler(renderer, handler) { } + wxInputHandler *handler); - // we don't highlight scrollbar elements, so there is no need to process - // mouse move events - virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event) - { - if ( event.Moving() ) - return FALSE; + virtual wxControlActions Map(wxControl *control, const wxMouseEvent& event); + virtual bool OnMouseMove(wxControl *control, const wxMouseEvent& event); - return wxStdScrollBarInputHandler::OnMouseMove(control, event); - } + virtual bool OnScrollTimer(wxScrollBar *scrollbar, + const wxControlAction& action, + const wxMouseEvent& event); protected: - virtual bool OnMouseLeave() { return TRUE; } virtual bool IsAllowedButton(int button) { return button == 1; } + + // the first and last event which caused the thumb to move + wxMouseEvent m_eventStartDrag, + m_eventLastDrag; + + // have we paused the scrolling because the mouse moved? + bool m_scrollPaused; + + // we remember the interval of the timer to be able to restart it + int m_interval; }; // ---------------------------------------------------------------------------- @@ -281,8 +288,6 @@ wxInputHandler *wxWin32Theme::GetInputHandler(const wxString& control) if ( n == wxNOT_FOUND ) { // create a new handler - n = m_handlerNames.Add(control); - if ( control.Matches(_T("wx*Button")) ) handler = new wxStdButtonInputHandler(GetInputHandler(_T("wxControl"))); else if ( control == _T("wxScrollBar") ) @@ -291,6 +296,7 @@ wxInputHandler *wxWin32Theme::GetInputHandler(const wxString& control) else handler = new wxWin32InputHandler(m_renderer); + n = m_handlerNames.Add(control); m_handlers.Insert(handler, n); } else // we already have it @@ -770,15 +776,12 @@ void wxWin32Renderer::DrawFrame(wxDC& dc, dc.GetTextExtent(label, NULL, &height); rectFrame.y += height / 2; rectFrame.height -= height / 2; - } - // draw the frame - DrawShadedRect(dc, &rectFrame, m_penDarkGrey, m_penHighlight); - DrawShadedRect(dc, &rectFrame, m_penHighlight, m_penDarkGrey); + // we have to draw each part of the frame individually as we can't + // erase the background beyond the label as it might contain some + // pixmap already, so drawing everything and then overwriting part of + // the frame with label doesn't work - // and overwrite it with label (if any) - if ( !label.empty() ) - { // TODO: the +5 and space insertion should be customizable wxRect rectText; @@ -795,9 +798,29 @@ void wxWin32Renderer::DrawFrame(wxDC& dc, indexAccel++; } - dc.SetBackgroundMode(wxSOLID); - DrawLabel(dc, label2, rectText, flags, alignment, indexAccel); - dc.SetBackgroundMode(wxTRANSPARENT); + wxRect rectLabel; + DrawLabel(dc, label2, wxNullBitmap, + rectText, flags, alignment, indexAccel, &rectLabel); + + // draw left, bottom and right lines entirely + DrawVerticalLine(dc, rectFrame.GetLeft(), + rectFrame.GetTop(), rectFrame.GetBottom() - 2); + DrawHorizontalLine(dc, rectFrame.GetBottom() - 1, + rectFrame.GetLeft(), rectFrame.GetRight()); + DrawVerticalLine(dc, rectFrame.GetRight() - 1, + rectFrame.GetTop(), rectFrame.GetBottom() - 1); + + // and 2 parts of the top line + DrawHorizontalLine(dc, rectFrame.GetTop(), + rectFrame.GetLeft() + 1, rectLabel.GetLeft()); + DrawHorizontalLine(dc, rectFrame.GetTop(), + rectLabel.GetRight(), rectFrame.GetRight() - 2); + } + else + { + // just draw the complete frame + DrawShadedRect(dc, &rectFrame, m_penDarkGrey, m_penHighlight); + DrawShadedRect(dc, &rectFrame, m_penHighlight, m_penDarkGrey); } } @@ -807,10 +830,12 @@ void wxWin32Renderer::DrawFrame(wxDC& dc, void wxWin32Renderer::DrawLabel(wxDC& dc, const wxString& label, + const wxBitmap& image, const wxRect& rect, int flags, int alignment, - int indexAccel) + int indexAccel, + wxRect *rectBounds) { // shift the label if a button is pressed wxRect rectLabel = rect; @@ -822,7 +847,7 @@ void wxWin32Renderer::DrawLabel(wxDC& dc, if ( flags & wxCONTROL_DISABLED ) { - // make the text grey and draw a shade for it + // make the text grey and draw a shadow of it dc.SetTextForeground(m_colHighlight); wxRect rectShadow = rectLabel; rectShadow.x++; @@ -831,13 +856,14 @@ void wxWin32Renderer::DrawLabel(wxDC& dc, dc.SetTextForeground(m_colDarkGrey); } + // leave enough space for the focus rectangle wxRect rectText = rectLabel; if ( flags & wxCONTROL_FOCUSED ) { rectText.Inflate(-2); } - dc.DrawLabel(label, rectText, alignment, indexAccel); + dc.DrawLabel(label, image, rectText, alignment, indexAccel, rectBounds); if ( flags & wxCONTROL_FOCUSED ) { @@ -1111,7 +1137,11 @@ void wxWin32Renderer::AdjustSize(wxSize *size, const wxWindow *window) { // TODO size->x += 3*window->GetCharWidth(); - size->y = (11*(window->GetCharHeight() + 8))/10; + wxCoord heightBtn = (11*(window->GetCharHeight() + 8))/10; + if ( size->y < heightBtn - 8 ) + size->y = heightBtn; + else + size->y += 9; } else { @@ -1172,3 +1202,173 @@ wxControlActions wxWin32InputHandler::Map(wxControl *control, { return wxACTION_NONE; } + +// ---------------------------------------------------------------------------- +// wxWin32ScrollBarInputHandler +// ---------------------------------------------------------------------------- + +wxWin32ScrollBarInputHandler:: +wxWin32ScrollBarInputHandler(wxWin32Renderer *renderer, + wxInputHandler *handler) + : wxStdScrollBarInputHandler(renderer, handler) +{ + m_scrollPaused = FALSE; + m_interval = 0; +} + +bool wxWin32ScrollBarInputHandler::OnScrollTimer(wxScrollBar *scrollbar, + const wxControlAction& action, + const wxMouseEvent& event) +{ + // stop if went beyond the position of the original click (this can only + // happen when we scroll by pages) + bool stop = FALSE; + if ( action == wxACTION_SCROLL_PAGE_DOWN ) + { + stop = m_renderer->HitTestScrollbar(scrollbar, m_ptStartScrolling) + != wxHT_SCROLLBAR_BAR_2; + } + else if ( action == wxACTION_SCROLL_PAGE_UP ) + { + stop = m_renderer->HitTestScrollbar(scrollbar, m_ptStartScrolling) + != wxHT_SCROLLBAR_BAR_1; + } + + if ( stop ) + { + StopScrolling(scrollbar); + + scrollbar->Refresh(); + + return FALSE; + } + + return wxStdScrollBarInputHandler::OnScrollTimer(scrollbar, + action, + event); +} + +wxControlActions wxWin32ScrollBarInputHandler::Map(wxControl *control, + const wxMouseEvent& event) +{ + // remember the current state + bool wasDraggingThumb = m_htLast == wxHT_SCROLLBAR_THUMB; + + // do process the message + wxControlActions actions = wxStdScrollBarInputHandler::Map(control, event); + + // analyse the changes + if ( !wasDraggingThumb && (m_htLast == wxHT_SCROLLBAR_THUMB) ) + { + // we just started dragging the thumb, remember its initial position to + // be able to restore it if the drag is cancelled later + m_eventStartDrag = event; + } + + return actions; +} + +bool wxWin32ScrollBarInputHandler::OnMouseMove(wxControl *control, + const wxMouseEvent& event) +{ + // we don't highlight scrollbar elements, so there is no need to process + // mouse move events normally - only do it while mouse is captured (i.e. + // when we're dragging the thumb or pressing on something) + if ( !m_winCapture ) + return FALSE; + + if ( event.Entering() ) + { + // we're not interested in this at all + return FALSE; + } + + wxScrollBar *scrollbar = wxStaticCast(control, wxScrollBar); + wxHitTest ht; + if ( m_scrollPaused ) + { + // check if the mouse returned to its original location + + if ( event.Leaving() ) + { + // it surely didn't + return FALSE; + } + + ht = m_renderer->HitTestScrollbar(scrollbar, event.GetPosition()); + if ( ht == m_htLast ) + { + // yes it did, resume scrolling + m_scrollPaused = FALSE; + if ( m_timerScroll ) + { + // we were scrolling by line/page, restart timer + m_timerScroll->Start(m_interval); + + Press(scrollbar, TRUE); + } + else // we were dragging the thumb + { + // restore its last location + scrollbar->PerformAction(wxACTION_SCROLL_THUMB_MOVE, + m_eventLastDrag); + } + + return TRUE; + } + } + else // normal case, scrolling hasn't been paused + { + // if we're scrolling the scrollbar because the arrow or the shaft was + // pressed, check that the mouse stays on the same scrollbar element + + if ( event.Moving() ) + { + ht = m_renderer->HitTestScrollbar(scrollbar, event.GetPosition()); + } + else // event.Leaving() + { + ht = wxHT_NOWHERE; + } + + // if we're dragging the thumb and the mouse stays in the scrollbar, it + // is still ok - we only want to catch the case when the mouse leaves + // the scrollbar here + if ( m_htLast == wxHT_SCROLLBAR_THUMB && ht != wxHT_NOWHERE ) + { + ht = wxHT_SCROLLBAR_THUMB; + } + + if ( ht != m_htLast ) + { + // what were we doing? 2 possibilities: either an arrow/shaft was + // pressed in which case we have a timer and so we just stop it or + // we were dragging the thumb + if ( m_timerScroll ) + { + // pause scrolling + m_interval = m_timerScroll->GetInterval(); + m_timerScroll->Stop(); + m_scrollPaused = TRUE; + + // unpress the arrow + Press(scrollbar, FALSE); + } + else // we were dragging the thumb + { + // remember the current thumb position to be able to restore it + // if the mouse returns to it later + m_eventLastDrag = event; + + // and restore the original position (before dragging) of the + // thumb for now + scrollbar->PerformAction(wxACTION_SCROLL_THUMB_MOVE, + m_eventStartDrag); + } + + return TRUE; + } + } + + return wxStdScrollBarInputHandler::OnMouseMove(control, event); +}