diff --git a/include/wx/html/htmlcell.h b/include/wx/html/htmlcell.h
index a4fefc2eee..0068c8c173 100644
--- a/include/wx/html/htmlcell.h
+++ b/include/wx/html/htmlcell.h
@@ -35,7 +35,8 @@ public:
wxHtmlSelection()
: m_fromPos(wxDefaultPosition), m_toPos(wxDefaultPosition),
m_fromCharacterPos(-1), m_toCharacterPos(-1),
- m_fromCell(NULL), m_toCell(NULL) {}
+ m_fromCell(NULL), m_toCell(NULL),
+ m_extBeforeSel(0), m_extBeforeSelEnd(0) {}
// this version is used for the user selection defined with the mouse
void Set(const wxPoint& fromPos, const wxHtmlCell *fromCell,
@@ -58,6 +59,11 @@ public:
wxCoord GetFromCharacterPos () const { return m_fromCharacterPos; }
wxCoord GetToCharacterPos () const { return m_toCharacterPos; }
+ void SetExtentBeforeSelection(unsigned ext) { m_extBeforeSel = ext; }
+ void SetExtentBeforeSelectionEnd(unsigned ext) { m_extBeforeSelEnd = ext; }
+ unsigned GetExtentBeforeSelection() const { return m_extBeforeSel; }
+ unsigned GetExtentBeforeSelectionEnd() const { return m_extBeforeSelEnd; }
+
bool IsEmpty() const
{ return m_fromPos == wxDefaultPosition &&
m_toPos == wxDefaultPosition; }
@@ -66,6 +72,12 @@ private:
wxPoint m_fromPos, m_toPos;
wxCoord m_fromCharacterPos, m_toCharacterPos;
const wxHtmlCell *m_fromCell, *m_toCell;
+
+ // Extent of the text before selection start.
+ unsigned m_extBeforeSel;
+
+ // Extent of the text from the beginning to the selection end.
+ unsigned m_extBeforeSelEnd;
};
@@ -115,8 +127,17 @@ public:
class WXDLLIMPEXP_HTML wxDefaultHtmlRenderingStyle : public wxHtmlRenderingStyle
{
public:
+ explicit wxDefaultHtmlRenderingStyle(const wxWindowBase* wnd = NULL)
+ : m_wnd(wnd)
+ {}
+
virtual wxColour GetSelectedTextColour(const wxColour& clr) wxOVERRIDE;
virtual wxColour GetSelectedTextBgColour(const wxColour& clr) wxOVERRIDE;
+
+private:
+ const wxWindowBase* const m_wnd;
+
+ wxDECLARE_NO_COPY_CLASS(wxDefaultHtmlRenderingStyle);
};
@@ -320,7 +341,12 @@ public:
// Returns absolute position of the cell on HTML canvas.
// If rootCell is provided, then it's considered to be the root of the
// hierarchy and the returned value is relative to it.
- wxPoint GetAbsPos(wxHtmlCell *rootCell = NULL) const;
+ wxPoint GetAbsPos(const wxHtmlCell *rootCell = NULL) const;
+
+ // Returns minimum bounding rectangle of this cell in coordinates, relative
+ // to the rootCell, if it is provided, or relative to the result of
+ // GetRootCell() if the rootCell is NULL.
+ wxRect GetRect(const wxHtmlCell *rootCell = NULL) const;
// Returns root cell of the hierarchy (i.e. grand-grand-...-parent that
// doesn't have a parent itself)
@@ -417,7 +443,8 @@ protected:
void SetSelectionPrivPos(const wxDC& dc, wxHtmlSelection *s) const;
void Split(const wxDC& dc,
const wxPoint& selFrom, const wxPoint& selTo,
- unsigned& pos1, unsigned& pos2) const;
+ unsigned& pos1, unsigned& pos2,
+ unsigned& ext1, unsigned& ext2) const;
wxString m_Word;
bool m_allowLinebreak;
diff --git a/include/wx/html/htmlwin.h b/include/wx/html/htmlwin.h
index 1dfc31b5cd..472fffbc81 100644
--- a/include/wx/html/htmlwin.h
+++ b/include/wx/html/htmlwin.h
@@ -408,6 +408,7 @@ protected:
void OnMouseMove(wxMouseEvent& event);
void OnMouseDown(wxMouseEvent& event);
void OnMouseUp(wxMouseEvent& event);
+ void OnFocusEvent(wxFocusEvent& event);
#if wxUSE_CLIPBOARD
void OnKeyUp(wxKeyEvent& event);
void OnDoubleClick(wxMouseEvent& event);
diff --git a/src/generic/htmllbox.cpp b/src/generic/htmllbox.cpp
index 011f6cc557..e1c3720235 100644
--- a/src/generic/htmllbox.cpp
+++ b/src/generic/htmllbox.cpp
@@ -159,7 +159,9 @@ private:
class wxHtmlListBoxStyle : public wxDefaultHtmlRenderingStyle
{
public:
- wxHtmlListBoxStyle(const wxHtmlListBox& hlbox) : m_hlbox(hlbox) { }
+ wxHtmlListBoxStyle(const wxHtmlListBox& hlbox)
+ : wxDefaultHtmlRenderingStyle(&hlbox), m_hlbox(hlbox)
+ { }
virtual wxColour GetSelectedTextColour(const wxColour& colFg) wxOVERRIDE
{
diff --git a/src/html/htmlcell.cpp b/src/html/htmlcell.cpp
index f5b115823d..a853cc0084 100644
--- a/src/html/htmlcell.cpp
+++ b/src/html/htmlcell.cpp
@@ -65,7 +65,12 @@ wxColour
wxDefaultHtmlRenderingStyle::
GetSelectedTextBgColour(const wxColour& WXUNUSED(clr))
{
- return wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
+ // By default we use the fixed standard selection colour, but if we're
+ // associated with a window use the colour appropriate for the window
+ // state, i.e. grey out selection when it's not in focus.
+
+ return wxSystemSettings::GetColour(!m_wnd || m_wnd->HasFocus() ?
+ wxSYS_COLOUR_HIGHLIGHT : wxSYS_COLOUR_BTNSHADOW);
}
@@ -216,10 +221,10 @@ wxHtmlCell *wxHtmlCell::FindCellByPos(wxCoord x, wxCoord y,
}
-wxPoint wxHtmlCell::GetAbsPos(wxHtmlCell *rootCell) const
+wxPoint wxHtmlCell::GetAbsPos(const wxHtmlCell *rootCell) const
{
wxPoint p(m_PosX, m_PosY);
- for (wxHtmlCell *parent = m_Parent; parent && parent != rootCell;
+ for (const wxHtmlCell *parent = m_Parent; parent && parent != rootCell;
parent = parent->m_Parent)
{
p.x += parent->m_PosX;
@@ -228,6 +233,11 @@ wxPoint wxHtmlCell::GetAbsPos(wxHtmlCell *rootCell) const
return p;
}
+wxRect wxHtmlCell::GetRect(const wxHtmlCell* rootCell) const
+{
+ return wxRect(GetAbsPos(rootCell), wxSize(m_Width, m_Height));
+}
+
wxHtmlCell *wxHtmlCell::GetRootCell() const
{
wxHtmlCell *c = wxConstCast(this, wxHtmlCell);
@@ -333,7 +343,8 @@ void wxHtmlWordCell::SetPreviousWord(wxHtmlWordCell *cell)
// where s2 and s3 start:
void wxHtmlWordCell::Split(const wxDC& dc,
const wxPoint& selFrom, const wxPoint& selTo,
- unsigned& pos1, unsigned& pos2) const
+ unsigned& pos1, unsigned& pos2,
+ unsigned& ext1, unsigned& ext2) const
{
wxPoint pt1 = (selFrom == wxDefaultPosition) ?
wxDefaultPosition : selFrom - GetAbsPos();
@@ -390,21 +401,30 @@ void wxHtmlWordCell::Split(const wxDC& dc,
pos2 = j;
wxASSERT( pos2 >= pos1 );
+
+ ext1 = pos1 == 0 ? 0 : (pos1 < widths.size() ? widths[pos1-1] : widths.Last());
+ ext2 = pos2 == 0 ? 0 : (pos2 < widths.size() ? widths[pos2-1] : widths.Last());
}
void wxHtmlWordCell::SetSelectionPrivPos(const wxDC& dc, wxHtmlSelection *s) const
{
- unsigned p1, p2;
+ unsigned p1, p2, ext1, ext2;
Split(dc,
this == s->GetFromCell() ? s->GetFromPos() : wxDefaultPosition,
this == s->GetToCell() ? s->GetToPos() : wxDefaultPosition,
- p1, p2);
+ p1, p2, ext1, ext2);
if ( this == s->GetFromCell() )
- s->SetFromCharacterPos (p1); // selection starts here
+ {
+ s->SetFromCharacterPos(p1); // selection starts here
+ s->SetExtentBeforeSelection(ext1);
+ }
if ( this == s->GetToCell() )
- s->SetToCharacterPos (p2); // selection ends here
+ {
+ s->SetToCharacterPos(p2); // selection ends here
+ s->SetExtentBeforeSelectionEnd(ext2);
+ }
}
@@ -449,7 +469,6 @@ void wxHtmlWordCell::Draw(wxDC& dc, int x, int y,
// Selection changing, we must draw the word piecewise:
wxHtmlSelection *s = info.GetSelection();
wxString txt;
- int w, h;
int ofs = 0;
// NB: this is quite a hack: in order to compute selection boundaries
@@ -469,8 +488,7 @@ void wxHtmlWordCell::Draw(wxDC& dc, int x, int y,
{
txt = m_Word.Mid(0, part1);
dc.DrawText(txt, x + m_PosX, y + m_PosY);
- dc.GetTextExtent(txt, &w, &h);
- ofs += w;
+ ofs += s->GetExtentBeforeSelection();
}
SwitchSelState(dc, info, true);
@@ -480,11 +498,9 @@ void wxHtmlWordCell::Draw(wxDC& dc, int x, int y,
if ( (size_t)part2 < m_Word.length() )
{
- dc.GetTextExtent(txt, &w, &h);
- ofs += w;
SwitchSelState(dc, info, false);
txt = m_Word.Mid(part2);
- dc.DrawText(txt, ofs + x + m_PosX, y + m_PosY);
+ dc.DrawText(txt, x + m_PosX + s->GetExtentBeforeSelectionEnd(), y + m_PosY);
}
else
drawSelectionAfterCell = true;
diff --git a/src/html/htmlwin.cpp b/src/html/htmlwin.cpp
index d3373316a5..8fdbe56cf6 100644
--- a/src/html/htmlwin.cpp
+++ b/src/html/htmlwin.cpp
@@ -1138,7 +1138,7 @@ void wxHtmlWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
dc->SetLayoutDirection(GetLayoutDirection());
wxHtmlRenderingInfo rinfo;
- wxDefaultHtmlRenderingStyle rstyle;
+ wxDefaultHtmlRenderingStyle rstyle(this);
rinfo.SetSelection(m_selection);
rinfo.SetStyle(&rstyle);
m_Cell->Draw(*dc, 0, 0,
@@ -1184,7 +1184,115 @@ void wxHtmlWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
}
}
+namespace
+{
+// Returns true if leftCell is an ancestor of rightCell.
+bool IsAncestor(const wxHtmlCell* leftCell, const wxHtmlCell* rightCell)
+{
+ for ( const wxHtmlCell* parent = rightCell->GetParent();
+ parent; parent = parent->GetParent() )
+ {
+ if ( leftCell == parent )
+ return true;
+ }
+ return false;
+}
+
+// Returns minimum bounding rectangle of all the cells between fromCell
+// and toCell, inclusive.
+wxRect GetBoundingRect(const wxHtmlCell* const fromCell,
+ const wxHtmlCell* const toCell)
+{
+ wxCHECK_MSG(fromCell || toCell, wxRect(), "At least one cell is required");
+
+ // Check if we have only one cell or the cells are equal.
+ if ( !fromCell )
+ return toCell->GetRect();
+ else if ( !toCell || fromCell == toCell )
+ return fromCell->GetRect();
+
+ // Check if one of the cells is an ancestor of the other.
+ if ( IsAncestor(fromCell, toCell) )
+ return fromCell->GetRect();
+ else if ( IsAncestor(toCell, fromCell) )
+ return toCell->GetRect();
+
+ // Combine MBRs, starting with the fromCell.
+ wxRect boundingRect = fromCell->GetRect();
+
+ // For each subtree toward the lowest common ancestor,
+ // combine MBRs until the (subtree of) toCell is reached.
+ for ( const wxHtmlCell *startCell = fromCell,
+ *parent = fromCell->GetParent();
+ parent;
+ startCell = parent, parent = parent->GetParent() )
+ {
+ if ( IsAncestor(parent, toCell) )
+ {
+ // Combine all the cells up to the toCell or its subtree.
+ for ( const wxHtmlCell* nextCell = startCell->GetNext();
+ nextCell;
+ nextCell = nextCell->GetNext() )
+ {
+ if ( nextCell == toCell )
+ return boundingRect.Union(toCell->GetRect());
+
+ if ( IsAncestor(nextCell, toCell) )
+ {
+ return boundingRect.Union(GetBoundingRect(
+ nextCell->GetFirstTerminal(), toCell));
+ }
+
+ boundingRect.Union(nextCell->GetRect());
+ }
+
+ wxFAIL_MSG("Unexpected: toCell is not reachable from the fromCell");
+ return GetBoundingRect(toCell, fromCell);
+ }
+ else
+ {
+ // Combine rest of current container.
+ for ( const wxHtmlCell* nextCell = startCell->GetNext();
+ nextCell;
+ nextCell = nextCell->GetNext() )
+ {
+ boundingRect.Union(nextCell->GetRect());
+ }
+ }
+ }
+
+ wxFAIL_MSG("The cells have no common ancestor");
+ return wxRect();
+}
+
+} // namespace
+
+void wxHtmlWindow::OnFocusEvent(wxFocusEvent& event)
+{
+ event.Skip();
+
+ // Redraw selection, because its background colour depends on
+ // whether the window has keyboard focus or not.
+
+ if ( !m_selection || m_selection->IsEmpty() )
+ return;
+
+ const wxHtmlCell* fromCell = m_selection->GetFromCell();
+ const wxHtmlCell* toCell = m_selection->GetToCell();
+ wxCHECK_RET(fromCell || toCell,
+ "Unexpected: selection is set but cells are not");
+
+ wxRect boundingRect = GetBoundingRect(fromCell, toCell);
+
+ boundingRect = wxRect
+ (
+ CalcScrolledPosition(boundingRect.GetTopLeft()),
+ CalcScrolledPosition(boundingRect.GetBottomRight())
+ );
+
+ RefreshRect(boundingRect);
+}
void wxHtmlWindow::OnSize(wxSizeEvent& event)
@@ -1502,14 +1610,12 @@ void wxHtmlWindow::OnMouseLeave(wxMouseEvent& event)
void wxHtmlWindow::OnKeyUp(wxKeyEvent& event)
{
- if ( IsSelectionEnabled() &&
- (event.GetKeyCode() == 'C' && event.CmdDown()) )
+ if ( IsSelectionEnabled() && event.GetModifiers() == wxMOD_CONTROL &&
+ (event.GetKeyCode() == 'C' || event.GetKeyCode() == WXK_INSERT) )
{
wxClipboardTextEvent evt(wxEVT_TEXT_COPY, GetId());
-
evt.SetEventObject(this);
-
- GetEventHandler()->ProcessEvent(evt);
+ ProcessWindowEvent(evt);
}
else
{
@@ -1656,6 +1762,8 @@ wxBEGIN_EVENT_TABLE(wxHtmlWindow, wxScrolledWindow)
EVT_MOTION(wxHtmlWindow::OnMouseMove)
EVT_PAINT(wxHtmlWindow::OnPaint)
EVT_ERASE_BACKGROUND(wxHtmlWindow::OnEraseBackground)
+ EVT_SET_FOCUS(wxHtmlWindow::OnFocusEvent)
+ EVT_KILL_FOCUS(wxHtmlWindow::OnFocusEvent)
#if wxUSE_CLIPBOARD
EVT_LEFT_DCLICK(wxHtmlWindow::OnDoubleClick)
EVT_ENTER_WINDOW(wxHtmlWindow::OnMouseEnter)