diff options
Diffstat (limited to 'wx+/grid.cpp')
-rw-r--r-- | wx+/grid.cpp | 102 |
1 files changed, 86 insertions, 16 deletions
diff --git a/wx+/grid.cpp b/wx+/grid.cpp index 89891879..e1208109 100644 --- a/wx+/grid.cpp +++ b/wx+/grid.cpp @@ -16,15 +16,16 @@ #include <zen/tick_count.h> #include <zen/string_tools.h> #include <zen/scope_guard.h> +#include <zen/utf.h> #include "format_unit.h" #ifdef FFS_LINUX #include <gtk/gtk.h> #endif - using namespace zen; + wxColor zen::getColorSelectionGradientFrom() { return wxColor(137, 172, 255); } //blue: H:158 S:255 V:196 wxColor zen::getColorSelectionGradientTo () { return wxColor(225, 234, 255); } // H:158 S:255 V:240 @@ -210,12 +211,55 @@ void GridData::drawCellBackground(wxDC& dc, const wxRect& rect, bool enabled, bo } -void GridData::drawCellText(wxDC& dc, const wxRect& rect, const wxString& text, bool enabled, int alignment) +namespace { - wxDCTextColourChanger dummy(dc, enabled ? dc.GetTextForeground() : wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT)); +#ifdef _MSC_VER +#pragma warning(disable:4428) // VC wrongly issues warning C4428: universal-character-name encountered in source +#endif +const wchar_t ELLIPSIS = L'\u2026'; //... + +template <class Function> inline +wxString getTruncatedText(const wxString& text, Function textFits) +{ + if (textFits(text)) + return text; + + //unlike Windows 7 Explorer, we truncate UTF-16 correctly: e.g. CJK-Ideogramm encodes to TWO wchar_t: utfCvrtTo<wxString>("\xf0\xa4\xbd\x9c"); + size_t low = 0; //number of unicode chars! + size_t high = unicodeLength(text); // + + for (;;) + { + const size_t middle = (low + high) / 2; + wxString candidate(strBegin(text), findUnicodePos(text, middle)); + candidate += ELLIPSIS; + + if (high - low <= 1) + return candidate; + + if (textFits(candidate)) + low = middle; + else + high = middle; + } +} + +void drawTextLabelFitting(wxDC& dc, const wxString& text, const wxRect& rect, int alignment) +{ DcClipper clip(dc, rect); //wxDC::DrawLabel doesn't care about width, WTF? - dc.DrawLabel(text, rect, alignment); + + //truncate large texts and add ellipsis + auto textFits = [&](const wxString& phrase) { return dc.GetTextExtent(phrase).GetWidth() <= rect.GetWidth(); }; + dc.DrawLabel(getTruncatedText(text, textFits), rect, alignment); +} +} + + +void GridData::drawCellText(wxDC& dc, const wxRect& rect, const wxString& text, bool enabled, int alignment) +{ + wxDCTextColourChanger dummy(dc, enabled ? dc.GetTextForeground() : wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT)); + drawTextLabelFitting(dc, text, rect, alignment); } @@ -260,8 +304,8 @@ void GridData::drawColumnLabelBackground(wxDC& dc, const wxRect& rect, bool high void GridData::drawColumnLabelText(wxDC& dc, const wxRect& rect, const wxString& text) { - DcClipper clip(dc, rect); //wxDC::DrawLabel doesn't care about witdh, WTF? - dc.DrawLabel(text, rect, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + wxDCTextColourChanger dummy(dc, *wxBLACK); //accessibility: always set both foreground AND background colors! + drawTextLabelFitting(dc, text, rect, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); } //---------------------------------------------------------------------------------------------------------------- @@ -481,7 +525,7 @@ public: } private: - static wxString formatRow(size_t row) { return toStringSep(row + 1); } //convert number to std::wstring including thousands separator + static wxString formatRow(size_t row) { return toGuiString(row + 1); } //convert number to std::wstring including thousands separator virtual bool AcceptsFocus() const { return false; } @@ -495,7 +539,8 @@ private: wxFont labelFont = GetFont(); labelFont.SetWeight(wxFONTWEIGHT_BOLD); dc.SetFont(labelFont); - dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); + + wxDCTextColourChanger dummy(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //use user setting for labels auto rowRange = getRowsOnClient(rect); //returns range [begin, end) for (auto row = rowRange.first; row < rowRange.second; ++row) @@ -513,6 +558,7 @@ private: { //clearArea(dc, rect, getColorRowLabel()); dc.GradientFillLinear(rect, COLOR_LABEL_GRADIENT_FROM, COLOR_LABEL_GRADIENT_TO, wxWEST); //clear overlapping cells + wxDCTextColourChanger dummy3(dc, *wxBLACK); //accessibility: always set both foreground AND background colors! //label text wxRect textRect = rect; @@ -621,7 +667,8 @@ private: wxFont labelFont = GetFont(); labelFont.SetWeight(wxFONTWEIGHT_BOLD); dc.SetFont(labelFont); - dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); + + wxDCTextColourChanger dummy(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //use user setting for labels const int colLabelHeight = refParent().colLabelHeight; @@ -847,6 +894,10 @@ private: }; //---------------------------------------------------------------------------------------------------------------- +namespace +{ +const wxEventType EVENT_GRID_HAS_SCROLLED = wxNewEventType(); //internal to Grid::MainWin::ScrollWindow() +} //---------------------------------------------------------------------------------------------------------------- class Grid::MainWin : public SubWindow @@ -857,7 +908,10 @@ public: ColLabelWin& colLabelWin) : SubWindow(parent), rowLabelWin_(rowLabelWin), colLabelWin_(colLabelWin), - selectionAnchor(0) {} + selectionAnchor(0) + { + Connect(EVENT_GRID_HAS_SCROLLED, wxCommandEventHandler(MainWin::updateAfterScroll), nullptr, this); + } void makeRowVisible(size_t row) { @@ -915,7 +969,8 @@ private: clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); dc.SetFont(GetFont()); - dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); + + wxDCTextColourChanger dummy(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //use user setting for labels const int rowHeight = rowLabelWin_.getRowHeight(); @@ -938,7 +993,7 @@ private: { //draw background lines { - DcClipper dummy(dc, rect); //solve issues with drawBackground() painting in area outside of rect (which is not also refreshed by renderCell()) -> keep small scope! + DcClipper dummy2(dc, rect); //solve issues with drawBackground() painting in area outside of rect (which is not also refreshed by renderCell()) -> keep small scope! for (int row = rowFirst; row < rowLast; ++row) drawBackground(*prov, dc, wxRect(cellAreaTL + wxPoint(0, row * rowHeight), wxSize(compWidth, rowHeight)), row, compPos); } @@ -992,8 +1047,12 @@ private: { const wxPoint absPos = refParent().CalcUnscrolledPosition(event.GetPosition()); const auto row = rowLabelWin_.getRowAtPos(absPos.y); //return -1 if no row at this position - if (const auto colInfo = refParent().getColumnAtPos(absPos.x)) //returns (column type, compPos) - sendEventNow(GridClickEvent(EVENT_GRID_MOUSE_LEFT_DOUBLE, event, row, colInfo->first, colInfo->second)); + const auto colInfo = refParent().getColumnAtPos(absPos.x); //returns (column type, compPos) + + const ColumnType colType = colInfo ? colInfo->first : DUMMY_COLUMN_TYPE; + const ptrdiff_t compPos = colInfo ? colInfo->second : -1; + //client is interested in all double-clicks, even those outside of the grid! + sendEventNow(GridClickEvent(EVENT_GRID_MOUSE_LEFT_DOUBLE, event, row, colType, compPos)); event.Skip(); } @@ -1070,7 +1129,7 @@ private: const auto colInfo = refParent().getColumnAtPos(absPos.x); //returns optional pair (column type, compPos) const ColumnType colType = colInfo ? colInfo->first : DUMMY_COLUMN_TYPE; //we probably should notify even if colInfo is invalid! - const size_t compPos = colInfo ? colInfo->second : 0; + const ptrdiff_t compPos = colInfo ? colInfo->second : -1; //notify event sendEventNow(GridClickEvent(event.RightUp() ? EVENT_GRID_MOUSE_RIGHT_UP : EVENT_GRID_MOUSE_LEFT_UP, event, row, colType, compPos)); @@ -1361,7 +1420,18 @@ private: rowLabelWin_.ScrollWindow(0, dy, rect); colLabelWin_.ScrollWindow(dx, 0, rect); - refParent().updateWindowSizes(false); //row label width has changed -> do *not* update scrollbars: recursion on wxGTK! + //attention, wxGTK call sequence: wxScrolledWindow::Scroll() -> wxScrolledHelperNative::Scroll() -> wxScrolledHelperNative::DoScroll() + //which *first* calls us, MainWin::ScrollWindow(), and *then* internally updates m_yScrollPosition + //=> we cannot use CalcUnscrolledPosition() here which gives the wrong/outdated value!!! + //=> we need to update asynchronously: + wxCommandEvent scrollEvent(EVENT_GRID_HAS_SCROLLED); + if (wxEvtHandler* evtHandler = GetEventHandler()) + evtHandler->AddPendingEvent(scrollEvent); + } + + void updateAfterScroll(wxCommandEvent&) + { + refParent().updateWindowSizes(false); //row label width has changed -> do *not* update scrollbars: recursion on wxGTK! -> still a problem, now that we're called async?? rowLabelWin_.Update(); //update while dragging scroll thumb } |