From 1338c59a025505bc066be220fe56e898a72b3ad3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= Date: Wed, 4 Jun 2003 18:17:04 +0000 Subject: [PATCH] added selecting-while-dragging git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@20922 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/html/htmlcell.h | 18 ++- include/wx/html/htmlwin.h | 20 +++- src/html/htmlcell.cpp | 21 +++- src/html/htmlwin.cpp | 228 ++++++++++++++++++++++++++++++++++--- 4 files changed, 253 insertions(+), 34 deletions(-) diff --git a/include/wx/html/htmlcell.h b/include/wx/html/htmlcell.h index 312e334c99..11066eb8d8 100644 --- a/include/wx/html/htmlcell.h +++ b/include/wx/html/htmlcell.h @@ -41,9 +41,9 @@ public: m_fromPrivPos(wxDefaultPosition), m_toPrivPos(wxDefaultPosition), m_fromCell(NULL), m_toCell(NULL) {} - void Set(const wxPoint& fromPos, wxHtmlCell *fromCell, - const wxPoint& toPos, wxHtmlCell *toCell); - void Set(wxHtmlCell *fromCell, wxHtmlCell *toCell); + void Set(const wxPoint& fromPos, const wxHtmlCell *fromCell, + const wxPoint& toPos, const wxHtmlCell *toCell); + void Set(const wxHtmlCell *fromCell, const wxHtmlCell *toCell); const wxHtmlCell *GetFromCell() const { return m_fromCell; } const wxHtmlCell *GetToCell() const { return m_toCell; } @@ -57,6 +57,7 @@ public: const wxPoint& GetToPrivPos() const { return m_toPrivPos; } void SetFromPrivPos(const wxPoint& pos) { m_fromPrivPos = pos; } void SetToPrivPos(const wxPoint& pos) { m_toPrivPos = pos; } + void ClearPrivPos() { m_toPrivPos = m_fromPrivPos = wxDefaultPosition; } const bool IsEmpty() const { return m_fromPos == wxDefaultPosition && @@ -65,7 +66,7 @@ public: private: wxPoint m_fromPos, m_toPos; wxPoint m_fromPrivPos, m_toPrivPos; - wxHtmlCell *m_fromCell, *m_toCell; + const wxHtmlCell *m_fromCell, *m_toCell; }; @@ -144,7 +145,7 @@ enum { wxHTML_FIND_EXACT = 1, wxHTML_FIND_NEAREST_BEFORE = 2, - wxHTML_FIND_NEAREST_AFTER = 4, + wxHTML_FIND_NEAREST_AFTER = 4 }; @@ -283,10 +284,7 @@ public: // cells (= as they are read). If cell A is (grand)parent of cell B, // then both A.IsBefore(B) and B.IsBefore(A) always return true. bool IsBefore(wxHtmlCell *cell) const; - - // Sets cell's private position values in wxHtmlSelection - virtual void SetSelectionPrivPos(wxDC& dc, wxHtmlSelection *s) const {} - + // Converts the cell into text representation. If sel != NULL then // only part of the cell inside the selection is converted. virtual wxString ConvertToText(wxHtmlSelection *WXUNUSED(sel)) const @@ -332,9 +330,9 @@ public: void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2, wxHtmlRenderingInfo& info); wxString ConvertToText(wxHtmlSelection *sel) const; - void SetSelectionPrivPos(wxDC& dc, wxHtmlSelection *s) const; protected: + void SetSelectionPrivPos(wxDC& dc, wxHtmlSelection *s) const; void Split(wxDC& dc, const wxPoint& selFrom, const wxPoint& selTo, unsigned& pos1, unsigned& pos2) const; diff --git a/include/wx/html/htmlwin.h b/include/wx/html/htmlwin.h index 6b1f0dd6a0..6a4e2fdf2e 100644 --- a/include/wx/html/htmlwin.h +++ b/include/wx/html/htmlwin.h @@ -32,6 +32,7 @@ class wxHtmlProcessor; class wxHtmlWinModule; class wxHtmlHistoryArray; class wxHtmlProcessorList; +class WXDLLEXPORT wxHtmlWinAutoScrollTimer; // wxHtmlWindow flags: @@ -207,7 +208,8 @@ protected: // actual size of window. This method also setup scrollbars void CreateLayout(); - void OnDraw(wxDC& dc); + void OnEraseBackground(wxEraseEvent& event); + void OnPaint(wxPaintEvent& event); void OnSize(wxSizeEvent& event); void OnMouseMove(wxMouseEvent& event); void OnMouseDown(wxMouseEvent& event); @@ -216,6 +218,8 @@ protected: #if wxUSE_CLIPBOARD void OnKeyUp(wxKeyEvent& event); void OnCopy(wxCommandEvent& event); + void OnMouseEnter(wxMouseEvent& event); + void OnMouseLeave(wxMouseEvent& event); #endif // Returns new filter (will be stored into m_DefaultFilter variable) @@ -228,6 +232,7 @@ protected: // and wxHW_NO_SELECTION not used) bool IsSelectionEnabled() const; +#if wxUSE_CLIPBOARD // Convert selection to text: wxString SelectionToText(); @@ -239,10 +244,12 @@ protected: // Copies selection to clipboard: void CopySelection(ClipboardType t = Secondary); + void StopAutoScrolling(); +#endif protected: - // This is pointer to the first cell in parsed data. - // (Note: the first cell is usually top one = all other cells are sub-cells of this one) + // This is pointer to the first cell in parsed data. (Note: the first cell + // is usually top one = all other cells are sub-cells of this one) wxHtmlContainerCell *m_Cell; // parser which is used to parse HTML input. // Each wxHtmlWindow has it's own parser because sharing one global @@ -275,7 +282,14 @@ protected: // true if the user is dragging mouse to select text bool m_makingSelection; +#if wxUSE_CLIPBOARD + wxHtmlWinAutoScrollTimer *m_timerAutoScroll; +#endif + private: + // window content for double buffered rendering: + wxBitmap *m_backBuffer; + // variables used when user is selecting text wxPoint m_tmpSelFromPos; wxHtmlCell *m_tmpSelFromCell; diff --git a/src/html/htmlcell.cpp b/src/html/htmlcell.cpp index 3fbef604ee..8a5cdb1f53 100644 --- a/src/html/htmlcell.cpp +++ b/src/html/htmlcell.cpp @@ -36,8 +36,8 @@ // Helper classes //----------------------------------------------------------------------------- -void wxHtmlSelection::Set(const wxPoint& fromPos, wxHtmlCell *fromCell, - const wxPoint& toPos, wxHtmlCell *toCell) +void wxHtmlSelection::Set(const wxPoint& fromPos, const wxHtmlCell *fromCell, + const wxPoint& toPos, const wxHtmlCell *toCell) { m_fromCell = fromCell; m_toCell = toCell; @@ -45,7 +45,7 @@ void wxHtmlSelection::Set(const wxPoint& fromPos, wxHtmlCell *fromCell, m_toPos = toPos; } -void wxHtmlSelection::Set(wxHtmlCell *fromCell, wxHtmlCell *toCell) +void wxHtmlSelection::Set(const wxHtmlCell *fromCell, const wxHtmlCell *toCell) { wxPoint p1 = fromCell ? fromCell->GetAbsPos() : wxDefaultPosition; wxPoint p2 = toCell ? toCell->GetAbsPos() : wxDefaultPosition; @@ -249,7 +249,7 @@ wxHtmlWordCell::wxHtmlWordCell(const wxString& word, wxDC& dc) : wxHtmlCell() // Splits m_Word into up to three parts according to selection, returns // substring before, in and after selection and the points (in relative coords) // where s2 and s3 start: -void wxHtmlWordCell::Split(wxDC& dc, +void wxHtmlWordCell::Split(wxDC& dc, const wxPoint& selFrom, const wxPoint& selTo, unsigned& pos1, unsigned& pos2) const { @@ -356,6 +356,19 @@ void wxHtmlWordCell::Draw(wxDC& dc, int x, int y, wxPoint priv = (this == s->GetFromCell()) ? s->GetFromPrivPos() : s->GetToPrivPos(); + + // NB: this is quite a hack: in order to compute selection boundaries + // (in word's characters) we must know current font, which is only + // possible inside rendering code. Therefore we update the + // information here and store it in wxHtmlSelection so that + // ConvertToText can use it later: + if ( priv == wxDefaultPosition ) + { + SetSelectionPrivPos(dc, s); + priv = (this == s->GetFromCell()) ? + s->GetFromPrivPos() : s->GetToPrivPos(); + } + int part1 = priv.x; int part2 = priv.y; diff --git a/src/html/htmlwin.cpp b/src/html/htmlwin.cpp index f4e541e312..a31d540ccf 100644 --- a/src/html/htmlwin.cpp +++ b/src/html/htmlwin.cpp @@ -33,10 +33,86 @@ #include "wx/html/htmlproc.h" #include "wx/list.h" #include "wx/clipbrd.h" +#include "wx/timer.h" +#include "wx/dcmemory.h" #include "wx/arrimpl.cpp" #include "wx/listimpl.cpp" + + +#if wxUSE_CLIPBOARD +// ---------------------------------------------------------------------------- +// wxHtmlWinAutoScrollTimer: the timer used to generate a stream of scroll +// events when a captured mouse is held outside the window +// ---------------------------------------------------------------------------- + +class wxHtmlWinAutoScrollTimer : public wxTimer +{ +public: + wxHtmlWinAutoScrollTimer(wxScrolledWindow *win, + wxEventType eventTypeToSend, + int pos, int orient) + { + m_win = win; + m_eventType = eventTypeToSend; + m_pos = pos; + m_orient = orient; + } + + virtual void Notify(); + +private: + wxScrolledWindow *m_win; + wxEventType m_eventType; + int m_pos, + m_orient; + + DECLARE_NO_COPY_CLASS(wxHtmlWinAutoScrollTimer) +}; + +void wxHtmlWinAutoScrollTimer::Notify() +{ + // only do all this as long as the window is capturing the mouse + if ( wxWindow::GetCapture() != m_win ) + { + Stop(); + } + else // we still capture the mouse, continue generating events + { + // first scroll the window if we are allowed to do it + wxScrollWinEvent event1(m_eventType, m_pos, m_orient); + event1.SetEventObject(m_win); + if ( m_win->GetEventHandler()->ProcessEvent(event1) ) + { + // and then send a pseudo mouse-move event to refresh the selection + wxMouseEvent event2(wxEVT_MOTION); + wxGetMousePosition(&event2.m_x, &event2.m_y); + + // the mouse event coordinates should be client, not screen as + // returned by wxGetMousePosition + wxWindow *parentTop = m_win; + while ( parentTop->GetParent() ) + parentTop = parentTop->GetParent(); + wxPoint ptOrig = parentTop->GetPosition(); + event2.m_x -= ptOrig.x; + event2.m_y -= ptOrig.y; + + event2.SetEventObject(m_win); + + // FIXME: we don't fill in the other members - ok? + m_win->GetEventHandler()->ProcessEvent(event2); + } + else // can't scroll further, stop + { + Stop(); + } + } +} +#endif + + + //----------------------------------------------------------------------------- // wxHtmlHistoryItem //----------------------------------------------------------------------------- @@ -95,6 +171,10 @@ void wxHtmlWindow::Init() SetBorders(10); m_selection = NULL; m_makingSelection = false; +#if wxUSE_CLIPBOARD + m_timerAutoScroll = NULL; +#endif + m_backBuffer = NULL; } bool wxHtmlWindow::Create(wxWindow *parent, wxWindowID id, @@ -113,6 +193,9 @@ bool wxHtmlWindow::Create(wxWindow *parent, wxWindowID id, wxHtmlWindow::~wxHtmlWindow() { +#if wxUSE_CLIPBOARD + StopAutoScrolling(); +#endif HistoryClear(); if (m_Cell) delete m_Cell; @@ -121,6 +204,7 @@ wxHtmlWindow::~wxHtmlWindow() delete m_FS; delete m_History; delete m_Processors; + delete m_backBuffer; } @@ -637,6 +721,7 @@ bool wxHtmlWindow::IsSelectionEnabled() const } +#if wxUSE_CLIPBOARD wxString wxHtmlWindow::SelectionToText() { if ( !m_selection ) @@ -666,7 +751,6 @@ wxString wxHtmlWindow::SelectionToText() void wxHtmlWindow::CopySelection(ClipboardType t) { -#if wxUSE_CLIPBOARD if ( m_selection ) { wxTheClipboard->UsePrimarySelection(t == Primary); @@ -679,8 +763,8 @@ void wxHtmlWindow::CopySelection(ClipboardType t) _("Copied to clipboard:\"%s\""), txt.c_str()); } } -#endif } +#endif void wxHtmlWindow::OnLinkClicked(const wxHtmlLinkInfo& link) @@ -705,25 +789,45 @@ void wxHtmlWindow::OnCellMouseHover(wxHtmlCell * WXUNUSED(cell), // do nothing here } -void wxHtmlWindow::OnDraw(wxDC& dc) +void wxHtmlWindow::OnEraseBackground(wxEraseEvent& event) +{ +} + +void wxHtmlWindow::OnPaint(wxPaintEvent& WXUNUSED(event)) { + wxPaintDC dc(this); + if (m_tmpCanDrawLocks > 0 || m_Cell == NULL) return; int x, y; - wxRect rect = GetUpdateRegion().GetBox(); - - dc.SetMapMode(wxMM_TEXT); - dc.SetBackgroundMode(wxTRANSPARENT); GetViewStart(&x, &y); - + wxRect rect = GetUpdateRegion().GetBox(); + wxSize sz = GetSize(); + + wxMemoryDC dcm; + if ( !m_backBuffer ) + m_backBuffer = new wxBitmap(sz.x, sz.y); + dcm.SelectObject(*m_backBuffer); + dcm.SetBackground(wxBrush(GetBackgroundColour(), wxSOLID)); + dcm.Clear(); + PrepareDC(dcm); + dcm.SetMapMode(wxMM_TEXT); + dcm.SetBackgroundMode(wxTRANSPARENT); + wxHtmlRenderingInfo rinfo; wxDefaultHtmlRenderingStyle rstyle; rinfo.SetSelection(m_selection); rinfo.SetStyle(&rstyle); - m_Cell->Draw(dc, 0, 0, + m_Cell->Draw(dcm, 0, 0, y * wxHTML_SCROLL_STEP + rect.GetTop(), y * wxHTML_SCROLL_STEP + rect.GetBottom(), rinfo); + + dcm.SetDeviceOrigin(0,0); + dc.Blit(0, rect.GetTop(), + sz.x, rect.GetBottom() - rect.GetTop() + 1, + &dcm, + 0, rect.GetTop()); } @@ -731,8 +835,19 @@ void wxHtmlWindow::OnDraw(wxDC& dc) void wxHtmlWindow::OnSize(wxSizeEvent& event) { + wxDELETE(m_backBuffer); + wxScrolledWindow::OnSize(event); CreateLayout(); + + // Recompute selection if necessary: + if ( m_selection ) + { + m_selection->Set(m_selection->GetFromCell(), + m_selection->GetToCell()); + m_selection->ClearPrivPos(); + } + Refresh(); } @@ -762,6 +877,7 @@ void wxHtmlWindow::OnMouseDown(wxMouseEvent& event) void wxHtmlWindow::OnMouseUp(wxMouseEvent& event) { +#if wxUSE_CLIPBOARD if ( m_makingSelection ) { ReleaseMouse(); @@ -778,6 +894,7 @@ void wxHtmlWindow::OnMouseUp(wxMouseEvent& event) return; } } +#endif SetFocus(); if ( m_Cell ) @@ -884,14 +1001,8 @@ void wxHtmlWindow::OnIdle(wxIdleEvent& WXUNUSED(event)) m_selection->Set(wxPoint(x,y), selcell, m_tmpSelFromPos, m_tmpSelFromCell); } - { - wxClientDC dc(this); - m_selection->GetFromCell()->SetSelectionPrivPos( - dc, m_selection); - m_selection->GetToCell()->SetSelectionPrivPos( - dc, m_selection); - } - Refresh(); // FIXME - optimize! + m_selection->ClearPrivPos(); + Refresh(); } } } @@ -931,6 +1042,85 @@ void wxHtmlWindow::OnIdle(wxIdleEvent& WXUNUSED(event)) } #if wxUSE_CLIPBOARD +void wxHtmlWindow::StopAutoScrolling() +{ + if ( m_timerAutoScroll ) + { + wxDELETE(m_timerAutoScroll); + } +} + +void wxHtmlWindow::OnMouseEnter(wxMouseEvent& event) +{ + StopAutoScrolling(); + event.Skip(); +} + +void wxHtmlWindow::OnMouseLeave(wxMouseEvent& event) +{ + // don't prevent the usual processing of the event from taking place + event.Skip(); + + // when a captured mouse leave a scrolled window we start generate + // scrolling events to allow, for example, extending selection beyond the + // visible area in some controls + if ( wxWindow::GetCapture() == this ) + { + // where is the mouse leaving? + int pos, orient; + wxPoint pt = event.GetPosition(); + if ( pt.x < 0 ) + { + orient = wxHORIZONTAL; + pos = 0; + } + else if ( pt.y < 0 ) + { + orient = wxVERTICAL; + pos = 0; + } + else // we're lower or to the right of the window + { + wxSize size = GetClientSize(); + if ( pt.x > size.x ) + { + orient = wxHORIZONTAL; + pos = GetVirtualSize().x / wxHTML_SCROLL_STEP; + } + else if ( pt.y > size.y ) + { + orient = wxVERTICAL; + pos = GetVirtualSize().y / wxHTML_SCROLL_STEP; + } + else // this should be impossible + { + // but seems to happen sometimes under wxMSW - maybe it's a bug + // there but for now just ignore it + + //wxFAIL_MSG( _T("can't understand where has mouse gone") ); + + return; + } + } + + // only start the auto scroll timer if the window can be scrolled in + // this direction + if ( !HasScrollbar(orient) ) + return; + + delete m_timerAutoScroll; + m_timerAutoScroll = new wxHtmlWinAutoScrollTimer + ( + this, + pos == 0 ? wxEVT_SCROLLWIN_LINEUP + : wxEVT_SCROLLWIN_LINEDOWN, + pos, + orient + ); + m_timerAutoScroll->Start(50); // FIXME: make configurable + } +} + void wxHtmlWindow::OnKeyUp(wxKeyEvent& event) { if ( event.GetKeyCode() == 'C' && event.ControlDown() ) @@ -962,7 +1152,11 @@ BEGIN_EVENT_TABLE(wxHtmlWindow, wxScrolledWindow) EVT_RIGHT_UP(wxHtmlWindow::OnMouseUp) EVT_MOTION(wxHtmlWindow::OnMouseMove) EVT_IDLE(wxHtmlWindow::OnIdle) + EVT_ERASE_BACKGROUND(wxHtmlWindow::OnEraseBackground) + EVT_PAINT(wxHtmlWindow::OnPaint) #if wxUSE_CLIPBOARD + EVT_ENTER_WINDOW(wxHtmlWindow::OnMouseEnter) + EVT_LEAVE_WINDOW(wxHtmlWindow::OnMouseLeave) EVT_KEY_UP(wxHtmlWindow::OnKeyUp) EVT_MENU(wxID_COPY, wxHtmlWindow::OnCopy) #endif -- 2.45.2