]> git.saurik.com Git - wxWidgets.git/commitdiff
more work on text selection: selecting should work now, but there's no clipboard...
authorVáclav Slavík <vslavik@fastmail.fm>
Sun, 1 Jun 2003 22:19:15 +0000 (22:19 +0000)
committerVáclav Slavík <vslavik@fastmail.fm>
Sun, 1 Jun 2003 22:19:15 +0000 (22:19 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@20849 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

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

index 4b2e9f72c30e12570110efcc50a0ad3d38cb33e8..3db125c3150d89ca4f9d86fad8c79a26fa087ce4 100644 (file)
@@ -101,8 +101,9 @@ private:
 // Flags for wxHtmlCell::FindCellByPos
 enum
 {
-    wxHTML_FIND_TERMINAL    = 0x0001,
-    wxHTML_FIND_NONTERMINAL = 0x0002
+    wxHTML_FIND_EXACT             = 1,
+    wxHTML_FIND_NEAREST_BEFORE    = 2,
+    wxHTML_FIND_NEAREST_AFTER     = 4,
 };
 
 
@@ -216,7 +217,17 @@ public:
     // nonterminal cells or both. In either case, returned cell is deepest
     // cell in cells tree that contains [x,y].
     virtual wxHtmlCell *FindCellByPos(wxCoord x, wxCoord y,
-                                  unsigned flags = wxHTML_FIND_TERMINAL) const;
+                                  unsigned flags = wxHTML_FIND_EXACT) const;
+
+    // Returns absolute position of the cell on HTML canvas
+    wxPoint GetAbsPos() const;
+
+    // Returns first (last) terminal cell inside this cell. It may return NULL,
+    // but it is rare -- only if there are no terminals in the tree.
+    virtual wxHtmlCell *GetFirstTerminal() const 
+        { return wxConstCast(this, wxHtmlCell); }
+    virtual wxHtmlCell *GetLastTerminal() const 
+        { return wxConstCast(this, wxHtmlCell); }
 
 protected:
     wxHtmlCell *m_Next;
@@ -325,7 +336,10 @@ public:
     virtual bool IsTerminalCell() const { return FALSE; }
 
     virtual wxHtmlCell *FindCellByPos(wxCoord x, wxCoord y,
-                                  unsigned flags = wxHTML_FIND_TERMINAL) const;
+                                  unsigned flags = wxHTML_FIND_EXACT) const;
+    
+    virtual wxHtmlCell *GetFirstTerminal() const;
+    virtual wxHtmlCell *GetLastTerminal() const;
 
 protected:
     void UpdateRenderingStatePre(wxHtmlRenderingState& state,
index 719fbc4fc574862151e6eddfdb645a0c3185bacd..380336f632b16ebcde33543c3913c7545862ba83 100644 (file)
@@ -210,7 +210,8 @@ protected:
     void OnDraw(wxDC& dc);
     void OnSize(wxSizeEvent& event);
     void OnMouseMove(wxMouseEvent& event);
-    void OnMouseButton(wxMouseEvent& event);
+    void OnMouseDown(wxMouseEvent& event);
+    void OnMouseUp(wxMouseEvent& event);
     void OnIdle(wxIdleEvent& event);
 
     // Returns new filter (will be stored into m_DefaultFilter variable)
@@ -252,7 +253,17 @@ protected:
 
     int m_Style;
 
+    // current text selection or NULL
+    wxHtmlSelection *m_selection;
+
+    // true if the user is dragging mouse to select text
+    bool m_makingSelection;
+
 private:
+    // variables used when user is selecting text
+    wxPoint     m_tmpSelFromPos;
+    wxHtmlCell *m_tmpSelFromCell;
+    
     // a flag indicated if mouse moved
     // (if TRUE we will try to change cursor in last call to OnIdle)
     bool m_tmpMouseMoved;
index d01ec35ffb694a6f3f7ff00da4f05820303701ba..5191e19ecde71601aa0e451f4805a958a4fde579 100644 (file)
@@ -113,7 +113,9 @@ class wxHtmlHelpHtmlWindow : public wxHtmlWindow
         virtual void OnLinkClicked(const wxHtmlLinkInfo& link)
         {
             wxHtmlWindow::OnLinkClicked(link);
-            m_Frame->NotifyPageChanged();
+            const wxMouseEvent *e = link.GetEvent();
+            if (e == NULL || e->LeftUp())
+                m_Frame->NotifyPageChanged();
         }
 
     private:
index 9a31271bc247612fc495fde6b8391b16c2322b0e..b54d5d19538e932ed7ab439ff2b2e21c1b4ad884 100644 (file)
@@ -119,12 +119,33 @@ const wxHtmlCell* wxHtmlCell::Find(int WXUNUSED(condition), const void* WXUNUSED
 wxHtmlCell *wxHtmlCell::FindCellByPos(wxCoord x, wxCoord y,
                                       unsigned flags) const
 {
-    if ( (flags & wxHTML_FIND_TERMINAL) &&
-         x >= 0 && x < m_Width && y >= 0 && y < m_Height )
+    if ( x >= 0 && x < m_Width && y >= 0 && y < m_Height )
     {
         return wxConstCast(this, wxHtmlCell);
     }
-    return NULL;
+    else
+    {
+        if ((flags & wxHTML_FIND_NEAREST_AFTER) &&
+                (y < 0 || (y == 0 && x <= 0)))
+            return wxConstCast(this, wxHtmlCell);
+        else if ((flags & wxHTML_FIND_NEAREST_BEFORE) &&
+                (y > m_Height-1 || (y == m_Height-1 && x >= m_Width)))
+            return wxConstCast(this, wxHtmlCell);
+        else
+            return NULL;
+    }
+}
+
+
+wxPoint wxHtmlCell::GetAbsPos() const
+{
+    wxPoint p(m_PosX, m_PosY);
+    for (wxHtmlCell *parent = m_Parent; parent; parent = parent->m_Parent)
+    {
+        p.x += parent->m_PosX;
+        p.y += parent->m_PosY;
+    }
+    return p;
 }
 
 
@@ -145,7 +166,7 @@ void wxHtmlWordCell::Draw(wxDC& dc, int x, int y,
                           int WXUNUSED(view_y1), int WXUNUSED(view_y2),
                           wxHtmlRenderingState& state)
 {
-    if (state.GetSelectionState() == wxHTML_SEL_IN &&
+    if (state.GetSelectionState() != wxHTML_SEL_OUT &&
         dc.GetBackgroundMode() != wxSOLID)
     {
         dc.SetBackgroundMode(wxSOLID);
@@ -440,10 +461,10 @@ void wxHtmlContainerCell::UpdateRenderingStatePost(wxHtmlRenderingState& state,
 {
     wxHtmlSelection *s = state.GetSelection();
     if (!s) return;
-    if (s->GetFromCell() == cell)
-        state.SetSelectionState(wxHTML_SEL_IN);
-    else if (s->GetToCell() == cell)
+    if (s->GetToCell() == cell)
         state.SetSelectionState(wxHTML_SEL_OUT);
+    else if (s->GetFromCell() == cell)
+        state.SetSelectionState(wxHTML_SEL_IN);
 }
 
 #define mMin(a, b) (((a) < (b)) ? (a) : (b))
@@ -616,24 +637,53 @@ const wxHtmlCell* wxHtmlContainerCell::Find(int condition, const void* param) co
 wxHtmlCell *wxHtmlContainerCell::FindCellByPos(wxCoord x, wxCoord y,
                                                unsigned flags) const
 {
-    for ( const wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext() )
+    if (flags & wxHTML_FIND_EXACT)
     {
-        int cx = cell->GetPosX(),
-            cy = cell->GetPosY();
+        for ( const wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext() )
+        {
+            int cx = cell->GetPosX(),
+                cy = cell->GetPosY();
+
+            if ( (cx <= x) && (cx + cell->GetWidth() > x) &&
+                 (cy <= y) && (cy + cell->GetHeight() > y) )
+            {
+                return cell->FindCellByPos(x - cx, y - cy, flags);
+            }
+        }
+        return NULL;
+    }
 
-        if ( (cx <= x) && (cx + cell->GetWidth() > x) &&
-             (cy <= y) && (cy + cell->GetHeight() > y) )
+    if ( flags & wxHTML_FIND_NEAREST_AFTER )
+    {
+        wxHtmlCell *c;
+        int y2;
+        for ( const wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext() )
         {
-            wxHtmlCell *c = cell->FindCellByPos(x - cx, y - cy, flags);
-            if (c == NULL && (flags & wxHTML_FIND_NONTERMINAL))
-                return wxConstCast(this, wxHtmlContainerCell);
-            else
-                return c;
+            y2 = cell->GetPosY() + cell->GetHeight() - 1;
+            if (y2 < y || (y2 == y && cell->GetPosX()+cell->GetWidth()-1 < x))
+                continue;
+            c = cell->FindCellByPos(x - cell->GetPosX(), y - cell->GetPosY(),
+                                    flags);
+            if (c) return c;
         }
+        return NULL;
     }
 
-    return (flags & wxHTML_FIND_NONTERMINAL) ? 
-                wxConstCast(this, wxHtmlContainerCell) : NULL;
+    if ( flags & wxHTML_FIND_NEAREST_BEFORE )
+    {
+        wxHtmlCell *c = NULL;
+        wxHtmlCell *cx;
+        for ( const wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext() )
+        {
+            if (cell->GetPosY() > y || 
+                    (cell->GetPosY() == y && cell->GetPosX() > x))
+                break;
+            cx = cell->FindCellByPos(x - cell->GetPosX(), y - cell->GetPosY(),
+                                     flags);
+            if (cx) c = cx;
+        }
+        return c;
+    }
 }
 
 
@@ -669,6 +719,26 @@ void wxHtmlContainerCell::GetHorizontalConstraints(int *left, int *right) const
         *right = cright;
 }
 
+    
+wxHtmlCell *wxHtmlContainerCell::GetFirstTerminal() const
+{
+    if (m_Cells)
+        return m_Cells->GetFirstTerminal();
+    else
+        return NULL;
+}
+
+wxHtmlCell *wxHtmlContainerCell::GetLastTerminal() const
+{
+    if (m_Cells)
+    {
+        wxHtmlCell *c;
+        for (c = m_Cells; c->GetNext(); c = c->GetNext()) {}
+        return c;
+    }
+    else
+        return NULL;
+}
 
 
 
index 08e39660447d00a43b86e5c7fe90ce1776965857..653eec918d391cfea242c77eac536232f42b66da 100644 (file)
@@ -92,6 +92,8 @@ void wxHtmlWindow::Init()
     m_Processors = NULL;
     m_Style = 0;
     SetBorders(10);
+    m_selection = NULL;
+    m_makingSelection = false;
 }
 
 bool wxHtmlWindow::Create(wxWindow *parent, wxWindowID id,
@@ -153,6 +155,8 @@ bool wxHtmlWindow::SetPage(const wxString& source)
 {
     wxString newsrc(source);
 
+    wxDELETE(m_selection);
+
     // pass HTML through registered processors:
     if (m_Processors || m_GlobalProcessors)
     {
@@ -665,7 +669,7 @@ void wxHtmlWindow::OnDraw(wxDC& dc)
     dc.SetBackgroundMode(wxTRANSPARENT);
     GetViewStart(&x, &y);
 
-    wxHtmlRenderingState rstate(NULL);
+    wxHtmlRenderingState rstate(m_selection);
     m_Cell->Draw(dc, 0, 0,
                  y * wxHTML_SCROLL_STEP + rect.GetTop(),
                  y * wxHTML_SCROLL_STEP + rect.GetBottom(),
@@ -688,20 +692,44 @@ void wxHtmlWindow::OnMouseMove(wxMouseEvent& event)
     m_tmpMouseMoved = true;
 }
 
-void wxHtmlWindow::OnMouseButton(wxMouseEvent& event)
+void wxHtmlWindow::OnMouseDown(wxMouseEvent& event)
 {
-    SetFocus();
-    if ( m_Cell )
+    if ( event.LeftDown() && IsSelectionEnabled() )
     {
-        int sx, sy;
-        GetViewStart(&sx, &sy);
-        sx *= wxHTML_SCROLL_STEP;
-        sy *= wxHTML_SCROLL_STEP;
+        m_makingSelection = true;
+            
+        if ( m_selection )
+        {
+            wxDELETE(m_selection);
+            Refresh();
+        }
+        m_tmpSelFromPos = CalcUnscrolledPosition(event.GetPosition());
+        m_tmpSelFromCell = NULL;
 
-        wxPoint pos = event.GetPosition();
-        pos.x += sx;
-        pos.y += sy;
+        CaptureMouse();
+    }
+}
 
+void wxHtmlWindow::OnMouseUp(wxMouseEvent& event)
+{
+    if ( m_makingSelection )
+    {
+        ReleaseMouse();
+        m_makingSelection = false;
+
+        // did the user move the mouse far enough from starting point?
+        if ( m_selection )
+        {
+            // we don't want mouse up event that ended selecting to be
+            // handled as mouse click and e.g. follow hyperlink:
+            return;
+        }
+    }
+    
+    SetFocus();
+    if ( m_Cell )
+    {
+        wxPoint pos = CalcUnscrolledPosition(event.GetPosition());
         wxHtmlCell *cell = m_Cell->FindCellByPos(pos.x, pos.y);
 
         // VZ: is it possible that we don't find anything at all?
@@ -724,18 +752,90 @@ void wxHtmlWindow::OnIdle(wxIdleEvent& WXUNUSED(event))
 
     if (m_tmpMouseMoved && (m_Cell != NULL))
     {
-        int sx, sy;
-        GetViewStart(&sx, &sy);
-        sx *= wxHTML_SCROLL_STEP;
-        sy *= wxHTML_SCROLL_STEP;
-
-        int x, y;
-        wxGetMousePosition(&x, &y);
-        ScreenToClient(&x, &y);
-        x += sx;
-        y += sy;
+        int xc, yc, x, y;
+        wxGetMousePosition(&xc, &yc);
+        ScreenToClient(&xc, &yc);
+        CalcUnscrolledPosition(xc, yc, &x, &y);
 
         wxHtmlCell *cell = m_Cell->FindCellByPos(x, y);
+
+        // handle selection update:
+        if ( m_makingSelection )
+        {
+            bool goingDown = m_tmpSelFromPos.y < y ||
+                             m_tmpSelFromPos.y == y && m_tmpSelFromPos.x < x;
+
+            if ( !m_tmpSelFromCell )
+            {
+                if (goingDown)
+                {
+                    m_tmpSelFromCell = m_Cell->FindCellByPos(x, y,
+                                                 wxHTML_FIND_NEAREST_BEFORE);
+                    if (!m_tmpSelFromCell)
+                        m_tmpSelFromCell = m_Cell->GetFirstTerminal();
+                }
+                else
+                {
+                    m_tmpSelFromCell = m_Cell->FindCellByPos(x, y,
+                                                 wxHTML_FIND_NEAREST_AFTER);
+                    if (!m_tmpSelFromCell)
+                        m_tmpSelFromCell = m_Cell->GetLastTerminal();
+                }
+            }
+
+            wxHtmlCell *selcell = cell;
+            if (!selcell)
+            {
+                if (goingDown)
+                {
+                    selcell = m_Cell->FindCellByPos(x, y,
+                                                 wxHTML_FIND_NEAREST_AFTER);
+                    if (!selcell)
+                        selcell = m_Cell->GetLastTerminal();
+                }
+                else
+                {
+                    selcell = m_Cell->FindCellByPos(x, y,
+                                                 wxHTML_FIND_NEAREST_BEFORE);
+                    if (!selcell)
+                        selcell = m_Cell->GetFirstTerminal();
+                }
+            }
+
+            // NB: it may *rarely* happen that the code above didn't find one
+            //     of the cells, e.g. if wxHtmlWindow doesn't contain any
+            //     visible cells. 
+            if ( selcell && m_tmpSelFromCell )
+            {                
+                if ( !m_selection )
+                {
+                    // start selecting only if mouse movement was big enough
+                    // (otherwise it was meant as mouse click, not selection):
+                    const int PRECISION = 2;
+                    wxPoint diff = m_tmpSelFromPos - wxPoint(x,y);
+                    if (abs(diff.x) > PRECISION || abs(diff.y) > PRECISION)
+                    {
+                        m_selection = new wxHtmlSelection();
+                    }
+                }
+                if ( m_selection )
+                {
+                    if (goingDown)
+                    {
+                        m_selection->Set(m_tmpSelFromPos, m_tmpSelFromCell,
+                                         wxPoint(x,y), selcell);
+                    }
+                    else
+                    {
+                        m_selection->Set(wxPoint(x,y), selcell,
+                                         m_tmpSelFromPos, m_tmpSelFromCell);
+                    }
+                    Refresh(); // FIXME - optimize!
+                }
+            }
+        }
+        
+        // handle cursor and status bar text changes:
         if ( cell != m_tmpLastCell )
         {
             wxHtmlLinkInfo *lnk = cell ? cell->GetLink(x, y) : NULL;
@@ -776,8 +876,9 @@ IMPLEMENT_DYNAMIC_CLASS(wxHtmlWindow,wxScrolledWindow)
 
 BEGIN_EVENT_TABLE(wxHtmlWindow, wxScrolledWindow)
     EVT_SIZE(wxHtmlWindow::OnSize)
-    EVT_LEFT_UP(wxHtmlWindow::OnMouseButton)
-    EVT_RIGHT_UP(wxHtmlWindow::OnMouseButton)
+    EVT_LEFT_DOWN(wxHtmlWindow::OnMouseDown)
+    EVT_LEFT_UP(wxHtmlWindow::OnMouseUp)
+    EVT_RIGHT_UP(wxHtmlWindow::OnMouseUp)
     EVT_MOTION(wxHtmlWindow::OnMouseMove)
     EVT_IDLE(wxHtmlWindow::OnIdle)
 END_EVENT_TABLE()