diff options
Diffstat (limited to 'wx+')
-rw-r--r-- | wx+/dc.h | 15 | ||||
-rw-r--r-- | wx+/file_drop.cpp | 3 | ||||
-rw-r--r-- | wx+/grid.cpp | 179 | ||||
-rw-r--r-- | wx+/grid.h | 16 | ||||
-rw-r--r-- | wx+/image_resources.cpp | 2 | ||||
-rw-r--r-- | wx+/image_resources.h | 2 | ||||
-rw-r--r-- | wx+/popup_dlg.cpp | 2 |
7 files changed, 127 insertions, 92 deletions
@@ -39,8 +39,8 @@ void clearArea(wxDC& dc, const wxRect& rect, const wxColor& col) { //wxDC::DrawRectangle() just widens inner area if wxTRANSPARENT_PEN is used! //bonus: wxTRANSPARENT_PEN is about 2x faster than redundantly drawing with col! - wxDCPenChanger dummy (dc, *wxTRANSPARENT_PEN); - wxDCBrushChanger dummy2(dc, col); + wxDCPenChanger areaPen (dc, *wxTRANSPARENT_PEN); + wxDCBrushChanger areaBrush(dc, col); dc.DrawRectangle(rect); } } @@ -51,8 +51,8 @@ inline void drawFilledRectangle(wxDC& dc, wxRect rect, int borderWidth, const wxColor& borderCol, const wxColor& innerCol) { assert(borderCol.IsSolid() && innerCol.IsSolid()); - wxDCPenChanger graphPen (dc, *wxTRANSPARENT_PEN); - wxDCBrushChanger graphBrush(dc, borderCol); + wxDCPenChanger rectPen (dc, *wxTRANSPARENT_PEN); + wxDCBrushChanger rectBrush(dc, borderCol); dc.DrawRectangle(rect); rect.Deflate(borderWidth); //attention, more wxWidgets design mistakes: behavior of wxRect::Deflate depends on object being const/non-const!!! @@ -93,8 +93,11 @@ public: oldRect_ = it->second; wxRect tmp = r; - tmp.Intersect(*oldRect_); //better safe than sorry - dc_.SetClippingRegion(tmp); // + tmp.Intersect(*oldRect_); //better safe than sorry + + assert(!tmp.IsEmpty()); //"setting an empty clipping region is equivalent to DestroyClippingRegion()" + + dc_.SetClippingRegion(tmp); //new clipping region is intersection of given and previously set regions it->second = tmp; } else diff --git a/wx+/file_drop.cpp b/wx+/file_drop.cpp index 42cfbd3d..86db57c1 100644 --- a/wx+/file_drop.cpp +++ b/wx+/file_drop.cpp @@ -49,8 +49,7 @@ private: => switching to wxTextDropTarget won't help (much): we'd get the format mtp://[usb:001,002]/Telefonspeicher/Folder/file.txt instead of - /run/user/1000/gvfs/mtp:host=%5Busb%3A001%2C002%5D/Telefonspeicher/Folder/file.txt - */ + /run/user/1000/gvfs/mtp:host=%5Busb%3A001%2C002%5D/Telefonspeicher/Folder/file.txt */ if (!dropWindow_.IsEnabled()) return false; diff --git a/wx+/grid.cpp b/wx+/grid.cpp index 80c9aaf1..6eb25ac9 100644 --- a/wx+/grid.cpp +++ b/wx+/grid.cpp @@ -99,14 +99,13 @@ wxDEFINE_EVENT(EVENT_GRID_CONTEXT_MENU, GridContextMenuEvent); } //---------------------------------------------------------------------------------------------------------------- -void GridData::renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected) +void GridData::renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected, HoverArea rowHover) { if (enabled) { if (selected) dc.GradientFillLinear(rect, getColorSelectionGradientFrom(), getColorSelectionGradientTo(), wxEAST); - else - clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + //else: clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); -> already the default } else clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); @@ -384,6 +383,9 @@ private: else parent_.HandleOnMouseWheel(event); + onMouseMovement(event); + event.Skip(false); + //if (!sendEventToParent(event)) // event.Skip(); } @@ -462,7 +464,7 @@ public: int bestWidth = 0; for (ptrdiff_t i = rowFrom; i <= rowTo; ++i) - bestWidth = std::max(bestWidth, dc.GetTextExtent(formatRow(i)).GetWidth() + fastFromDIP(2 * ROW_LABEL_BORDER_DIP)); + bestWidth = std::max(bestWidth, dc.GetTextExtent(formatRowNum(i)).GetWidth() + fastFromDIP(2 * ROW_LABEL_BORDER_DIP)); return bestWidth; } @@ -500,7 +502,7 @@ public: } private: - static std::wstring formatRow(size_t row) { return formatNumber(row + 1); } //convert number to std::wstring including thousands separator + static std::wstring formatRowNum(size_t row) { return formatNumber(row + 1); } //convert number to std::wstring including thousands separator bool AcceptsFocus() const override { return false; } @@ -533,7 +535,7 @@ private: wxRect textRect = rect; textRect.Deflate(fastFromDIP(1)); - GridData::drawCellText(dc, textRect, formatRow(row), wxALIGN_CENTRE); + GridData::drawCellText(dc, textRect, formatRowNum(row), wxALIGN_CENTRE); //border lines { @@ -733,8 +735,9 @@ private: } else //notify single label click { + const wxPoint mousePos = GetPosition() + event.GetPosition(); if (const std::optional<ColumnType> colType = refParent().colToType(activeClickOrMove_->getColumnFrom())) - sendEventToParent(GridLabelClickEvent(EVENT_GRID_COL_LABEL_MOUSE_LEFT, *colType)); + sendEventToParent(GridLabelClickEvent(EVENT_GRID_COL_LABEL_MOUSE_LEFT, *colType, mousePos)); } activeClickOrMove_.reset(); } @@ -840,16 +843,18 @@ private: void onMouseRightDown(wxMouseEvent& event) override { + const wxPoint mousePos = GetPosition() + event.GetPosition(); + if (const std::optional<ColAction> action = refParent().clientPosToColumnAction(event.GetPosition())) { if (const std::optional<ColumnType> colType = refParent().colToType(action->col)) - sendEventToParent(GridLabelClickEvent(EVENT_GRID_COL_LABEL_MOUSE_RIGHT, *colType)); //notify right click + sendEventToParent(GridLabelClickEvent(EVENT_GRID_COL_LABEL_MOUSE_RIGHT, *colType, mousePos)); //notify right click else assert(false); } else //notify right click (on free space after last column) if (fillGapAfterColumns) - sendEventToParent(GridLabelClickEvent(EVENT_GRID_COL_LABEL_MOUSE_RIGHT, ColumnType::none)); + sendEventToParent(GridLabelClickEvent(EVENT_GRID_COL_LABEL_MOUSE_RIGHT, ColumnType::none, mousePos)); event.Skip(); } @@ -894,14 +899,16 @@ private: void render(wxDC& dc, const wxRect& rect) override { const bool enabled = renderAsEnabled(*this); - clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); //CONTRACT! expected by GridData::renderRowBackgound()! - dc.SetFont(GetFont()); //harmonize with Grid::getBestColumnSize() + if (auto prov = refParent().getDataProvider()) + { + dc.SetFont(GetFont()); //harmonize with Grid::getBestColumnSize() - wxDCTextColourChanger textColor(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //use user setting for labels + wxDCTextColourChanger textColor(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //use user setting for labels + + std::vector<ColumnWidth> absWidths = refParent().getColWidths(); //resolve stretched widths - std::vector<ColumnWidth> absWidths = refParent().getColWidths(); //resolve stretched widths - { int totalRowWidth = 0; for (const ColumnWidth& cw : absWidths) totalRowWidth += cw.width; @@ -910,36 +917,37 @@ private: if (fillGapAfterColumns) totalRowWidth = std::max(totalRowWidth, GetClientSize().GetWidth()); - if (auto prov = refParent().getDataProvider()) - { - RecursiveDcClipper dummy2(dc, rect); //do NOT draw background on cells outside of invalidated rect invalidating foreground text! + RecursiveDcClipper dummy(dc, rect); //do NOT draw background on cells outside of invalidated rect invalidating foreground text! - wxPoint cellAreaTL(refParent().CalcScrolledPosition(wxPoint(0, 0))); //client coordinates - const int rowHeight = rowLabelWin_.getRowHeight(); - const auto rowRange = rowLabelWin_.getRowsOnClient(rect); //returns range [begin, end) + const wxPoint gridAreaTL(refParent().CalcScrolledPosition(wxPoint(0, 0))); //client coordinates + const int rowHeight = rowLabelWin_.getRowHeight(); + const auto rowRange = rowLabelWin_.getRowsOnClient(rect); //returns range [begin, end) + for (auto row = rowRange.first; row < rowRange.second; ++row) + { //draw background lines - for (auto row = rowRange.first; row < rowRange.second; ++row) - { - const wxRect rowRect(cellAreaTL + wxPoint(0, row * rowHeight), wxSize(totalRowWidth, rowHeight)); - RecursiveDcClipper dummy3(dc, rowRect); - prov->renderRowBackgound(dc, rowRect, row, enabled, drawAsSelected(row)); - } + const wxRect rowRect(gridAreaTL + wxPoint(0, row * rowHeight), wxSize(totalRowWidth, rowHeight)); + const bool drawSelected = drawAsSelected(row); + const HoverArea rowHover = getRowHoverToDraw(row); - //draw single cells, column by column + RecursiveDcClipper dummy2(dc, rowRect); + prov->renderRowBackgound(dc, rowRect, row, enabled, drawSelected, rowHover); + + //draw cells column by column + wxRect cellRect = rowRect; for (const ColumnWidth& cw : absWidths) { - if (cellAreaTL.x > rect.GetRight()) - return; //done - - if (cellAreaTL.x + cw.width > rect.x) - for (auto row = rowRange.first; row < rowRange.second; ++row) - { - const wxRect cellRect(cellAreaTL.x, cellAreaTL.y + row * rowHeight, cw.width, rowHeight); - RecursiveDcClipper dummy3(dc, cellRect); - prov->renderCell(dc, cellRect, row, cw.type, enabled, drawAsSelected(row), getRowHoverToDraw(row)); - } - cellAreaTL.x += cw.width; + cellRect.width = cw.width; + + if (cellRect.x > rect.GetRight()) + break; //done + + if (cellRect.x + cw.width > rect.x) + { + RecursiveDcClipper dummy3(dc, cellRect); + prov->renderCell(dc, cellRect, row, cw.type, enabled, drawSelected, rowHover); + } + cellRect.x += cw.width; } } } @@ -979,15 +987,21 @@ private: { if (auto prov = refParent().getDataProvider()) { - wxClientDC dc(this); - dc.SetFont(GetFont()); - + const wxPoint mousePos = GetPosition() + event.GetPosition(); const ptrdiff_t rowCount = refParent().getRowCount(); const wxPoint absPos = refParent().CalcUnscrolledPosition(event.GetPosition()); const ptrdiff_t row = rowLabelWin_.getRowAtPos(absPos.y); //return -1 for invalid position; >= rowCount if out of range const ColumnPosInfo cpi = refParent().getColumnAtPos(absPos.x); //returns ColumnType::none if no column at x position! - const HoverArea rowHover = 0 <= row && row < rowCount ? prov->getRowMouseHover(dc, row, cpi.colType, cpi.cellRelativePosX, cpi.colWidth) : HoverArea::none; - const wxPoint mousePos = GetPosition() + event.GetPosition(); + const HoverArea rowHover = [&] + { + if (0 <= row && row < rowCount && cpi.colType != ColumnType::none) + { + wxClientDC dc(this); + dc.SetFont(GetFont()); + return prov->getMouseHover(dc, row, cpi.colType, cpi.cellRelativePosX, cpi.colWidth); + } + return HoverArea::none; + }(); //client is interested in all double-clicks, even those outside of the grid! sendEventToParent(GridClickEvent(EVENT_GRID_MOUSE_LEFT_DOUBLE, row, rowHover, mousePos)); @@ -999,17 +1013,23 @@ private: { if (auto prov = refParent().getDataProvider()) { - onMouseMovement(event); //update highlight in obscure cases (e.g. right-click while context menu is open) - - wxClientDC dc(this); - dc.SetFont(GetFont()); + onMouseMovement(event); //update highlight in obscure cases (e.g. right-click while context menu is open) - const ptrdiff_t rowCount = refParent().getRowCount(); - const wxPoint absPos = refParent().CalcUnscrolledPosition(event.GetPosition()); - const ptrdiff_t row = rowLabelWin_.getRowAtPos(absPos.y); //return -1 for invalid position; >= rowCount if out of range - const ColumnPosInfo cpi = refParent().getColumnAtPos(absPos.x); //returns ColumnType::none if no column at x position! - const HoverArea rowHover = 0 <= row && row < rowCount ? prov->getRowMouseHover(dc, row, cpi.colType, cpi.cellRelativePosX, cpi.colWidth) : HoverArea::none; const wxPoint mousePos = GetPosition() + event.GetPosition(); + const ptrdiff_t rowCount = refParent().getRowCount(); + const wxPoint absPos = refParent().CalcUnscrolledPosition(event.GetPosition()); + const ptrdiff_t row = rowLabelWin_.getRowAtPos(absPos.y); //return -1 for invalid position; >= rowCount if out of range + const ColumnPosInfo cpi = refParent().getColumnAtPos(absPos.x); //returns ColumnType::none if no column at x position! + const HoverArea rowHover = [&] + { + if (0 <= row && row < rowCount && cpi.colType != ColumnType::none) + { + wxClientDC dc(this); + dc.SetFont(GetFont()); + return prov->getMouseHover(dc, row, cpi.colType, cpi.cellRelativePosX, cpi.colWidth); + } + return HoverArea::none; + }(); assert(row >= 0); //row < 0 was possible in older wxWidgets: https://github.com/wxWidgets/wxWidgets/commit/2c69d27c0d225d3a331c773da466686153185320#diff-9f11c8f2cb1f734f7c0c1071aba491a5 @@ -1050,7 +1070,7 @@ private: //update mouse highlight (in case it was frozen above) event.SetPosition(ScreenToClient(wxGetMousePosition())); //mouse position may have changed within above callbacks (e.g. context menu was shown)! - onMouseMovement(event); + onMouseMovement(event); } event.Skip(); //allow changing focus } @@ -1077,9 +1097,9 @@ private: } //slight deviation from Explorer: change cursor while dragging mouse! -> unify behavior with shift + direction keys - const ptrdiff_t rowFrom = activeSelection_->getStartRow(); - const ptrdiff_t rowTo = activeSelection_->getCurrentRow(); - const bool positive = activeSelection_->isPositiveSelect(); + const ptrdiff_t rowFrom = activeSelection_->getStartRow(); + const ptrdiff_t rowTo = activeSelection_->getCurrentRow(); + const bool positive = activeSelection_->isPositiveSelect(); const GridClickEvent mouseClick = activeSelection_->getFirstClick(); assert((mouseClick.GetEventType() == EVENT_GRID_MOUSE_RIGHT_DOWN) == event.RightUp()); @@ -1090,29 +1110,34 @@ private: if (mouseClick.GetEventType() == EVENT_GRID_MOUSE_RIGHT_DOWN) sendEventToParent(GridContextMenuEvent(mouseClick.mousePos_)); } - #if 0 if (!event.RightUp()) if (auto prov = refParent().getDataProvider()) { - wxClientDC dc(this); - dc.SetFont(GetFont()); - //this one may point to row which is not in visible area! - const ptrdiff_t rowCount = refParent().getRowCount(); - const wxPoint absPos = refParent().CalcUnscrolledPosition(event.GetPosition()); - const ptrdiff_t row = rowLabelWin_.getRowAtPos(absPos.y); //return -1 for invalid position; >= rowCount if out of range - const ColumnPosInfo cpi = refParent().getColumnAtPos(absPos.x); //returns ColumnType::none if no column at x position! - const HoverArea rowHover = 0 <= row && row < rowCount ? prov->getRowMouseHover(dc, row, cpi.colType, cpi.cellRelativePosX, cpi.colWidth) : HoverArea::none; const wxPoint mousePos = GetPosition() + event.GetPosition(); + const ptrdiff_t rowCount = refParent().getRowCount(); + const wxPoint absPos = refParent().CalcUnscrolledPosition(event.GetPosition()); + const ptrdiff_t row = rowLabelWin_.getRowAtPos(absPos.y); //return -1 for invalid position; >= rowCount if out of range + const ColumnPosInfo cpi = refParent().getColumnAtPos(absPos.x); //returns ColumnType::none if no column at x position! + const HoverArea rowHover = [&] + { + if (0 <= row && row < rowCount && cpi.colType != ColumnType::none) + { + wxClientDC dc(this); + dc.SetFont(GetFont()); + return prov->getMouseHover(dc, row, cpi.colType, cpi.cellRelativePosX, cpi.colWidth); + } + return HoverArea::none; + }(); //notify click event after the range selection! e.g. this makes sure the selection is applied before showing a context menu sendEventToParent(GridClickEvent(EVENT_GRID_MOUSE_LEFT_UP, row, rowHover, mousePos)); } #endif - + //update mouse highlight and tooltip: macOS no mouse movement event is generated after a mouse button click (unlike on Windows) event.SetPosition(ScreenToClient(wxGetMousePosition())); //mouse position may have changed within above callbacks (e.g. context menu was shown)! - onMouseMovement(event); + onMouseMovement(event); event.Skip(); //allow changing focus } @@ -1135,18 +1160,25 @@ private: { if (auto prov = refParent().getDataProvider()) { - wxClientDC dc(this); - dc.SetFont(GetFont()); - const ptrdiff_t rowCount = refParent().getRowCount(); const wxPoint absPos = refParent().CalcUnscrolledPosition(event.GetPosition()); const ptrdiff_t row = rowLabelWin_.getRowAtPos(absPos.y); //return -1 for invalid position; >= rowCount if out of range const ColumnPosInfo cpi = refParent().getColumnAtPos(absPos.x); //returns ColumnType::none if no column at x position! + const HoverArea rowHover = [&] + { + if (0 <= row && row < rowCount && cpi.colType != ColumnType::none) + { + wxClientDC dc(this); + dc.SetFont(GetFont()); + return prov->getMouseHover(dc, row, cpi.colType, cpi.cellRelativePosX, cpi.colWidth); + } + return HoverArea::none; + }(); const std::wstring toolTip = [&] { - if (cpi.colType != ColumnType::none && 0 <= row && row < rowCount) - return prov->getToolTip(row, cpi.colType); + if (0 <= row && row < rowCount && cpi.colType != ColumnType::none) + return prov->getToolTip(row, cpi.colType, rowHover); return std::wstring(); }(); setToolTip(toolTip); //show even during mouse selection! @@ -1154,10 +1186,7 @@ private: if (activeSelection_) activeSelection_->evalMousePos(); //call on both mouse movement + timer event! else - { - const HoverArea rowHover = 0 <= row && row < rowCount ? prov->getRowMouseHover(dc, row, cpi.colType, cpi.cellRelativePosX, cpi.colWidth) : HoverArea::none; updateMouseHover({row, rowHover}); - } } event.Skip(); } @@ -66,17 +66,18 @@ struct GridSelectEvent : public wxEvent GridSelectEvent* Clone() const override { return new GridSelectEvent(*this); } const size_t rowFirst_; //selected range: [rowFirst_, rowLast_) - const size_t rowLast_; - const bool positive_; //"false" when clearing selection! + const size_t rowLast_; // + const bool positive_; //"false" when clearing selection! const std::optional<GridClickEvent> mouseClick_; //filled unless selection was performed via keyboard shortcuts }; struct GridLabelClickEvent : public wxEvent { - GridLabelClickEvent(wxEventType et, ColumnType colType) : wxEvent(0 /*winid*/, et), colType_(colType) {} + GridLabelClickEvent(wxEventType et, ColumnType colType, const wxPoint& mousePos) : wxEvent(0 /*winid*/, et), colType_(colType), mousePos_(mousePos) {} GridLabelClickEvent* Clone() const override { return new GridLabelClickEvent(*this); } const ColumnType colType_; //may be ColumnType::none + const wxPoint mousePos_; //client coordinates }; struct GridColumnResizeEvent : public wxEvent @@ -85,7 +86,7 @@ struct GridColumnResizeEvent : public wxEvent GridColumnResizeEvent* Clone() const override { return new GridColumnResizeEvent(*this); } const ColumnType colType_; - const int offset_; + const int offset_; }; struct GridContextMenuEvent : public wxEvent @@ -109,11 +110,11 @@ public: //cell area: virtual std::wstring getValue(size_t row, ColumnType colType) const = 0; - virtual void renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected); //default implementation + virtual void renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected, HoverArea rowHover); //default implementation virtual void renderCell (wxDC& dc, const wxRect& rect, size_t row, ColumnType colType, bool enabled, bool selected, HoverArea rowHover); virtual int getBestSize (wxDC& dc, size_t row, ColumnType colType); //must correspond to renderCell()! - virtual HoverArea getRowMouseHover (wxDC& dc, size_t row, ColumnType colType, int cellRelativePosX, int cellWidth) { return HoverArea::none; } - virtual std::wstring getToolTip (size_t row, ColumnType colType) const { return std::wstring(); } + virtual HoverArea getMouseHover (wxDC& dc, size_t row, ColumnType colType, int cellRelativePosX, int cellWidth) { return HoverArea::none; } + virtual std::wstring getToolTip (size_t row, ColumnType colType, HoverArea rowHover) { return std::wstring(); } //label area: virtual std::wstring getColumnLabel(ColumnType colType) const = 0; @@ -174,6 +175,7 @@ public: //----------------------------------------------------------------------------- void setColumnLabelHeight(int height); + int getColumnLabelHeight() const { return colLabelHeight_; } void showRowLabel(bool visible); enum ScrollBarStatus diff --git a/wx+/image_resources.cpp b/wx+/image_resources.cpp index b89abe6d..6931e82e 100644 --- a/wx+/image_resources.cpp +++ b/wx+/image_resources.cpp @@ -317,7 +317,7 @@ void zen::imageResourcesInit(const Zstring& zipPath) //throw FileError } -void zen::ImageResourcesCleanup() +void zen::imageResourcesCleanup() { assert(runningOnMainThread()); //wxWidgets is not thread-safe! assert(globalImageBuffer); diff --git a/wx+/image_resources.h b/wx+/image_resources.h index 2ac6f308..6993e6f3 100644 --- a/wx+/image_resources.h +++ b/wx+/image_resources.h @@ -15,7 +15,7 @@ namespace zen { //pass resources .zip file at application startup void imageResourcesInit(const Zstring& zipPath); //throw FileError -void ImageResourcesCleanup(); +void imageResourcesCleanup(); const wxImage& loadImage(const std::string& name, int maxWidth /*optional*/, int maxHeight /*optional*/); const wxImage& loadImage(const std::string& name, int maxSize = -1); diff --git a/wx+/popup_dlg.cpp b/wx+/popup_dlg.cpp index ee682e19..541a787c 100644 --- a/wx+/popup_dlg.cpp +++ b/wx+/popup_dlg.cpp @@ -233,6 +233,8 @@ public: GetSizer()->SetSizeHints(this); //~=Fit() + SetMinSize() Center(); //needs to be re-applied after a dialog size change! + Raise(); //[!] popup may be triggered by ffs_batch job running in the background! + if (m_buttonAccept->IsEnabled()) m_buttonAccept->SetFocus(); else if (m_buttonAccept2->IsEnabled()) |