]> git.saurik.com Git - wxWidgets.git/commitdiff
added selecting-while-dragging
authorVáclav Slavík <vslavik@fastmail.fm>
Wed, 4 Jun 2003 18:17:04 +0000 (18:17 +0000)
committerVáclav Slavík <vslavik@fastmail.fm>
Wed, 4 Jun 2003 18:17:04 +0000 (18:17 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@20922 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/html/htmlcell.h
include/wx/html/htmlwin.h
src/html/htmlcell.cpp
src/html/htmlwin.cpp

index 312e334c999486c13075a5c12d5da56b28e7b2fc..11066eb8d8cb26a5916bdbf0de57abffb127c901 100644 (file)
@@ -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;
index 6b1f0dd6a0604fc730fa84726ad34395bb545289..6a4e2fdf2ec48614d7e4973a10347970b7c80951 100644 (file)
@@ -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;
index 3fbef604ee1b3a6d8a7bc71183286c0ba3881be7..8a5cdb1f532bb6155ff59cae3d1a44d8aa6986ee 100644 (file)
@@ -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;
 
index f4e541e312bad6eb2ccfd508063d6799bb0b09b1..a31d540ccf873cdad70e01c10ad0718d50784747 100644 (file)
 #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