diff options
Diffstat (limited to 'wx+')
-rw-r--r-- | wx+/file_drop.h | 113 | ||||
-rw-r--r-- | wx+/graph.cpp | 78 |
2 files changed, 124 insertions, 67 deletions
diff --git a/wx+/file_drop.h b/wx+/file_drop.h index 664b4387..0e9e92ad 100644 --- a/wx+/file_drop.h +++ b/wx+/file_drop.h @@ -4,29 +4,41 @@ // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** -#ifndef FILE_DROP_H_INCLUDED -#define FILE_DROP_H_INCLUDED +#ifndef FILE_DROP_H_09457802957842560325626 +#define FILE_DROP_H_09457802957842560325626 #include <vector> +#include <functional> +#include <zen/zstring.h> +#include <zen/utf.h> #include <wx/window.h> #include <wx/event.h> #include <wx/dnd.h> +#ifdef ZEN_WIN_VISTA_AND_LATER +#include <zen/win.h> +#endif + + namespace zen { //register simple file drop event (without issue of freezing dialogs and without wxFileDropTarget overdesign) //CAVEAT: a drop target window must not be directly or indirectly contained within a wxStaticBoxSizer until the following wxGTK bug //is fixed. According to wxWidgets release cycles this is expected to be: never http://trac.wxwidgets.org/ticket/2763 -//1. setup a window to emit EVENT_DROP_FILE -void setupFileDrop(wxWindow& wnd); +/* +1. setup a window to emit EVENT_DROP_FILE: + - simple file system paths: setupFileDrop + - any shell paths with validation: setupShellItemDrop + +2. register events: +wnd.Connect (EVENT_DROP_FILE, FileDropEventHandler(MyDlg::OnFilesDropped), nullptr, this); +wnd.Disconnect(EVENT_DROP_FILE, FileDropEventHandler(MyDlg::OnFilesDropped), nullptr, this); -//2. register events: -//wnd.Connect (EVENT_DROP_FILE, FileDropEventHandler(MyDlg::OnFilesDropped), nullptr, this); -//wnd.Disconnect(EVENT_DROP_FILE, FileDropEventHandler(MyDlg::OnFilesDropped), nullptr, this); +3. do something: +void MyDlg::OnFilesDropped(FileDropEvent& event); +*/ -//3. do something: -//void MyDlg::OnFilesDropped(FileDropEvent& event); @@ -46,29 +58,20 @@ wxEventType createNewEventType() } } - //define new event type const wxEventType EVENT_DROP_FILE = impl::createNewEventType(); class FileDropEvent : public wxCommandEvent { public: - FileDropEvent(const std::vector<wxString>& filesDropped, const wxWindow& dropWindow, wxPoint dropPos) : - wxCommandEvent(EVENT_DROP_FILE), - filesDropped_(filesDropped), - dropWindow_(dropWindow), - dropPos_(dropPos) {} + FileDropEvent(const std::vector<Zstring>& filesDropped) : wxCommandEvent(EVENT_DROP_FILE), filesDropped_(filesDropped) {} - wxEvent* Clone() const override { return new FileDropEvent(*this); } - - const std::vector<wxString>& getFiles() const { return filesDropped_; } - const wxWindow& getDropWindow() const { return dropWindow_; } - wxPoint getDropPosition() const { return dropPos_; } //position relative to drop window + const std::vector<Zstring>& getFiles() const { return filesDropped_; } private: - const std::vector<wxString> filesDropped_; - const wxWindow& dropWindow_; - const wxPoint dropPos_; + wxEvent* Clone() const override { return new FileDropEvent(*this); } + + const std::vector<Zstring> filesDropped_; }; typedef void (wxEvtHandler::*FileDropEventFunction)(FileDropEvent&); @@ -77,6 +80,50 @@ typedef void (wxEvtHandler::*FileDropEventFunction)(FileDropEvent&); (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(FileDropEventFunction, &func) + +#ifdef ZEN_WIN_VISTA_AND_LATER +using DragDropValidator = bool (*)(const std::vector<Zstring>& shellItemPaths); //plain static function => no lifetime management needed! +using DragDropConsumer = std::function<void (const std::vector<Zstring>& shellItemPaths)>; + +namespace impl +{ +void registerDragDrop(HWND hwnd, const DragDropValidator& acceptDrop, const DragDropConsumer& onDrop); +void unregisterDragDrop(HWND hwnd); + +class DragDropCleanupWindow : private wxWindow +{ +public: + DragDropCleanupWindow(wxWindow& dropWindow) : wxWindow(&dropWindow, wxID_ANY), dropHwnd(dropWindow.GetHWND()) + { + Hide(); //this is just a dummy window so that its parent can have ownership + Disable(); + } + ~DragDropCleanupWindow() { impl::unregisterDragDrop(dropHwnd); } + +private: + HWND dropHwnd; +}; +} + + +inline +void setupShellItemDrop(wxWindow& dropWindow, const DragDropValidator& acceptDrop) +{ + auto onDrop = [&dropWindow](const std::vector<Zstring>& shellItemPaths) + { + //create a custom event on drop window: execute event after file dropping is completed! (after mouse is released) + if (wxEvtHandler* handler = dropWindow.GetEventHandler()) + handler->AddPendingEvent(FileDropEvent(shellItemPaths)); + }; + + impl::registerDragDrop(static_cast<HWND>(dropWindow.GetHWND()), acceptDrop, onDrop); + + //make sure clean-up is tied to dropWindow life-time: + new impl::DragDropCleanupWindow(dropWindow); //ownership passed to "dropWindow" +} +#endif + + namespace impl { class WindowDropTarget : public wxFileDropTarget @@ -87,11 +134,14 @@ public: private: bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& fileArray) override { - std::vector<wxString> filepaths(fileArray.begin(), fileArray.end()); - if (!filepaths.empty()) - //create a custom event on drop window: execute event after file dropping is completed! (after mouse is released) - if (wxEvtHandler* handler = dropWindow_.GetEventHandler()) - handler->AddPendingEvent(FileDropEvent(filepaths, dropWindow_, wxPoint(x, y))); + //wxPoint clientDropPos(x, y) + std::vector<Zstring> filePaths; + for (const wxString& file : fileArray) + filePaths.push_back(utfCvrtTo<Zstring>(file)); + + //create a custom event on drop window: execute event after file dropping is completed! (after mouse is released) + if (wxEvtHandler* handler = dropWindow_.GetEventHandler()) + handler->AddPendingEvent(FileDropEvent(filePaths)); return true; } @@ -101,10 +151,7 @@ private: inline -void setupFileDrop(wxWindow& wnd) -{ - wnd.SetDropTarget(new impl::WindowDropTarget(wnd)); //takes ownership -} +void setupFileDrop(wxWindow& wnd) { wnd.SetDropTarget(new impl::WindowDropTarget(wnd)); /*takes ownership*/ } } -#endif // FILE_DROP_H_INCLUDED +#endif //FILE_DROP_H_09457802957842560325626 diff --git a/wx+/graph.cpp b/wx+/graph.cpp index cc844144..3ab045b7 100644 --- a/wx+/graph.cpp +++ b/wx+/graph.cpp @@ -109,31 +109,41 @@ private: //enlarge value range to display to a multiple of a "useful" block size -void widenRange(double& valMin, double& valMax, //in/out - int& blockCount, //out - int graphAreaSize, //in pixel - int optimalBlockSizePx, // - const LabelFormatter& labelFmt) +//returns block cound +int widenRange(double& valMin, double& valMax, //in/out + int graphAreaSize, //in pixel + int optimalBlockSizePx, // + const LabelFormatter& labelFmt) { - if (graphAreaSize > 0) - { - double valRangePerBlock = (valMax - valMin) * optimalBlockSizePx / graphAreaSize; //proposal - valRangePerBlock = labelFmt.getOptimalBlockSize(valRangePerBlock); - if (numeric::isNull(valRangePerBlock)) //handle valMin == valMax - valRangePerBlock = 1; - warn_static("/| arbitrary!?") - - int blockMin = std::floor(valMin / valRangePerBlock); - int blockMax = std::ceil (valMax / valRangePerBlock); - if (blockMin == blockMax) //handle valMin == valMax == integer - ++blockMax; - - valMin = blockMin * valRangePerBlock; - valMax = blockMax * valRangePerBlock; - blockCount = blockMax - blockMin; - return; - } - blockCount = 0; + if (graphAreaSize <= 0) return 0; + + const double minValRangePerBlock = (valMax - valMin) / graphAreaSize; + const double proposedValRangePerBlock = (valMax - valMin) * optimalBlockSizePx / graphAreaSize; + double valRangePerBlock = labelFmt.getOptimalBlockSize(proposedValRangePerBlock); + assert(numeric::isNull(proposedValRangePerBlock) || valRangePerBlock > minValRangePerBlock); + + if (numeric::isNull(valRangePerBlock)) //valMin == valMax or strange "optimal block size" + return 1; + + //don't allow sub-pixel blocks! => avoid erroneously high GDI render work load! + if (valRangePerBlock < minValRangePerBlock) + valRangePerBlock = std::ceil(minValRangePerBlock / valRangePerBlock) * valRangePerBlock; + + double blockMin = std::floor(valMin / valRangePerBlock); //store as double, not int: truncation possible, e.g. if valRangePerBlock == 1 + double blockMax = std::ceil (valMax / valRangePerBlock); // + int blockCount = numeric::round(blockMax - blockMin); + assert(blockCount >= 0); + + //handle valMin == valMax == integer + if (blockCount <= 0) + { + ++blockMax; + blockCount = 1; + } + + valMin = blockMin * valRangePerBlock; + valMax = blockMax * valRangePerBlock; + return blockCount; } @@ -591,16 +601,17 @@ void Graph2D::render(wxDC& dc) const maxX = std::max(maxX, rangeX.second); } + const wxSize minimalBlockSizePx = dc.GetTextExtent(L"00"); + if (minX <= maxX && maxX - minX < std::numeric_limits<double>::infinity()) //valid x-range { int blockCountX = 0; //enlarge minX, maxX to a multiple of a "useful" block size if (attr.labelposX != X_LABEL_NONE && attr.labelFmtX.get()) - widenRange(minX, maxX, //in/out - blockCountX, //out - graphArea.width, - dc.GetTextExtent(L"100000000000000").GetWidth(), - *attr.labelFmtX); + blockCountX = widenRange(minX, maxX, //in/out + graphArea.width, + minimalBlockSizePx.GetWidth() * 7, + *attr.labelFmtX); //get raw values + detect y value range double minY = attr.minYauto ? std::numeric_limits<double>::infinity() : attr.minY; //automatic: ensure values are initialized by first curve @@ -636,11 +647,10 @@ void Graph2D::render(wxDC& dc) const int blockCountY = 0; //enlarge minY, maxY to a multiple of a "useful" block size if (attr.labelposY != Y_LABEL_NONE && attr.labelFmtY.get()) - widenRange(minY, maxY, //in/out - blockCountY, //out - graphArea.height, - 3 * dc.GetTextExtent(L"1").GetHeight(), - *attr.labelFmtY); + blockCountY = widenRange(minY, maxY, //in/out + graphArea.height, + minimalBlockSizePx.GetHeight() * 3, + *attr.labelFmtY); if (graphArea.width <= 1 || graphArea.height <= 1) return; const ConvertCoord cvrtX(minX, maxX, graphArea.width - 1); //map [minX, maxX] to [0, pixelWidth - 1] |