summaryrefslogtreecommitdiff
path: root/wx+
diff options
context:
space:
mode:
Diffstat (limited to 'wx+')
-rw-r--r--wx+/choice_enum.h20
-rw-r--r--wx+/file_drop.h5
-rw-r--r--wx+/font_size.h68
-rw-r--r--wx+/graph.cpp10
-rw-r--r--wx+/graph.h14
-rw-r--r--wx+/grid.cpp137
-rw-r--r--wx+/grid.h21
-rw-r--r--wx+/image_resources.cpp119
-rw-r--r--wx+/image_resources.h22
-rw-r--r--wx+/popup_dlg.cpp279
-rw-r--r--wx+/popup_dlg.h91
-rw-r--r--wx+/popup_dlg_generated.cpp91
-rw-r--r--wx+/popup_dlg_generated.h71
-rw-r--r--wx+/shell_execute.h115
-rw-r--r--wx+/tooltip.cpp21
-rw-r--r--wx+/tooltip.h4
16 files changed, 868 insertions, 220 deletions
diff --git a/wx+/choice_enum.h b/wx+/choice_enum.h
index f780af87..e06931d5 100644
--- a/wx+/choice_enum.h
+++ b/wx+/choice_enum.h
@@ -44,7 +44,7 @@ struct EnumDescrList
descrList.push_back(std::make_pair(value, std::make_pair(text, tooltip)));
return *this;
}
- typedef std::vector<std::pair<Enum, std::pair<wxString, wxString> > > DescrList;
+ typedef std::vector<std::pair<Enum, std::pair<wxString, wxString>>> DescrList;
DescrList descrList;
};
template <class Enum> void setEnumVal(const EnumDescrList<Enum>& mapping, wxChoice& ctrl, Enum value);
@@ -71,15 +71,15 @@ void setEnumVal(const EnumDescrList<Enum>& mapping, wxChoice& ctrl, Enum value)
ctrl.Clear();
int selectedPos = 0;
- for (typename EnumDescrList<Enum>::DescrList::const_iterator i = mapping.descrList.begin(); i != mapping.descrList.end(); ++i)
+ for (auto it = mapping.descrList.begin(); it != mapping.descrList.end(); ++it)
{
- ctrl.Append(i->second.first);
- if (i->first == value)
+ ctrl.Append(it->second.first);
+ if (it->first == value)
{
- selectedPos = i - mapping.descrList.begin();
+ selectedPos = it - mapping.descrList.begin();
- if (!i->second.second.empty())
- ctrl.SetToolTip(i->second.second);
+ if (!it->second.second.empty())
+ ctrl.SetToolTip(it->second.second);
}
}
@@ -104,9 +104,9 @@ template <class Enum> void updateTooltipEnumVal(const EnumDescrList<Enum>& mappi
{
const Enum value = getEnumVal(mapping, ctrl);
- for (typename EnumDescrList<Enum>::DescrList::const_iterator i = mapping.descrList.begin(); i != mapping.descrList.end(); ++i)
- if (i->first == value)
- ctrl.SetToolTip(i->second.second);
+ for (const auto& item : mapping.descrList)
+ if (item.first == value)
+ ctrl.SetToolTip(item.second.second);
}
}
diff --git a/wx+/file_drop.h b/wx+/file_drop.h
index fb56c5d9..1cc24ebd 100644
--- a/wx+/file_drop.h
+++ b/wx+/file_drop.h
@@ -97,12 +97,9 @@ private:
{
std::vector<wxString> filenames(fileArray.begin(), fileArray.end());
if (!filenames.empty())
- {
//create a custom event on drop window: execute event after file dropping is completed! (after mouse is released)
- FileDropEvent evt(filenames, dropWindow_, wxPoint(x, y));
if (wxEvtHandler* handler = dropWindow_.GetEventHandler())
- handler->AddPendingEvent(evt);
- }
+ handler->AddPendingEvent(FileDropEvent(filenames, dropWindow_, wxPoint(x, y)));
return true;
}
diff --git a/wx+/font_size.h b/wx+/font_size.h
index 773be928..7bfc62fc 100644
--- a/wx+/font_size.h
+++ b/wx+/font_size.h
@@ -9,16 +9,78 @@
#include <zen/basic_math.h>
#include <wx/window.h>
+#ifdef ZEN_WIN
+#include <zen/dll.h>
+#include <Uxtheme.h>
+#include <vsstyle.h> //TEXT_MAININSTRUCTION
+#include <vssym32.h> //TMT_COLOR
+#endif
namespace zen
{
//set portable font size in multiples of the operating system's default font size
+void setRelativeFontSize(wxWindow& control, double factor);
+void setMainInstructionFont(wxWindow& control); //following Windows/Gnome/OS X guidelines
+
+
+
+
+
+
+
+
+
+
+
+
+//###################### implementation #####################
inline
void setRelativeFontSize(wxWindow& control, double factor)
{
- wxFont fnt = control.GetFont();
- fnt.SetPointSize(numeric::round(wxNORMAL_FONT->GetPointSize() * factor));
- control.SetFont(fnt);
+ wxFont font = control.GetFont();
+ font.SetPointSize(numeric::round(wxNORMAL_FONT->GetPointSize() * factor));
+ control.SetFont(font);
+};
+
+
+inline
+void setMainInstructionFont(wxWindow& control)
+{
+ wxFont font = control.GetFont();
+#ifdef ZEN_WIN //http://msdn.microsoft.com/de-DE/library/windows/desktop/aa974176#fonts
+ font.SetPointSize(numeric::round(wxNORMAL_FONT->GetPointSize() * 4.0 / 3));
+
+ //get main instruction color: don't hard-code, respect accessibility!
+ typedef HTHEME (WINAPI* OpenThemeDataFun )(HWND hwnd, LPCWSTR pszClassList);
+ typedef HRESULT (WINAPI* CloseThemeDataFun)(HTHEME hTheme);
+ typedef HRESULT (WINAPI* GetThemeColorFun )(HTHEME hTheme, int iPartId, int iStateId, int iPropId, COLORREF *pColor);
+
+ const SysDllFun<OpenThemeDataFun> openThemeData (L"UxTheme.dll", "OpenThemeData"); //available with Windows XP and later
+ const SysDllFun<CloseThemeDataFun> closeThemeData(L"UxTheme.dll", "CloseThemeData");
+ const SysDllFun<GetThemeColorFun> getThemeColor (L"UxTheme.dll", "GetThemeColor");
+ if (openThemeData && closeThemeData && getThemeColor)
+ if (HTHEME hTheme = openThemeData(NULL, //__in HWND hwnd,
+ L"TEXTSTYLE")) //__in LPCWSTR pszClassList
+ {
+ ZEN_ON_SCOPE_EXIT(closeThemeData(hTheme));
+
+ COLORREF cr = {};
+ if (getThemeColor(hTheme, //_In_ HTHEME hTheme,
+ TEXT_MAININSTRUCTION, // _In_ int iPartId,
+ 0, // _In_ int iStateId,
+ TMT_TEXTCOLOR, // _In_ int iPropId,
+ &cr) == S_OK) // _Out_ COLORREF *pColor
+ control.SetForegroundColour(wxColour(cr));
+ }
+
+#elif defined ZEN_LINUX //https://developer.gnome.org/hig-book/3.2/hig-book.html#alert-text
+ font.SetPointSize(numeric::round(wxNORMAL_FONT->GetPointSize() * 12.0 / 11));
+ font.SetWeight(wxFONTWEIGHT_BOLD);
+
+#elif defined ZEN_MAC //https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/AppleHIGuidelines/Windows/Windows.html#//apple_ref/doc/uid/20000961-TP10
+ font.SetWeight(wxFONTWEIGHT_BOLD);
+#endif
+ control.SetFont(font);
};
}
diff --git a/wx+/graph.cpp b/wx+/graph.cpp
index 29ec4f36..2f5b3775 100644
--- a/wx+/graph.cpp
+++ b/wx+/graph.cpp
@@ -137,7 +137,7 @@ void drawXLabel(wxDC& dc, double xMin, double xMax, int blockCount, const Conver
if (blockCount <= 0)
return;
- wxDCPenChanger dummy(dc, wxPen(wxColor(192, 192, 192))); //light grey
+ wxDCPenChanger dummy(dc, wxPen(wxColor(192, 192, 192))); //light grey => not accessible! but no big deal...
wxDCTextColourChanger dummy2(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //use user setting for labels
const double valRangePerBlock = (xMax - xMin) / blockCount;
@@ -165,7 +165,7 @@ void drawYLabel(wxDC& dc, double yMin, double yMax, int blockCount, const Conver
if (blockCount <= 0)
return;
- wxDCPenChanger dummy(dc, wxPen(wxColor(192, 192, 192))); //light grey
+ wxDCPenChanger dummy(dc, wxPen(wxColor(192, 192, 192))); //light grey => not accessible! but no big deal...
wxDCTextColourChanger dummy2(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //use user setting for labels
const double valRangePerBlock = (yMax - yMin) / blockCount;
@@ -555,8 +555,10 @@ void Graph2D::render(wxDC& dc) const
{
//paint graph background (excluding label area)
- wxDCPenChanger dummy (dc, wxColour(130, 135, 144)); //medium grey, the same Win7 uses for other frame borders
- wxDCBrushChanger dummy2(dc, *wxWHITE); //accessibility: we have to set both back- and foreground colors or none at all!
+ wxDCPenChanger dummy (dc, wxColour(130, 135, 144)); //medium grey, the same Win7 uses for other frame borders => not accessible! but no big deal...
+ wxDCBrushChanger dummy2(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
+ //accessibility: consider system text and background colors; small drawback: color of graphs is NOT connected to the background! => responsibility of client to use correct colors
+
dc.DrawRectangle(graphArea);
graphArea.Deflate(1, 1); //attention more wxWidgets design mistakes: behavior of wxRect::Deflate depends on object being const/non-const!!!
}
diff --git a/wx+/graph.h b/wx+/graph.h
index a752959b..84aa56cf 100644
--- a/wx+/graph.h
+++ b/wx+/graph.h
@@ -54,7 +54,7 @@ struct ContinuousCurveData : public CurveData
virtual double getValue(double x) const = 0;
private:
- virtual void getPoints(double minX, double maxX, int pixelWidth, std::vector<CurvePoint>& points) const final;
+ virtual void getPoints(double minX, double maxX, int pixelWidth, std::vector<CurvePoint>& points) const override;
};
struct SparseCurveData : public CurveData
@@ -65,7 +65,7 @@ struct SparseCurveData : public CurveData
virtual Opt<CurvePoint> getGreaterEq(double x) const = 0;
private:
- virtual void getPoints(double minX, double maxX, int pixelWidth, std::vector<CurvePoint>& points) const final;
+ virtual void getPoints(double minX, double maxX, int pixelWidth, std::vector<CurvePoint>& points) const override;
bool addSteps_;
};
@@ -75,9 +75,9 @@ struct ArrayCurveData : public SparseCurveData
virtual size_t getSize() const = 0;
private:
- virtual std::pair<double, double> getRangeX() const final { const size_t sz = getSize(); return std::make_pair(0.0, sz == 0 ? 0.0 : sz - 1.0); }
+ virtual std::pair<double, double> getRangeX() const override { const size_t sz = getSize(); return std::make_pair(0.0, sz == 0 ? 0.0 : sz - 1.0); }
- virtual Opt<CurvePoint> getLessEq(double x) const final
+ virtual Opt<CurvePoint> getLessEq(double x) const override
{
const size_t sz = getSize();
const size_t pos = std::min<ptrdiff_t>(std::floor(x), sz - 1); //[!] expect unsigned underflow if empty!
@@ -86,7 +86,7 @@ private:
return NoValue();
}
- virtual Opt<CurvePoint> getGreaterEq(double x) const final
+ virtual Opt<CurvePoint> getGreaterEq(double x) const override
{
const size_t pos = std::max<ptrdiff_t>(std::ceil(x), 0); //[!] use std::max with signed type!
if (pos < getSize())
@@ -99,8 +99,8 @@ struct VectorCurveData : public ArrayCurveData
{
std::vector<double>& refData() { return data; }
private:
- virtual double getValue(size_t pos) const final { return pos < data.size() ? data[pos] : 0; }
- virtual size_t getSize() const final { return data.size(); }
+ virtual double getValue(size_t pos) const override { return pos < data.size() ? data[pos] : 0; }
+ virtual size_t getSize() const override { return data.size(); }
std::vector<double> data;
};
diff --git a/wx+/grid.cpp b/wx+/grid.cpp
index c9dfbbe9..184302bf 100644
--- a/wx+/grid.cpp
+++ b/wx+/grid.cpp
@@ -36,30 +36,25 @@ void zen::clearArea(wxDC& dc, const wxRect& rect, const wxColor& col)
dc.DrawRectangle(rect);
}
+const int GridData::COLUMN_GAP_LEFT = 4;
+
namespace
{
//------------ Grid Constants --------------------------------
const double MOUSE_DRAG_ACCELERATION = 1.5; //unit: [rows / (pixel * sec)] -> same value as Explorer!
-const int DEFAULT_COL_LABEL_HEIGHT = 24;
-const int COLUMN_BORDER_LEFT = 4; //for left-aligned text
-const int COLUMN_LABEL_BORDER = COLUMN_BORDER_LEFT;
+const int DEFAULT_COL_LABEL_BORDER = 6; //top + bottom border in addition to label height
+const int COLUMN_LABEL_BORDER = GridData::COLUMN_GAP_LEFT;
const int COLUMN_MOVE_DELAY = 5; //unit: [pixel] (from Explorer)
const int COLUMN_MIN_WIDTH = 40; //only honored when resizing manually!
const int ROW_LABEL_BORDER = 3;
const int COLUMN_RESIZE_TOLERANCE = 6; //unit [pixel]
const int COLUMN_FILL_GAP_TOLERANCE = 10; //enlarge column to fill full width when resizing
-const wxColor COLOR_SELECTION_GRADIENT_NO_FOCUS_FROM = wxColour(192, 192, 192); //light grey wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
-const wxColor COLOR_SELECTION_GRADIENT_NO_FOCUS_TO = wxColour(228, 228, 228);
-
-const wxColor COLOR_LABEL_GRADIENT_FROM = wxColour(200, 200, 200); //light grey
-const wxColor COLOR_LABEL_GRADIENT_TO = *wxWHITE;
+const wxColor COLOR_LABEL_GRADIENT_FROM = *wxWHITE;
+const wxColor COLOR_LABEL_GRADIENT_TO = wxColour(200, 200, 200); //light grey
-const wxColor COLOR_LABEL_GRADIENT_FROM_FOCUS = getColorSelectionGradientFrom();
-const wxColor COLOR_LABEL_GRADIENT_TO_FOCUS = COLOR_LABEL_GRADIENT_TO;
-
-//wxColor getColorRowLabel () { return wxPanel::GetClassDefaultAttributes ().colBg; } //
-wxColor getColorMainWinBackground() { return wxListBox::GetClassDefaultAttributes().colBg; } //cannot be initialized statically on wxGTK!
+const wxColor COLOR_LABEL_GRADIENT_FROM_FOCUS = COLOR_LABEL_GRADIENT_FROM;
+const wxColor COLOR_LABEL_GRADIENT_TO_FOCUS = getColorSelectionGradientFrom();
const wxColor colorGridLine = wxColour(192, 192, 192); //light grey
}
@@ -76,25 +71,25 @@ const wxEventType zen::EVENT_GRID_MOUSE_RIGHT_UP = wxNewEventType();
const wxEventType zen::EVENT_GRID_SELECT_RANGE = wxNewEventType();
//----------------------------------------------------------------------------------------------------------------
-void GridData::renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected, bool hasFocus)
+void GridData::renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected)
{
- drawCellBackground(dc, rect, enabled, selected, hasFocus, getColorMainWinBackground());
+ drawCellBackground(dc, rect, enabled, selected, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
}
-void GridData::renderCell(Grid& grid, wxDC& dc, const wxRect& rect, size_t row, ColumnType colType)
+void GridData::renderCell(wxDC& dc, const wxRect& rect, size_t row, ColumnType colType, bool selected)
{
wxRect rectTmp = drawCellBorder(dc, rect);
- rectTmp.x += COLUMN_BORDER_LEFT;
- rectTmp.width -= COLUMN_BORDER_LEFT;
+ rectTmp.x += COLUMN_GAP_LEFT;
+ rectTmp.width -= COLUMN_GAP_LEFT;
drawCellText(dc, rectTmp, getValue(row, colType), true);
}
int GridData::getBestSize(wxDC& dc, size_t row, ColumnType colType)
{
- return dc.GetTextExtent(getValue(row, colType)).GetWidth() + 2 * COLUMN_BORDER_LEFT; //some border on left and right side
+ return dc.GetTextExtent(getValue(row, colType)).GetWidth() + 2 * COLUMN_GAP_LEFT + 1; //gap on left and right side + border
}
@@ -108,17 +103,12 @@ wxRect GridData::drawCellBorder(wxDC& dc, const wxRect& rect) //returns remainin
}
-void GridData::drawCellBackground(wxDC& dc, const wxRect& rect, bool enabled, bool selected, bool hasFocus, const wxColor& backgroundColor)
+void GridData::drawCellBackground(wxDC& dc, const wxRect& rect, bool enabled, bool selected, const wxColor& backgroundColor)
{
if (enabled)
{
if (selected)
- {
- //if (hasFocus)
dc.GradientFillLinear(rect, getColorSelectionGradientFrom(), getColorSelectionGradientTo(), wxEAST);
- //else -> doesn't look too good...
- // dc.GradientFillLinear(rect, COLOR_SELECTION_GRADIENT_NO_FOCUS_FROM, COLOR_SELECTION_GRADIENT_NO_FOCUS_TO, wxEAST);
- }
else
clearArea(dc, rect, backgroundColor);
}
@@ -193,8 +183,8 @@ void GridData::renderColumnLabel(Grid& grid, wxDC& dc, const wxRect& rect, Colum
wxRect rectTmp = drawColumnLabelBorder(dc, rect);
drawColumnLabelBackground(dc, rectTmp, highlighted);
- rectTmp.x += COLUMN_BORDER_LEFT;
- rectTmp.width -= COLUMN_BORDER_LEFT;
+ rectTmp.x += COLUMN_GAP_LEFT;
+ rectTmp.width -= COLUMN_GAP_LEFT;
drawColumnLabelText(dc, rectTmp, getColumnLabel(colType));
}
@@ -210,7 +200,7 @@ wxRect GridData::drawColumnLabelBorder(wxDC& dc, const wxRect& rect) //returns r
//draw border (with gradient)
{
wxDCPenChanger dummy(dc, wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID));
- dc.GradientFillLinear(wxRect(rect.GetTopRight(), rect.GetBottomRight()), dc.GetPen().GetColour(), COLOR_LABEL_GRADIENT_TO, wxNORTH);
+ dc.GradientFillLinear(wxRect(rect.GetTopRight(), rect.GetBottomRight()), COLOR_LABEL_GRADIENT_FROM, dc.GetPen().GetColour(), wxSOUTH);
dc.DrawLine(rect.GetBottomLeft(), rect.GetBottomRight() + wxPoint(1, 0));
}
@@ -221,9 +211,9 @@ wxRect GridData::drawColumnLabelBorder(wxDC& dc, const wxRect& rect) //returns r
void GridData::drawColumnLabelBackground(wxDC& dc, const wxRect& rect, bool highlighted)
{
if (highlighted)
- dc.GradientFillLinear(rect, COLOR_LABEL_GRADIENT_FROM_FOCUS, COLOR_LABEL_GRADIENT_TO_FOCUS, wxNORTH);
+ dc.GradientFillLinear(rect, COLOR_LABEL_GRADIENT_FROM_FOCUS, COLOR_LABEL_GRADIENT_TO_FOCUS, wxSOUTH);
else //regular background gradient
- dc.GradientFillLinear(rect, COLOR_LABEL_GRADIENT_FROM, COLOR_LABEL_GRADIENT_TO, wxNORTH); //clear overlapping cells
+ dc.GradientFillLinear(rect, COLOR_LABEL_GRADIENT_FROM, COLOR_LABEL_GRADIENT_TO, wxSOUTH); //clear overlapping cells
}
@@ -386,17 +376,17 @@ private:
{
const wxRect& clientRect = GetClientRect();
- dc.GradientFillLinear(clientRect, COLOR_LABEL_GRADIENT_FROM, COLOR_LABEL_GRADIENT_TO, wxNORTH);
+ dc.GradientFillLinear(clientRect, COLOR_LABEL_GRADIENT_FROM, COLOR_LABEL_GRADIENT_TO, wxSOUTH);
dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID));
{
- wxDCPenChanger dummy(dc, COLOR_LABEL_GRADIENT_TO);
+ wxDCPenChanger dummy(dc, COLOR_LABEL_GRADIENT_FROM);
dc.DrawLine(clientRect.GetTopLeft(), clientRect.GetTopRight());
}
- dc.GradientFillLinear(wxRect(clientRect.GetBottomLeft (), clientRect.GetTopLeft ()), dc.GetPen().GetColour(), COLOR_LABEL_GRADIENT_TO, wxNORTH);
- dc.GradientFillLinear(wxRect(clientRect.GetBottomRight(), clientRect.GetTopRight()), dc.GetPen().GetColour(), COLOR_LABEL_GRADIENT_TO, wxNORTH);
+ dc.GradientFillLinear(wxRect(clientRect.GetBottomLeft (), clientRect.GetTopLeft ()), COLOR_LABEL_GRADIENT_FROM, dc.GetPen().GetColour(), wxSOUTH);
+ dc.GradientFillLinear(wxRect(clientRect.GetBottomRight(), clientRect.GetTopRight()), COLOR_LABEL_GRADIENT_FROM, dc.GetPen().GetColour(), wxSOUTH);
dc.DrawLine(clientRect.GetBottomLeft(), clientRect.GetBottomRight());
@@ -492,7 +482,7 @@ private:
(Similar problem on Win 7: e.g. directly click sync button without comparing first)
*/
if (IsThisEnabled())
- clearArea(dc, rect, getColorMainWinBackground());
+ clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
else
clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
@@ -515,7 +505,7 @@ private:
void drawRowLabel(wxDC& dc, const wxRect& rect, size_t row)
{
//clearArea(dc, rect, getColorRowLabel());
- dc.GradientFillLinear(rect, COLOR_LABEL_GRADIENT_FROM, COLOR_LABEL_GRADIENT_TO, wxWEST); //clear overlapping cells
+ dc.GradientFillLinear(rect, COLOR_LABEL_GRADIENT_FROM, COLOR_LABEL_GRADIENT_TO, wxEAST); //clear overlapping cells
wxDCTextColourChanger dummy3(dc, *wxBLACK); //accessibility: always set both foreground AND background colors!
//label text
@@ -620,10 +610,11 @@ private:
virtual void render(wxDC& dc, const wxRect& rect)
{
if (IsThisEnabled())
- clearArea(dc, rect, getColorMainWinBackground());
+ clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
else
clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
+ //coordinate with "colLabelHeight" in Grid constructor:
wxFont labelFont = GetFont();
labelFont.SetWeight(wxFONTWEIGHT_BOLD);
dc.SetFont(labelFont);
@@ -666,9 +657,9 @@ private:
if (activeMove && activeMove->isRealMove() && activeMove->getComponentPos() == compPos)
{
if (col + 1 == activeMove->refColumnTo()) //handle pos 1, 2, .. up to "at end" position
- dc.GradientFillLinear(wxRect(rect.GetTopRight(), rect.GetBottomRight() + wxPoint(-2, 0)), *wxBLUE, COLOR_LABEL_GRADIENT_TO, wxNORTH);
+ dc.GradientFillLinear(wxRect(rect.GetTopRight(), rect.GetBottomRight() + wxPoint(-2, 0)), COLOR_LABEL_GRADIENT_FROM, *wxBLUE, wxSOUTH);
else if (col == activeMove->refColumnTo() && col == 0) //pos 0
- dc.GradientFillLinear(wxRect(rect.GetTopLeft(), rect.GetBottomLeft() + wxPoint(2, 0)), *wxBLUE, COLOR_LABEL_GRADIENT_TO, wxNORTH);
+ dc.GradientFillLinear(wxRect(rect.GetTopLeft(), rect.GetBottomLeft() + wxPoint(2, 0)), COLOR_LABEL_GRADIENT_FROM, *wxBLUE, wxSOUTH);
}
}
}
@@ -914,7 +905,7 @@ private:
virtual void render(wxDC& dc, const wxRect& rect)
{
if (IsThisEnabled())
- clearArea(dc, rect, getColorMainWinBackground());
+ clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
else
clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
@@ -944,10 +935,12 @@ private:
if (auto prov = refParent().getDataProvider(compPos))
{
//draw background lines
+ for (int row = rowFirst; row < rowLast; ++row)
{
- RecursiveDcClipper 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);
+ const wxRect rowRect(cellAreaTL + wxPoint(0, row * rowHeight), wxSize(compWidth, rowHeight));
+ RecursiveDcClipper dummy2(dc, rowRect); //solve issues with drawBackground() painting in area outside of rect
+ //(which is not also refreshed by renderCell()) -> keep small scope!
+ prov->renderRowBackgound(dc, rowRect, row, refParent().IsThisEnabled(), drawAsSelected(row, compPos));
}
//draw single cells, column by column
@@ -959,9 +952,10 @@ private:
if (cellAreaTL.x + cw.width_ > rect.x)
for (int row = rowFirst; row < rowLast; ++row)
{
- const wxRect& cellRect = wxRect(cellAreaTL.x, cellAreaTL.y + row * rowHeight, cw.width_, rowHeight);
+ const wxRect cellRect(cellAreaTL.x, cellAreaTL.y + row * rowHeight, cw.width_, rowHeight);
RecursiveDcClipper clip(dc, cellRect);
- prov->renderCell(refParent(), dc, cellRect, row, cw.type_);
+
+ prov->renderCell(dc, cellRect, row, cw.type_, drawAsSelected(row, compPos));
}
cellAreaTL.x += cw.width_;
}
@@ -971,21 +965,17 @@ private:
}
}
- void drawBackground(GridData& prov, wxDC& dc, const wxRect& rect, size_t row, size_t compPos)
+ bool drawAsSelected(size_t row, size_t compPos) const
{
- Grid& grid = refParent();
- //check if user is currently selecting with mouse
- bool drawSelection = grid.isSelected(row, compPos);
- if (activeSelection)
+ if (activeSelection) //check if user is currently selecting with mouse
{
const size_t rowFrom = std::min(activeSelection->getStartRow(), activeSelection->getCurrentRow());
const size_t rowTo = std::max(activeSelection->getStartRow(), activeSelection->getCurrentRow());
if (compPos == activeSelection->getComponentPos() && rowFrom <= row && row <= rowTo)
- drawSelection = activeSelection->isPositiveSelect(); //overwrite default
+ return activeSelection->isPositiveSelect(); //overwrite default
}
-
- prov.renderRowBackgound(dc, rect, row, grid.IsThisEnabled(), drawSelection, wxWindow::FindFocus() == &grid.getMainWin());
+ return refParent().isSelected(row, compPos);
}
virtual void onMouseLeftDown (wxMouseEvent& event) { onMouseDown(event); }
@@ -1423,20 +1413,28 @@ Grid::Grid(wxWindow* parent,
const wxString& name) : wxScrolledWindow(parent, id, pos, size, style | wxWANTS_CHARS, name),
showScrollbarX(SB_SHOW_AUTOMATIC),
showScrollbarY(SB_SHOW_AUTOMATIC),
- colLabelHeight(DEFAULT_COL_LABEL_HEIGHT),
+ colLabelHeight(0), //dummy init
drawRowLabel(true),
comp(1),
rowCountOld(0)
{
- Connect(wxEVT_PAINT, wxPaintEventHandler(Grid::onPaintEvent ), nullptr, this);
- Connect(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(Grid::onEraseBackGround), nullptr, this);
- Connect(wxEVT_SIZE, wxSizeEventHandler (Grid::onSizeEvent ), nullptr, this);
-
cornerWin_ = new CornerWin (*this); //
rowLabelWin_ = new RowLabelWin(*this); //owership handled by "this"
colLabelWin_ = new ColLabelWin(*this); //
mainWin_ = new MainWin (*this, *rowLabelWin_, *colLabelWin_); //
+ colLabelHeight = 2 * DEFAULT_COL_LABEL_BORDER + [&]() -> int
+ {
+ //coordinate with ColLabelWin::render():
+ wxFont labelFont = colLabelWin_->GetFont();
+ labelFont.SetWeight(wxFONTWEIGHT_BOLD);
+ return labelFont.GetPixelSize().GetHeight();
+ }();
+
+ Connect(wxEVT_PAINT, wxPaintEventHandler(Grid::onPaintEvent ), nullptr, this);
+ Connect(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(Grid::onEraseBackGround), nullptr, this);
+ Connect(wxEVT_SIZE, wxSizeEventHandler (Grid::onSizeEvent ), nullptr, this);
+
SetTargetWindow(mainWin_);
SetInitialSize(size); //"Most controls will use this to set their initial size" -> why not
@@ -1621,7 +1619,21 @@ void Grid::showRowLabel(bool show)
std::vector<size_t> Grid::getSelectedRows(size_t compPos) const
{
- return compPos < comp.size() ? comp[compPos].selection.get() : std::vector<size_t>();
+ if (compPos < comp.size())
+ return comp[compPos].selection.get();
+ assert(false);
+ return std::vector<size_t>();
+}
+
+
+void Grid::setSelectedRows(const std::vector<size_t>& sel, size_t compPos)
+{
+ if (compPos < comp.size())
+ {
+ comp[compPos].selection.set(sel);
+ Refresh();
+ }
+ else assert(false);
}
@@ -1665,10 +1677,13 @@ void Grid::Refresh(bool eraseBackground, const wxRect* rect)
if (rowCountOld != rowCountNew)
{
rowCountOld = rowCountNew;
- for (Component& c : comp)
- c.selection.init(rowCountNew);
updateWindowSizes();
}
+
+ for (Component& c : comp)
+ if (c.selection.size() != rowCountNew) //clear selection only when needed (consider setSelectedRows())
+ c.selection.init(rowCountNew);
+
wxScrolledWindow::Refresh(eraseBackground, rect);
}
diff --git a/wx+/grid.h b/wx+/grid.h
index f93c0d3b..e8f62a12 100644
--- a/wx+/grid.h
+++ b/wx+/grid.h
@@ -94,9 +94,9 @@ public:
//grid area
virtual wxString getValue(size_t row, ColumnType colType) const = 0;
- virtual void renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected, bool hasFocus); //default implementation
- virtual void renderCell(Grid& grid, wxDC& dc, const wxRect& rect, size_t row, ColumnType colType); //
- virtual int getBestSize(wxDC& dc, size_t row, ColumnType colType); //must correspond to renderCell()!
+ virtual void renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected); //default implementation
+ virtual void renderCell (wxDC& dc, const wxRect& rect, size_t row, ColumnType colType, bool selected); //
+ virtual int getBestSize (wxDC& dc, size_t row, ColumnType colType); //must correspond to renderCell()!
virtual wxString getToolTip(size_t row, ColumnType colType) const { return wxString(); }
//label area
@@ -104,9 +104,11 @@ public:
virtual void renderColumnLabel(Grid& grid, wxDC& dc, const wxRect& rect, ColumnType colType, bool highlighted); //default implementation
virtual wxString getToolTip(ColumnType colType) const { return wxString(); }
+ static const int COLUMN_GAP_LEFT; //for left-aligned text
+
protected: //optional helper routines
static wxRect drawCellBorder (wxDC& dc, const wxRect& rect); //returns inner rectangle
- static void drawCellBackground(wxDC& dc, const wxRect& rect, bool enabled, bool selected, bool hasFocus, const wxColor& backgroundColor);
+ static void drawCellBackground(wxDC& dc, const wxRect& rect, bool enabled, bool selected, const wxColor& backgroundColor);
static void drawCellText (wxDC& dc, const wxRect& rect, const wxString& text, bool enabled, int alignment = wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
static wxRect drawColumnLabelBorder (wxDC& dc, const wxRect& rect); //returns inner rectangle
@@ -165,6 +167,7 @@ public:
void showScrollBars(ScrollBarStatus horizontal, ScrollBarStatus vertical);
std::vector<size_t> getSelectedRows(size_t compPos = 0) const;
+ void setSelectedRows(const std::vector<size_t>& sel, size_t compPos = 0);
void clearSelection(bool emitSelectRangeEvent = true, size_t compPos = 0); //turn off range selection event when calling this function in an event handler to avoid recursion!
void scrollDelta(int deltaX, int deltaY); //in scroll units
@@ -226,6 +229,8 @@ private:
public:
void init(size_t rowCount) { rowSelectionValue.resize(rowCount); clear(); }
+ size_t size() const { return rowSelectionValue.size(); }
+
std::vector<size_t> get() const
{
std::vector<size_t> selection;
@@ -235,6 +240,14 @@ private:
return selection;
}
+ void set(const std::vector<size_t>& newSel)
+ {
+ clear();
+ for (size_t row : newSel)
+ if (row < rowSelectionValue.size())
+ rowSelectionValue[row] = true;
+ }
+
void clear() { selectRange(0, rowSelectionValue.size(), false); }
bool isSelected(size_t row) const { return row < rowSelectionValue.size() ? rowSelectionValue[row] != 0 : false; }
diff --git a/wx+/image_resources.cpp b/wx+/image_resources.cpp
new file mode 100644
index 00000000..6da12c17
--- /dev/null
+++ b/wx+/image_resources.cpp
@@ -0,0 +1,119 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#include "image_resources.h"
+#include <memory>
+#include <map>
+#include <wx/wfstream.h>
+#include <wx/zipstrm.h>
+#include <wx/image.h>
+#include <wx/mstream.h>
+#include <zen/utf.h>
+
+using namespace zen;
+
+
+namespace
+{
+void loadAnimFromZip(wxZipInputStream& zipInput, wxAnimation& anim)
+{
+ //work around wxWidgets bug:
+ //construct seekable input stream (zip-input stream is non-seekable) for wxAnimation::Load()
+ //luckily this method call is very fast: below measurement precision!
+ std::vector<char> data;
+ data.reserve(10000);
+
+ int newValue = 0;
+ while ((newValue = zipInput.GetC()) != wxEOF)
+ data.push_back(newValue);
+
+ wxMemoryInputStream seekAbleStream(&data.front(), data.size()); //stream does not take ownership of data
+
+ anim.Load(seekAbleStream, wxANIMATION_TYPE_GIF);
+}
+
+
+class GlobalResources
+{
+public:
+ static GlobalResources& instance()
+ {
+ static GlobalResources inst;
+ return inst;
+ }
+
+ void init(const Zstring& filename);
+
+ const wxBitmap& getImage(const wxString& name) const;
+ const wxAnimation& getAnimation(const wxString& name) const;
+
+private:
+ GlobalResources() {}
+ GlobalResources(const GlobalResources&);
+ GlobalResources& operator=(const GlobalResources&);
+
+ std::map<wxString, wxBitmap> bitmaps;
+ std::map<wxString, wxAnimation> anims;
+};
+
+
+void GlobalResources::init(const Zstring& filename)
+{
+ wxFFileInputStream input(utfCvrtTo<wxString>(filename));
+ if (input.IsOk()) //if not... we don't want to react too harsh here
+ {
+ //activate support for .png files
+ wxImage::AddHandler(new wxPNGHandler); //ownership passed
+
+ wxZipInputStream resourceFile(input, wxConvUTF8);
+ //do NOT rely on wxConvLocal! On failure shows unhelpful popup "Cannot convert from the charset 'Unknown encoding (-1)'!"
+
+ while (true)
+ {
+ std::unique_ptr<wxZipEntry> entry(resourceFile.GetNextEntry()); //take ownership!
+ if (!entry)
+ break;
+
+ const wxString name = entry->GetName();
+
+ //generic image loading
+ if (endsWith(name, L".png"))
+ bitmaps.insert(std::make_pair(name, wxImage(resourceFile, wxBITMAP_TYPE_PNG)));
+ else if (endsWith(name, L".gif"))
+ loadAnimFromZip(resourceFile, anims[name]);
+ }
+ }
+}
+
+
+const wxBitmap& GlobalResources::getImage(const wxString& name) const
+{
+ auto it = bitmaps.find(contains(name, L'.') ? name : name + L".png"); //assume .png ending if nothing else specified
+ if (it != bitmaps.end())
+ return it->second;
+
+ assert(false);
+ return wxNullBitmap;
+}
+
+
+const wxAnimation& GlobalResources::getAnimation(const wxString& name) const
+{
+ auto it = anims.find(contains(name, L'.') ? name : name + L".gif");
+ if (it != anims.end())
+ return it->second;
+
+ assert(false);
+ return wxNullAnimation;
+}
+}
+
+
+void zen::initResourceImages(const Zstring& filename) { GlobalResources::instance().init(filename); }
+
+const wxBitmap& zen::getResourceImage(const wxString& name) { return GlobalResources::instance().getImage(name); }
+
+const wxAnimation& zen::getResourceAnimation(const wxString& name) { return GlobalResources::instance().getAnimation(name); }
diff --git a/wx+/image_resources.h b/wx+/image_resources.h
new file mode 100644
index 00000000..61e0b61c
--- /dev/null
+++ b/wx+/image_resources.h
@@ -0,0 +1,22 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#ifndef RESOURCES_H_8740257825342532457
+#define RESOURCES_H_8740257825342532457
+
+#include <wx/bitmap.h>
+#include <wx/animate.h>
+#include <zen/zstring.h>
+
+namespace zen
+{
+void initResourceImages(const Zstring& filename); //pass resources .zip file at application startup
+
+const wxBitmap& getResourceImage (const wxString& name);
+const wxAnimation& getResourceAnimation(const wxString& name);
+}
+
+#endif //RESOURCES_H_8740257825342532457
diff --git a/wx+/popup_dlg.cpp b/wx+/popup_dlg.cpp
new file mode 100644
index 00000000..27526922
--- /dev/null
+++ b/wx+/popup_dlg.cpp
@@ -0,0 +1,279 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#include "popup_dlg.h"
+#include <wx/app.h>
+#include <wx+/mouse_move_dlg.h>
+#include <wx+/std_button_order.h>
+#include <wx+/font_size.h>
+#include <wx+/image_resources.h>
+#include "popup_dlg_generated.h"
+
+using namespace zen;
+
+
+namespace
+{
+void setAsStandard(wxButton& btn)
+{
+ btn.SetDefault();
+ btn.SetFocus();
+}
+
+
+void setBestInitialSize(wxTextCtrl& ctrl, const wxString& text, wxSize maxSize)
+{
+ const int scrollbarWidth = 30;
+ if (maxSize.x <= scrollbarWidth) //implicitly checks for non-zero, too!
+ return;
+ maxSize.x -= scrollbarWidth;
+
+ int bestWidth = 0;
+ int rowCount = 0;
+ int rowHeight = 0;
+
+ auto evalLineExtent = [&](const wxSize& sz) -> bool //return true when done
+ {
+ if (sz.x > bestWidth)
+ bestWidth = std::min(maxSize.x, sz.x);
+
+ rowCount += (sz.x + maxSize.x - 1) / maxSize.x; //integer round up: consider line-wraps!
+ rowHeight = std::max(rowHeight, sz.y); //all rows *should* have same height
+
+ return rowCount * rowHeight >= maxSize.y;
+ };
+
+ for (auto it = text.begin();;)
+ {
+ auto itEnd = std::find(it, text.end(), L'\n');
+ wxString line(it, itEnd);
+ if (line.empty())
+ line = L" "; //GetTextExtent() returns (0, 0) for empty strings!
+
+ wxSize sz = ctrl.GetTextExtent(line); //exactly gives row height, but does *not* consider newlines
+ if (evalLineExtent(sz))
+ break;
+
+ if (itEnd == text.end())
+ break;
+ it = itEnd + 1;
+ }
+
+ const wxSize bestSize(bestWidth + scrollbarWidth, std::min(rowCount * rowHeight, maxSize.y));
+ ctrl.SetMinSize(bestSize); //alas, SetMinClientSize() is just not working!
+}
+}
+
+
+class zen::StandardPopupDialog : public PopupDialogGenerated
+{
+public:
+ StandardPopupDialog(wxWindow* parent, DialogInfoType type, const PopupDialogCfg& cfg) :
+ PopupDialogGenerated(parent),
+ checkBoxValue_(cfg.checkBoxValue)
+ {
+#ifdef ZEN_WIN
+ new zen::MouseMoveWindow(*this); //allow moving main dialog by clicking (nearly) anywhere...; ownership passed to "this"
+#endif
+ wxString titleTmp = cfg.title;
+ switch (type)
+ {
+ case DialogInfoType::INFO:
+ //"information" is meaningless as caption text!
+ //confirmation doesn't use info icon
+ //m_bitmapMsgType->Hide();
+ //m_bitmapMsgType->SetSize(30, -1);
+ //m_bitmapMsgType->SetBitmap(getResourceImage(L"msg_info"));
+ break;
+ case DialogInfoType::WARNING:
+ if (titleTmp.empty()) titleTmp = _("Warning");
+ m_bitmapMsgType->SetBitmap(getResourceImage(L"msg_warning"));
+ break;
+ case DialogInfoType::ERROR2:
+ if (titleTmp.empty()) titleTmp = _("Error");
+ m_bitmapMsgType->SetBitmap(getResourceImage(L"msg_error"));
+ break;
+ }
+
+ if (titleTmp.empty())
+ SetTitle(wxTheApp->GetAppDisplayName());
+ else
+ {
+ if (parent && parent->IsShownOnScreen())
+ SetTitle(titleTmp);
+ else
+ SetTitle(wxTheApp->GetAppDisplayName() + L" - " + titleTmp);
+ }
+
+ const wxSize maxSize(500, 380);
+
+ assert(!cfg.textMain.empty() || !cfg.textDetail.empty());
+ if (!cfg.textMain.empty())
+ {
+ setMainInstructionFont(*m_staticTextMain);
+ m_staticTextMain->SetLabel(cfg.textMain);
+ m_staticTextMain->Wrap(maxSize.GetWidth()); //call *after* SetLabel()
+ }
+ else
+ m_staticTextMain->Hide();
+
+ if (!cfg.textDetail.empty())
+ {
+ const wxString& text = L"\n" + cfg.textDetail + L"\n"; //add empty top/bottom lines *instead* of using border space!
+ setBestInitialSize(*m_textCtrlTextDetail, text, maxSize);
+ m_textCtrlTextDetail->ChangeValue(text);
+ }
+ else
+ m_textCtrlTextDetail->Hide();
+
+ if (checkBoxValue_)
+ {
+ assert(contains(cfg.checkBoxLabel, L"&"));
+ m_checkBoxCustom->SetLabel(cfg.checkBoxLabel);
+ m_checkBoxCustom->SetValue(*checkBoxValue_);
+ }
+ else
+ m_checkBoxCustom->Hide();
+
+ Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(StandardPopupDialog::OnKeyPressed), nullptr, this);
+ }
+
+private:
+ virtual void OnClose (wxCloseEvent& event) override { EndModal(static_cast<int>(ConfirmationButton3::CANCEL)); }
+ virtual void OnCancel(wxCommandEvent& event) override { EndModal(static_cast<int>(ConfirmationButton3::CANCEL)); }
+
+ void OnKeyPressed(wxKeyEvent& event)
+ {
+ const int keyCode = event.GetKeyCode();
+ if (keyCode == WXK_ESCAPE) //handle case where cancel button is hidden!
+ {
+ EndModal(static_cast<int>(ConfirmationButton3::CANCEL));
+ return;
+ }
+ event.Skip();
+ }
+
+ virtual void OnButtonAffirmative(wxCommandEvent& event) override
+ {
+ if (checkBoxValue_)
+ * checkBoxValue_ = m_checkBoxCustom->GetValue();
+ EndModal(static_cast<int>(ConfirmationButton3::DO_IT));
+ }
+
+ virtual void OnButtonNegative(wxCommandEvent& event) override
+ {
+ if (checkBoxValue_)
+ * checkBoxValue_ = m_checkBoxCustom->GetValue();
+ EndModal(static_cast<int>(ConfirmationButton3::DONT_DO_IT));
+ }
+
+ bool* checkBoxValue_;
+};
+
+
+namespace
+{
+class NotificationDialog : public StandardPopupDialog
+{
+public:
+ NotificationDialog(wxWindow* parent, DialogInfoType type, const PopupDialogCfg& cfg) :
+ StandardPopupDialog(parent, type, cfg)
+ {
+ m_buttonAffirmative->SetLabel(_("Close")); //UX Guide: use "Close" for errors, warnings and windows in which users can't make changes (no ampersand!)
+ m_buttonNegative->Hide();
+ m_buttonCancel->Hide();
+
+ //set std order after button visibility was set
+ setStandardButtonOrder(*bSizerStdButtons, StdButtons().setAffirmative(m_buttonAffirmative));
+ setAsStandard(*m_buttonAffirmative);
+ GetSizer()->SetSizeHints(this); //~=Fit() + SetMinSize()
+ }
+};
+
+
+class ConfirmationDialog : public StandardPopupDialog
+{
+public:
+ ConfirmationDialog(wxWindow* parent, DialogInfoType type, const PopupDialogCfg& cfg, const wxString& labelDoIt) :
+ StandardPopupDialog(parent, type, cfg)
+ {
+ assert(contains(labelDoIt, L"&"));
+ m_buttonAffirmative->SetLabel(labelDoIt);
+ m_buttonNegative->Hide();
+
+ //set std order after button visibility was set
+ setStandardButtonOrder(*bSizerStdButtons, StdButtons().setAffirmative(m_buttonAffirmative).setCancel(m_buttonCancel));
+ setAsStandard(*m_buttonAffirmative);
+ GetSizer()->SetSizeHints(this); //~=Fit() + SetMinSize()
+ }
+};
+}
+
+class zen::ConfirmationDialog3 : public StandardPopupDialog
+{
+public:
+ ConfirmationDialog3(wxWindow* parent, DialogInfoType type, const PopupDialogCfg3& cfg, const wxString& labelDoIt, const wxString& labelDontDoIt) :
+ StandardPopupDialog(parent, type, cfg.pdCfg),
+ buttonToDisableWhenChecked(cfg.buttonToDisableWhenChecked)
+ {
+ assert(contains(labelDoIt, L"&"));
+ assert(contains(labelDontDoIt, L"&"));
+ m_buttonAffirmative->SetLabel(labelDoIt);
+ m_buttonNegative ->SetLabel(labelDontDoIt);
+
+ //m_buttonAffirmative->SetId(wxID_IGNORE); -> setting id after button creation breaks "mouse snap to" functionality
+ //m_buttonNegative ->SetId(wxID_RETRY); -> also wxWidgets docs seem to hide some info: "Normally, the identifier should be provided on creation and should not be modified subsequently."
+
+ updateGui();
+
+ //set std order after button visibility was set
+ setStandardButtonOrder(*bSizerStdButtons, StdButtons().setAffirmative(m_buttonAffirmative).setNegative(m_buttonNegative).setCancel(m_buttonCancel));
+ setAsStandard(*m_buttonAffirmative);
+ GetSizer()->SetSizeHints(this); //~=Fit() + SetMinSize()
+ }
+
+private:
+ virtual void OnCheckBoxClick(wxCommandEvent& event) override { updateGui(); event.Skip(); }
+
+ void updateGui()
+ {
+ switch (buttonToDisableWhenChecked)
+ {
+ case ConfirmationButton3::DO_IT:
+ m_buttonAffirmative->Enable(!m_checkBoxCustom->GetValue());
+ break;
+ case ConfirmationButton3::DONT_DO_IT:
+ m_buttonNegative->Enable(!m_checkBoxCustom->GetValue());
+ break;
+ case ConfirmationButton3::CANCEL:
+ break;
+ }
+ }
+
+ const ConfirmationButton3 buttonToDisableWhenChecked;
+};
+
+//########################################################################################
+
+void zen::showNotificationDialog(wxWindow* parent, DialogInfoType type, const PopupDialogCfg& cfg)
+{
+ NotificationDialog dlg(parent, type, cfg);
+ dlg.ShowModal();
+}
+
+
+ConfirmationButton zen::showConfirmationDialog(wxWindow* parent, DialogInfoType type, const PopupDialogCfg& cfg, const wxString& labelDoIt)
+{
+ ConfirmationDialog dlg(parent, type, cfg, labelDoIt);
+ return static_cast<ConfirmationButton>(dlg.ShowModal());
+}
+
+
+ConfirmationButton3 zen::showConfirmationDialog3(wxWindow* parent, DialogInfoType type, const PopupDialogCfg3& cfg, const wxString& labelDoIt, const wxString& labelDontDoIt)
+{
+ ConfirmationDialog3 dlg(parent, type, cfg, labelDoIt, labelDontDoIt);
+ return static_cast<ConfirmationButton3>(dlg.ShowModal());
+}
diff --git a/wx+/popup_dlg.h b/wx+/popup_dlg.h
new file mode 100644
index 00000000..ab988702
--- /dev/null
+++ b/wx+/popup_dlg.h
@@ -0,0 +1,91 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#ifndef MESSAGEPOPUP_H_820780154723456
+#define MESSAGEPOPUP_H_820780154723456
+
+#include <wx/window.h>
+#include <wx/string.h>
+
+namespace zen
+{
+//parent window, optional: support correct dialog placement above parent on multiple monitor systems
+//this module requires error, warning and info image files in resources.zip, see <wx+/image_resources.h>
+
+struct PopupDialogCfg;
+struct PopupDialogCfg3;
+
+enum class DialogInfoType
+{
+ INFO,
+ WARNING,
+ ERROR2, //fuck the ERROR macro in WinGDI.h!
+};
+
+enum class ConfirmationButton3
+{
+ DO_IT,
+ DONT_DO_IT,
+ CANCEL
+};
+
+enum class ConfirmationButton
+{
+ DO_IT = static_cast<int>(ConfirmationButton3::DO_IT), //[!]
+ CANCEL = static_cast<int>(ConfirmationButton3::CANCEL), //Clang requires a "static_cast"
+};
+
+void showNotificationDialog (wxWindow* parent, DialogInfoType type, const PopupDialogCfg& cfg);
+ConfirmationButton showConfirmationDialog (wxWindow* parent, DialogInfoType type, const PopupDialogCfg& cfg, const wxString& labelDoIt);
+ConfirmationButton3 showConfirmationDialog3(wxWindow* parent, DialogInfoType type, const PopupDialogCfg3& cfg, const wxString& labelDoIt, const wxString& labelDontDoIt);
+
+//----------------------------------------------------------------------------------------------------------------
+class StandardPopupDialog;
+class ConfirmationDialog3;
+
+struct PopupDialogCfg
+{
+ PopupDialogCfg() : checkBoxValue() {}
+ PopupDialogCfg& setTitle (const wxString& label) { title = label; return *this; }
+ PopupDialogCfg& setMainInstructions (const wxString& label) { textMain = label; return *this; } //set at least one of these!
+ PopupDialogCfg& setDetailInstructions(const wxString& label) { textDetail = label; return *this; } //
+ PopupDialogCfg& setCheckBox(bool& value, const wxString& label) { checkBoxValue = &value; checkBoxLabel = label; return *this; }
+
+private:
+ friend class StandardPopupDialog;
+
+ wxString title;
+ wxString textMain;
+ wxString textDetail;
+ bool* checkBoxValue; //in/out
+ wxString checkBoxLabel;
+};
+
+
+struct PopupDialogCfg3
+{
+ PopupDialogCfg3() : buttonToDisableWhenChecked(ConfirmationButton3::CANCEL) {}
+ PopupDialogCfg3& setTitle (const wxString& label) { pdCfg.setTitle (label); return *this; }
+ PopupDialogCfg3& setMainInstructions (const wxString& label) { pdCfg.setMainInstructions (label); return *this; } //set at least one of these!
+ PopupDialogCfg3& setDetailInstructions(const wxString& label) { pdCfg.setDetailInstructions(label); return *this; } //
+ PopupDialogCfg3& setCheckBox(bool& value, const wxString& label) { pdCfg.setCheckBox(value, label); return *this; }
+ PopupDialogCfg3& setCheckBox(bool& value, const wxString& label, ConfirmationButton3 disableWhenChecked)
+ {
+ assert(disableWhenChecked != ConfirmationButton3::CANCEL);
+ setCheckBox(value, label);
+ buttonToDisableWhenChecked = disableWhenChecked;
+ return *this;
+ }
+
+private:
+ friend class ConfirmationDialog3;
+
+ PopupDialogCfg pdCfg;
+ ConfirmationButton3 buttonToDisableWhenChecked;
+};
+}
+
+#endif //MESSAGEPOPUP_H_820780154723456
diff --git a/wx+/popup_dlg_generated.cpp b/wx+/popup_dlg_generated.cpp
new file mode 100644
index 00000000..b7618545
--- /dev/null
+++ b/wx+/popup_dlg_generated.cpp
@@ -0,0 +1,91 @@
+///////////////////////////////////////////////////////////////////////////
+// C++ code generated with wxFormBuilder (version Oct 8 2012)
+// http://www.wxformbuilder.org/
+//
+// PLEASE DO "NOT" EDIT THIS FILE!
+///////////////////////////////////////////////////////////////////////////
+
+#include "popup_dlg_generated.h"
+
+///////////////////////////////////////////////////////////////////////////
+
+PopupDialogGenerated::PopupDialogGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
+{
+ this->SetSizeHints( wxSize( -1,-1 ), wxDefaultSize );
+ this->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
+
+ wxBoxSizer* bSizer24;
+ bSizer24 = new wxBoxSizer( wxVERTICAL );
+
+ m_panel33 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+ m_panel33->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
+
+ wxBoxSizer* bSizer165;
+ bSizer165 = new wxBoxSizer( wxHORIZONTAL );
+
+ m_bitmapMsgType = new wxStaticBitmap( m_panel33, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), 0 );
+ bSizer165->Add( m_bitmapMsgType, 0, wxALL, 10 );
+
+ wxBoxSizer* bSizer16;
+ bSizer16 = new wxBoxSizer( wxVERTICAL );
+
+ m_staticTextMain = new wxStaticText( m_panel33, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticTextMain->Wrap( -1 );
+ bSizer16->Add( m_staticTextMain, 0, wxTOP|wxBOTTOM|wxRIGHT, 15 );
+
+ m_textCtrlTextDetail = new wxTextCtrl( m_panel33, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxNO_BORDER );
+ bSizer16->Add( m_textCtrlTextDetail, 1, wxEXPAND, 5 );
+
+
+ bSizer165->Add( bSizer16, 1, wxEXPAND, 5 );
+
+
+ m_panel33->SetSizer( bSizer165 );
+ m_panel33->Layout();
+ bSizer165->Fit( m_panel33 );
+ bSizer24->Add( m_panel33, 1, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
+
+ m_staticline6 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
+ bSizer24->Add( m_staticline6, 0, wxEXPAND|wxALIGN_CENTER_HORIZONTAL, 5 );
+
+ wxBoxSizer* bSizer25;
+ bSizer25 = new wxBoxSizer( wxVERTICAL );
+
+ m_checkBoxCustom = new wxCheckBox( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
+ bSizer25->Add( m_checkBoxCustom, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP|wxRIGHT|wxLEFT, 5 );
+
+ bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL );
+
+ m_buttonAffirmative = new wxButton( this, wxID_YES, _("dummy"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ bSizerStdButtons->Add( m_buttonAffirmative, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
+
+ m_buttonNegative = new wxButton( this, wxID_NO, _("dummy"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ bSizerStdButtons->Add( m_buttonNegative, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
+
+ m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ bSizerStdButtons->Add( m_buttonCancel, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
+
+
+ bSizer25->Add( bSizerStdButtons, 0, wxALIGN_RIGHT, 5 );
+
+
+ bSizer24->Add( bSizer25, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
+
+
+ this->SetSizer( bSizer24 );
+ this->Layout();
+ bSizer24->Fit( this );
+
+ this->Centre( wxBOTH );
+
+ // Connect Events
+ this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( PopupDialogGenerated::OnClose ) );
+ m_checkBoxCustom->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( PopupDialogGenerated::OnCheckBoxClick ), NULL, this );
+ m_buttonAffirmative->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PopupDialogGenerated::OnButtonAffirmative ), NULL, this );
+ m_buttonNegative->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PopupDialogGenerated::OnButtonNegative ), NULL, this );
+ m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PopupDialogGenerated::OnCancel ), NULL, this );
+}
+
+PopupDialogGenerated::~PopupDialogGenerated()
+{
+}
diff --git a/wx+/popup_dlg_generated.h b/wx+/popup_dlg_generated.h
new file mode 100644
index 00000000..5aab9f68
--- /dev/null
+++ b/wx+/popup_dlg_generated.h
@@ -0,0 +1,71 @@
+///////////////////////////////////////////////////////////////////////////
+// C++ code generated with wxFormBuilder (version Oct 8 2012)
+// http://www.wxformbuilder.org/
+//
+// PLEASE DO "NOT" EDIT THIS FILE!
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef __POPUP_DLG_GENERATED_H__
+#define __POPUP_DLG_GENERATED_H__
+
+#include <wx/artprov.h>
+#include <wx/xrc/xmlres.h>
+#include <wx/intl.h>
+#include <wx/bitmap.h>
+#include <wx/image.h>
+#include <wx/icon.h>
+#include <wx/statbmp.h>
+#include <wx/gdicmn.h>
+#include <wx/font.h>
+#include <wx/colour.h>
+#include <wx/settings.h>
+#include <wx/string.h>
+#include <wx/stattext.h>
+#include <wx/textctrl.h>
+#include <wx/sizer.h>
+#include <wx/panel.h>
+#include <wx/statline.h>
+#include <wx/checkbox.h>
+#include <wx/button.h>
+#include <wx/dialog.h>
+
+#include "zen/i18n.h"
+
+///////////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Class PopupDialogGenerated
+///////////////////////////////////////////////////////////////////////////////
+class PopupDialogGenerated : public wxDialog
+{
+ private:
+
+ protected:
+ wxPanel* m_panel33;
+ wxStaticBitmap* m_bitmapMsgType;
+ wxStaticText* m_staticTextMain;
+ wxTextCtrl* m_textCtrlTextDetail;
+ wxStaticLine* m_staticline6;
+ wxCheckBox* m_checkBoxCustom;
+ wxBoxSizer* bSizerStdButtons;
+ wxButton* m_buttonAffirmative;
+ wxButton* m_buttonNegative;
+ wxButton* m_buttonCancel;
+
+ // Virtual event handlers, overide them in your derived class
+ virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
+ virtual void OnCheckBoxClick( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnButtonAffirmative( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnButtonNegative( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); }
+
+
+ public:
+
+ PopupDialogGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("dummy"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
+ ~PopupDialogGenerated();
+
+};
+
+#endif //__POPUP_DLG_GENERATED_H__
diff --git a/wx+/shell_execute.h b/wx+/shell_execute.h
deleted file mode 100644
index 1d67aa21..00000000
--- a/wx+/shell_execute.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
-// **************************************************************************
-
-#ifndef EXECUTE_HEADER_23482134578134134
-#define EXECUTE_HEADER_23482134578134134
-
-#include <zen/zstring.h>
-#include <zen/scope_guard.h>
-#include <zen/i18n.h>
-#include <zen/utf.h>
-#include <wx/msgdlg.h>
-
-#ifdef ZEN_WIN
-#include <zen/sys_error.h>
-//#include <zen/string_tools.h>
-#include <zen/win.h> //includes "windows.h"
-
-#elif defined ZEN_LINUX || defined ZEN_MAC
-#include <zen/thread.h>
-#include <stdlib.h> //::system()
-//#include <wx/utils.h>
-//#include <wx/log.h>
-#endif
-
-
-namespace zen
-{
-//launch commandline and report errors via popup dialog
-//windows: COM needs to be initialized before calling this function!
-enum ExecutionType
-{
- EXEC_TYPE_SYNC,
- EXEC_TYPE_ASYNC
-};
-
-namespace
-{
-void shellExecute(const Zstring& command, ExecutionType type = EXEC_TYPE_ASYNC)
-{
-#ifdef ZEN_WIN
- //parse commandline
- Zstring commandTmp = command;
- trim(commandTmp, true, false); //CommandLineToArgvW() does not like leading spaces
-
- std::vector<std::wstring> argv;
- int argc = 0;
- if (LPWSTR* tmp = ::CommandLineToArgvW(commandTmp.c_str(), &argc))
- {
- ZEN_ON_SCOPE_EXIT(::LocalFree(tmp));
- std::copy(tmp, tmp + argc, std::back_inserter(argv));
- }
-
- std::wstring filename;
- std::wstring arguments;
- if (!argv.empty())
- {
- filename = argv[0];
- for (auto iter = argv.begin() + 1; iter != argv.end(); ++iter)
- arguments += (iter != argv.begin() ? L" " : L"") +
- (iter->empty() || std::any_of(iter->begin(), iter->end(), &isWhiteSpace<wchar_t>) ? L"\"" + *iter + L"\"" : *iter);
- }
-
- SHELLEXECUTEINFO execInfo = {};
- execInfo.cbSize = sizeof(execInfo);
-
- //SEE_MASK_NOASYNC is equal to SEE_MASK_FLAG_DDEWAIT, but former is defined not before Win SDK 6.0
- execInfo.fMask = type == EXEC_TYPE_SYNC ? (SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT) : 0; //don't use SEE_MASK_ASYNCOK -> returns successful despite errors!
- execInfo.fMask |= SEE_MASK_UNICODE | SEE_MASK_FLAG_NO_UI; //::ShellExecuteEx() shows a non-blocking pop-up dialog on errors -> we want a blocking one
- execInfo.lpVerb = nullptr;
- execInfo.lpFile = filename.c_str();
- execInfo.lpParameters = arguments.c_str();
- execInfo.nShow = SW_SHOWNORMAL;
-
- if (!::ShellExecuteEx(&execInfo)) //__inout LPSHELLEXECUTEINFO lpExecInfo
- {
- wxString cmdFmt = L"File: " + filename + L"\nArg: " + arguments;
- wxMessageBox(_("Invalid command line:") + L"\n" + cmdFmt + L"\n\n" + formatSystemError(L"ShellExecuteEx", getLastError()), /*L"FreeFileSync - " + */_("Error"), wxOK | wxICON_ERROR);
- return;
- }
-
- if (execInfo.hProcess)
- {
- ZEN_ON_SCOPE_EXIT(::CloseHandle(execInfo.hProcess));
-
- if (type == EXEC_TYPE_SYNC)
- ::WaitForSingleObject(execInfo.hProcess, INFINITE);
- }
-
-#elif defined ZEN_LINUX || defined ZEN_MAC
- /*
- we cannot use wxExecute due to various issues:
- - screws up encoding on OS X for non-ASCII characters
- - does not provide any reasonable error information
- - uses a zero-sized dummy window as a hack to keep focus which leaves a useless empty icon in ALT-TAB list
- */
-
- if (type == EXEC_TYPE_SYNC)
- {
- //Posix::system - execute a shell command
- int rv = ::system(command.c_str()); //do NOT use std::system as its documentation says nothing about "WEXITSTATUS(rv)", ect...
- if (rv == -1 || WEXITSTATUS(rv) == 127) //http://linux.die.net/man/3/system "In case /bin/sh could not be executed, the exit status will be that of a command that does exit(127)"
- wxMessageBox(_("Invalid command line:") + L"\n" + utfCvrtTo<wxString>(command), /*L"FreeFileSync - " +*/ _("Error"), wxOK | wxICON_ERROR);
- }
- else
- async([=] { int rv = ::system(command.c_str()); (void)rv; });
- //unfortunately we are not allowed to show a wxMessageBox from a worker thread
-#endif
-}
-}
-}
-
-#endif //EXECUTE_HEADER_23482134578134134
diff --git a/wx+/tooltip.cpp b/wx+/tooltip.cpp
index ebf3c61c..d4bcf302 100644
--- a/wx+/tooltip.cpp
+++ b/wx+/tooltip.cpp
@@ -16,15 +16,15 @@
using namespace zen;
-class Tooltip::PopupDialogGenerated : public wxDialog
+class Tooltip::TooltipDialogGenerated : public wxDialog
{
public:
- PopupDialogGenerated(wxWindow* parent,
- wxWindowID id = wxID_ANY,
- const wxString& title = wxEmptyString,
- const wxPoint& pos = wxDefaultPosition,
- const wxSize& size = wxDefaultSize,
- long style = 0) : wxDialog(parent, id, title, pos, size, style)
+ TooltipDialogGenerated(wxWindow* parent,
+ wxWindowID id = wxID_ANY,
+ const wxString& title = wxEmptyString,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = 0) : wxDialog(parent, id, title, pos, size, style)
{
//Suse Linux/X11: needs parent window, else there are z-order issues
@@ -43,7 +43,7 @@ public:
this->Layout();
bSizer158->Fit(this);
-#if defined ZEN_WIN //prevent window stealing focus!
+#ifdef ZEN_WIN //prevent window from stealing focus!
Disable(); //= dark/grey text and image on Linux; no visible difference on OS X
#endif
}
@@ -56,7 +56,7 @@ public:
void Tooltip::show(const wxString& text, wxPoint mousePos, const wxBitmap* bmp)
{
if (!tipWindow)
- tipWindow = new PopupDialogGenerated(&parent_); //ownership passed to parent
+ tipWindow = new TooltipDialogGenerated(&parent_); //ownership passed to parent
const wxBitmap& newBmp = bmp ? *bmp : wxNullBitmap;
@@ -72,7 +72,8 @@ void Tooltip::show(const wxString& text, wxPoint mousePos, const wxBitmap* bmp)
tipWindow->m_staticTextMain->Wrap(600);
}
- tipWindow->Fit(); //Linux: Fit() seems to be somewhat broken => this needs to be called EVERY time inside show, not only if text or bmp change
+ tipWindow->GetSizer()->SetSizeHints(tipWindow); //~=Fit() + SetMinSize()
+ //Linux: Fit() seems to be somewhat broken => this needs to be called EVERY time inside show, not only if text or bmp change
const wxPoint newPos = wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ?
mousePos - wxPoint(30 + tipWindow->GetSize().GetWidth(), 0) :
diff --git a/wx+/tooltip.h b/wx+/tooltip.h
index d17e650e..7f58ff27 100644
--- a/wx+/tooltip.h
+++ b/wx+/tooltip.h
@@ -23,8 +23,8 @@ public:
void hide();
private:
- class PopupDialogGenerated;
- PopupDialogGenerated* tipWindow;
+ class TooltipDialogGenerated;
+ TooltipDialogGenerated* tipWindow;
wxWindow& parent_;
};
}
bgstack15