From adf2eb2d343159326a68ba1a9b1a76f60f30d937 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= Date: Sun, 1 Jun 2003 22:19:15 +0000 Subject: [PATCH] more work on text selection: selecting should work now, but there's no clipboard interaction yet git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@20849 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/html/htmlcell.h | 22 +++++- include/wx/html/htmlwin.h | 13 +++- src/html/helpfrm.cpp | 4 +- src/html/htmlcell.cpp | 108 ++++++++++++++++++++++----- src/html/htmlwin.cpp | 147 +++++++++++++++++++++++++++++++------ 5 files changed, 246 insertions(+), 48 deletions(-) diff --git a/include/wx/html/htmlcell.h b/include/wx/html/htmlcell.h index 4b2e9f72c3..3db125c315 100644 --- a/include/wx/html/htmlcell.h +++ b/include/wx/html/htmlcell.h @@ -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, diff --git a/include/wx/html/htmlwin.h b/include/wx/html/htmlwin.h index 719fbc4fc5..380336f632 100644 --- a/include/wx/html/htmlwin.h +++ b/include/wx/html/htmlwin.h @@ -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; diff --git a/src/html/helpfrm.cpp b/src/html/helpfrm.cpp index d01ec35ffb..5191e19ecd 100644 --- a/src/html/helpfrm.cpp +++ b/src/html/helpfrm.cpp @@ -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: diff --git a/src/html/htmlcell.cpp b/src/html/htmlcell.cpp index 9a31271bc2..b54d5d1953 100644 --- a/src/html/htmlcell.cpp +++ b/src/html/htmlcell.cpp @@ -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; +} diff --git a/src/html/htmlwin.cpp b/src/html/htmlwin.cpp index 08e3966044..653eec918d 100644 --- a/src/html/htmlwin.cpp +++ b/src/html/htmlwin.cpp @@ -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() -- 2.45.2