summaryrefslogtreecommitdiff
path: root/wx+
diff options
context:
space:
mode:
Diffstat (limited to 'wx+')
-rw-r--r--wx+/file_drop.h113
-rw-r--r--wx+/graph.cpp78
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]
bgstack15