summaryrefslogtreecommitdiff
path: root/wx+
diff options
context:
space:
mode:
authorB. Stack <bgstack15@gmail.com>2022-06-26 16:00:37 +0000
committerB. Stack <bgstack15@gmail.com>2022-06-26 16:00:37 +0000
commit2a026bc7d76875b88700bebc7c5a801fef881bfd (patch)
treef820b53379f3d14e103e2663e8b0ecd38d1b2105 /wx+
parentMerge branch 'b11.21' into 'master' (diff)
parentadd upstream 11.22 (diff)
downloadFreeFileSync-11.22.tar.gz
FreeFileSync-11.22.tar.bz2
FreeFileSync-11.22.zip
Merge branch '11.22' into 'master'11.22
add upstream 11.22 See merge request opensource-tracking/FreeFileSync!45
Diffstat (limited to 'wx+')
-rw-r--r--wx+/async_task.h3
-rw-r--r--wx+/bitmap_button.h6
-rw-r--r--wx+/dc.h34
-rw-r--r--wx+/image_resources.cpp3
-rw-r--r--wx+/image_tools.cpp4
-rw-r--r--wx+/image_tools.h7
-rw-r--r--wx+/popup_dlg.cpp60
-rw-r--r--wx+/popup_dlg.h11
-rw-r--r--wx+/rtl.h10
-rw-r--r--wx+/std_button_layout.h17
10 files changed, 106 insertions, 49 deletions
diff --git a/wx+/async_task.h b/wx+/async_task.h
index a7ce2eb5..5a3e7caa 100644
--- a/wx+/async_task.h
+++ b/wx+/async_task.h
@@ -114,7 +114,8 @@ private:
class AsyncGuiQueue : private wxEvtHandler
{
public:
- AsyncGuiQueue(int pollingMs = 50) : pollingMs_(pollingMs) { timer_.Bind(wxEVT_TIMER, [this](wxTimerEvent& event) { onTimerEvent(event); }); }
+ explicit AsyncGuiQueue(int pollingMs = 50) :
+ pollingMs_(pollingMs) { timer_.Bind(wxEVT_TIMER, [this](wxTimerEvent& event) { onTimerEvent(event); }); }
template <class Fun, class Fun2>
void processAsync(Fun&& evalAsync, Fun2&& evalOnGui)
diff --git a/wx+/bitmap_button.h b/wx+/bitmap_button.h
index 32bc68c1..d701e64c 100644
--- a/wx+/bitmap_button.h
+++ b/wx+/bitmap_button.h
@@ -11,6 +11,7 @@
#include <wx/settings.h>
#include <wx/statbmp.h>
#include "image_tools.h"
+#include "std_button_layout.h"
#include "dc.h"
@@ -66,9 +67,8 @@ void setBitmapTextLabel(wxBitmapButton& btn, const wxImage& img, const wxString&
stackImages(imgTxt, img, ImageStackLayout::horizontal, ImageStackAlignment::center, gap);
//SetMinSize() instead of SetSize() is needed here for wxWindows layout determination to work correctly
- const int defaultHeight = wxButton::GetDefaultSize().GetHeight();
btn.SetMinSize({imgTxt.GetWidth () + 2 * border,
- std::max(imgTxt.GetHeight() + 2 * border, defaultHeight)});
+ std::max(imgTxt.GetHeight() + 2 * border, getDefaultButtonHeight())});
setImage(btn, imgTxt);
}
@@ -104,6 +104,7 @@ inline
wxBitmap renderSelectedButton(const wxSize& sz)
{
wxBitmap bmp(sz); //seems we don't need to pass 24-bit depth here even for high-contrast color schemes
+ bmp.SetScaleFactor(getDisplayScaleFactor());
{
wxMemoryDC dc(bmp);
@@ -119,6 +120,7 @@ inline
wxBitmap renderPressedButton(const wxSize& sz)
{
wxBitmap bmp(sz); //seems we don't need to pass 24-bit depth here even for high-contrast color schemes
+ bmp.SetScaleFactor(getDisplayScaleFactor());
{
//draw rectangle border with gradient
const wxColor colFrom = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
diff --git a/wx+/dc.h b/wx+/dc.h
index 3728aeb4..c93715c2 100644
--- a/wx+/dc.h
+++ b/wx+/dc.h
@@ -87,7 +87,7 @@ void drawInsetRectangle(wxDC& dc, const wxRect& rect, int borderWidth, const wxC
/* Standard DPI:
Windows/Ubuntu: 96 x 96
macOS: wxWidgets uses DIP (note: wxScreenDC().GetPPI() returns 72 x 72 which is a lie; looks like 96 x 96) */
-constexpr int defaultDpi = 96;
+constexpr int defaultDpi = 96; //on Windows same as wxDisplay::GetStdPPIValue() (however returns 72 on macOS!)
inline
int getDPI()
@@ -104,6 +104,13 @@ int getDPI()
inline
+double getDisplayScaleFactor()
+{
+ return static_cast<double>(getDPI()) / defaultDpi;
+}
+
+
+inline
int fastFromDIP(int d) //like wxWindow::FromDIP (but tied to primary monitor and buffered)
{
return numeric::intDivRound(d * getDPI() - 10 /*round values like 1.5 down => 1 pixel on 150% scale*/, defaultDpi);
@@ -123,11 +130,23 @@ wxBitmapBundle toBitmapBundle(const wxImage& img /*expected to be DPI-scaled!*/)
{
//return wxBitmap(img, -1 /*depth*/, static_cast<double>(getDPI()) / defaultDpi); implementation just ignores scale parameter! WTF!
wxBitmap bmpScaled(img);
- bmpScaled.SetScaleFactor(static_cast<double>(getDPI()) / defaultDpi);
+ bmpScaled.SetScaleFactor(getDisplayScaleFactor());
return bmpScaled;
}
+//all this shit just because wxDC::SetScaleFactor() is missing:
+inline
+void setScaleFactor(wxDC& dc, double scale)
+{
+ struct wxDcSurgeon : public wxDCImpl
+ {
+ void setScaleFactor(double scale) { m_contentScaleFactor = scale; }
+ };
+ static_cast<wxDcSurgeon*>(dc.GetImpl())->setScaleFactor(scale);
+}
+
+
//---------------------- implementation ------------------------
class RecursiveDcClipper
{
@@ -195,10 +214,13 @@ public:
const wxSize clientSize = wnd.GetClientSize();
if (clientSize.GetWidth() > 0 && clientSize.GetHeight() > 0) //wxBitmap asserts this!! width may be 0; test case "Grid::CornerWin": compare both sides, then change config
{
- if (!buffer_ || clientSize != wxSize(buffer->GetWidth(), buffer->GetHeight()))
- buffer = wxBitmap(clientSize.GetWidth(), clientSize.GetHeight());
+ if (!buffer_ || buffer->GetSize() != clientSize)
+ buffer.emplace(clientSize);
+
+ if (buffer->GetScaleFactor() != wnd.GetDPIScaleFactor())
+ buffer->SetScaleFactor(wnd.GetDPIScaleFactor());
- SelectObject(*buffer);
+ SelectObject(*buffer); //copies scale factor from wxBitmap
if (paintDc_.IsOk() && paintDc_.GetLayoutDirection() == wxLayout_RightToLeft)
SetLayoutDirection(wxLayout_RightToLeft);
@@ -213,7 +235,7 @@ public:
{
if (GetLayoutDirection() == wxLayout_RightToLeft)
{
- paintDc_.SetLayoutDirection(wxLayout_LeftToRight); //workaround bug in wxDC::Blit()
+ paintDc_.SetLayoutDirection(wxLayout_LeftToRight); //work around bug in wxDC::Blit()
SetLayoutDirection(wxLayout_LeftToRight); //
}
diff --git a/wx+/image_resources.cpp b/wx+/image_resources.cpp
index 0301a082..36055f3f 100644
--- a/wx+/image_resources.cpp
+++ b/wx+/image_resources.cpp
@@ -209,8 +209,7 @@ ImageBuffer::ImageBuffer(const Zstring& zipPath) //throw FileError
}
//--------------------------------------------------------------------
- //activate support for .png files
- wxImage::AddHandler(new wxPNGHandler); //ownership passed
+ wxImage::AddHandler(new wxPNGHandler/*ownership passed*/); //activate support for .png files
//do we need xBRZ scaling for high quality DPI images?
const int hqScale = std::clamp(numeric::intDivCeil(fastFromDIP(1000), 1000), 1, xbrz::SCALE_FACTOR_MAX);
diff --git a/wx+/image_tools.cpp b/wx+/image_tools.cpp
index ccbd05e2..2df24b6e 100644
--- a/wx+/image_tools.cpp
+++ b/wx+/image_tools.cpp
@@ -169,6 +169,7 @@ wxImage zen::stackImages(const wxImage& img1, const wxImage& img2, ImageStackLay
wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const wxColor& col, ImageStackAlignment textAlign)
{
wxMemoryDC dc; //the context used for bitmaps
+ setScaleFactor(dc, getDisplayScaleFactor());
dc.SetFont(font); //the font parameter of GetMultiLineTextExtent() is not evaluated on OS X, wxWidgets 2.9.5, so apply it to the DC directly!
std::vector<std::pair<wxString, wxSize>> lineInfo; //text + extent
@@ -187,8 +188,9 @@ wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const
return wxNullImage;
wxBitmap newBitmap(maxWidth, lineHeight * lineInfo.size()); //seems we don't need to pass 24-bit depth here even for high-contrast color schemes
+ newBitmap.SetScaleFactor(getDisplayScaleFactor());
{
- dc.SelectObject(newBitmap);
+ dc.SelectObject(newBitmap); //copies scale factor from wxBitmap
ZEN_ON_SCOPE_EXIT(dc.SelectObject(wxNullBitmap));
if (wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft)
diff --git a/wx+/image_tools.h b/wx+/image_tools.h
index c2fed4c1..bfd107d0 100644
--- a/wx+/image_tools.h
+++ b/wx+/image_tools.h
@@ -61,13 +61,6 @@ wxImage resizeCanvas(const wxImage& img, wxSize newSize, int alignment);
-inline
-int getDefaultMenuIconSize()
-{
- return fastFromDIP(20);
-}
-
-
diff --git a/wx+/popup_dlg.cpp b/wx+/popup_dlg.cpp
index c163b037..0a4c75c0 100644
--- a/wx+/popup_dlg.cpp
+++ b/wx+/popup_dlg.cpp
@@ -34,18 +34,20 @@ void setBestInitialSize(wxRichTextCtrl& ctrl, const wxString& text, wxSize maxSi
if (maxSize.x <= scrollbarWidth) //implicitly checks for non-zero, too!
return;
+ const int rowGap = 0;
int maxLineWidth = 0;
- int rowCount = 0;
int rowHeight = 0;
+ int rowCount = 0;
bool haveLineWrap = false;
auto evalLineExtent = [&](const wxSize& sz) -> bool //return true when done
{
+ assert(rowHeight == 0 || rowHeight == sz.y + rowGap); //all rows *should* have same height
+ rowHeight = std::max(rowHeight, sz.y + rowGap);
maxLineWidth = std::max(maxLineWidth, sz.x);
const int wrappedRows = numeric::intDivCeil(sz.x, maxSize.x - scrollbarWidth); //round up: consider line-wraps!
rowCount += wrappedRows;
- rowHeight = std::max(rowHeight, sz.y); //all rows *should* have same height
if (wrappedRows > 1)
haveLineWrap = true;
@@ -68,20 +70,23 @@ void setBestInitialSize(wxRichTextCtrl& ctrl, const wxString& text, wxSize maxSi
it = itEnd + 1;
}
-#if 1 //wxRichTextCtrl
- const int rowGap = 0;
- const int extraHeight = 0;
-#else //wxTextCtrl
- const int rowGap = 0;
- const int extraHeight = 0;
-#endif
int extraWidth = 0;
if (haveLineWrap) //compensate for trivial intDivCeil() not...
extraWidth += ctrl.GetTextExtent(L"FreeFileSync").x / 2; //...understanding line wrap algorithm
- const wxSize bestSize(std::min(maxLineWidth, maxSize.x) + extraWidth,
- std::min(rowCount * (rowHeight + rowGap) + extraHeight, maxSize.y));
+ const wxSize bestSize(std::min(maxLineWidth + scrollbarWidth /*1*/+ extraWidth, maxSize.x),
+ std::min(rowHeight * (rowCount + 1 /*2*/), maxSize.y));
+ //1: wxWidgets' layout algorithm sucks: e.g. shows scrollbar *nedlessly* => extra line wrap increases height => scrollbar suddenly *needed*: catch 22!
+ //2: add some vertical space just for looks (*instead* of using border gap)! Extra space needed anyway to avoid scrollbars on Windows (2 px) and macOS (11 px)
+
ctrl.SetMinSize(bestSize); //alas, SetMinClientSize() is just not working!
+#if 0
+ std::cout << "rowCount " << rowCount << "\n" <<
+ "maxLineWidth " << maxLineWidth << "\n" <<
+ "rowHeight " << rowHeight << "\n" <<
+ "haveLineWrap " << haveLineWrap << "\n" <<
+ "scrollbarWidth " << scrollbarWidth << "\n\n";
+#endif
}
}
@@ -173,8 +178,7 @@ public:
if (!cfg.textDetail.empty())
{
- const wxString& text = trimCpy(cfg.textDetail) + L'\n'; //add empty line *instead* of using border space!
-
+ const wxString& text = trimCpy(cfg.textDetail);
setBestInitialSize(*m_richTextDetail, text, wxSize(maxWidth, maxHeight));
setTextWithUrls(*m_richTextDetail, text);
}
@@ -214,6 +218,26 @@ public:
}
//------------------------------------------------------------------------------
+
+ auto setButtonImage = [&](wxButton& button, ConfirmationButton3 btnType)
+ {
+ auto it = cfg.buttonImages.find(btnType);
+ if (it != cfg.buttonImages.end())
+ setImage(button, it->second); //caveat: image + text at the same time not working on GTK < 2.6
+ };
+ setButtonImage(*m_buttonAccept, ConfirmationButton3::accept);
+ setButtonImage(*m_buttonAccept2, ConfirmationButton3::accept2);
+ setButtonImage(*m_buttonDecline, ConfirmationButton3::decline);
+ setButtonImage(*m_buttonCancel, ConfirmationButton3::cancel);
+
+
+ if (cfg.disabledButtons.contains(ConfirmationButton3::accept )) m_buttonAccept ->Disable();
+ if (cfg.disabledButtons.contains(ConfirmationButton3::accept2)) m_buttonAccept2->Disable();
+ if (cfg.disabledButtons.contains(ConfirmationButton3::decline)) m_buttonDecline->Disable();
+ assert(!cfg.disabledButtons.contains(ConfirmationButton3::cancel));
+ assert(!cfg.disabledButtons.contains(cfg.buttonToDisableWhenChecked));
+
+
StdButtons stdBtns;
stdBtns.setAffirmative(m_buttonAccept);
if (labelAccept.empty()) //notification dialog
@@ -251,18 +275,12 @@ public:
stdBtns.setAffirmativeAll(m_buttonAccept2);
}
}
+ //set std order after button visibility was set
+ setStandardButtonLayout(*bSizerStdButtons, stdBtns);
- if (cfg.disabledButtons.contains(ConfirmationButton3::accept )) m_buttonAccept ->Disable();
- if (cfg.disabledButtons.contains(ConfirmationButton3::accept2)) m_buttonAccept2->Disable();
- if (cfg.disabledButtons.contains(ConfirmationButton3::decline)) m_buttonDecline->Disable();
- assert(!cfg.disabledButtons.contains(ConfirmationButton3::cancel));
- assert(!cfg.disabledButtons.contains(cfg.buttonToDisableWhenChecked));
updateGui();
- //set std order after button visibility was set
- setStandardButtonLayout(*bSizerStdButtons, stdBtns);
-
GetSizer()->SetSizeHints(this); //~=Fit() + SetMinSize()
Center(); //needs to be re-applied after a dialog size change!
diff --git a/wx+/popup_dlg.h b/wx+/popup_dlg.h
index 12c19c14..ca4a7591 100644
--- a/wx+/popup_dlg.h
+++ b/wx+/popup_dlg.h
@@ -7,7 +7,8 @@
#ifndef POPUP_DLG_H_820780154723456
#define POPUP_DLG_H_820780154723456
-#include <set>
+#include <unordered_set>
+#include <unordered_map>
#include <zen/zstring.h>
#include <wx/window.h>
#include <wx/bitmap.h>
@@ -19,8 +20,6 @@ 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 Icons.zip, see <wx+/image_resources.h>
-struct PopupDialogCfg;
-
enum class DialogInfoType
{
info,
@@ -53,6 +52,8 @@ enum class QuestionButton2
no = static_cast<int>(ConfirmationButton3::decline),
};
+struct PopupDialogCfg;
+
void showNotificationDialog(wxWindow* parent, DialogInfoType type, const PopupDialogCfg& cfg);
ConfirmationButton showConfirmationDialog(wxWindow* parent, DialogInfoType type, const PopupDialogCfg& cfg, const wxString& labelAccept);
ConfirmationButton2 showConfirmationDialog(wxWindow* parent, DialogInfoType type, const PopupDialogCfg& cfg, const wxString& labelAccept, const wxString& labelAccept2);
@@ -69,6 +70,7 @@ struct PopupDialogCfg
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& disableButton(ConfirmationButton3 button) { disabledButtons.insert(button); return *this; }
+ PopupDialogCfg& setButtonImage(ConfirmationButton3 button, const wxImage& img) { buttonImages.emplace(button, img); return *this; }
PopupDialogCfg& alertWhenPending(const Zstring& soundFilePath) { soundFileAlertPending = soundFilePath; return *this; }
PopupDialogCfg& setCheckBox(bool& value, const wxString& label, ConfirmationButton3 disableWhenChecked = ConfirmationButton3::cancel)
{
@@ -85,7 +87,8 @@ private:
wxString title;
wxString textMain;
wxString textDetail;
- std::set<ConfirmationButton3> disabledButtons;
+ std::unordered_set<ConfirmationButton3> disabledButtons;
+ std::unordered_map<ConfirmationButton3, wxImage> buttonImages;
Zstring soundFileAlertPending;
bool* checkBoxValue = nullptr; //in/out
wxString checkBoxLabel;
diff --git a/wx+/rtl.h b/wx+/rtl.h
index b59b5d14..9eb25bb6 100644
--- a/wx+/rtl.h
+++ b/wx+/rtl.h
@@ -64,11 +64,15 @@ void drawBitmapRtlMirror(wxDC& dc, const wxImage& img, const wxRect& rect, int a
return impl::drawBitmapAligned(dc, img, rect, alignment);
case wxLayout_RightToLeft:
+ if (rect.GetWidth() > 0 && rect.GetHeight() > 0)
{
- if (!buffer || buffer->GetWidth() != rect.width || buffer->GetHeight() < rect.height) //[!] since we do a mirror, width needs to match exactly!
- buffer = wxBitmap(rect.width, rect.height);
+ if (!buffer || buffer->GetSize() != rect.GetSize()) //[!] since we do a mirror, width needs to match exactly!
+ buffer.emplace(rect.GetSize());
- wxMemoryDC memDc(*buffer);
+ if (buffer->GetScaleFactor() != dc.GetContentScaleFactor()) //needed here?
+ buffer->SetScaleFactor(dc.GetContentScaleFactor()); //
+
+ wxMemoryDC memDc(*buffer); //copies scale factor from wxBitmap
memDc.Blit(wxPoint(0, 0), rect.GetSize(), &dc, rect.GetTopLeft()); //blit in: background is mirrored due to memDc, dc having different layout direction!
impl::drawBitmapAligned(memDc, img, wxRect(0, 0, rect.width, rect.height), alignment);
diff --git a/wx+/std_button_layout.h b/wx+/std_button_layout.h
index 72756041..fbbee1b7 100644
--- a/wx+/std_button_layout.h
+++ b/wx+/std_button_layout.h
@@ -32,6 +32,20 @@ void setStandardButtonLayout(wxBoxSizer& sizer, const StdButtons& buttons = StdB
//sizer width will change! => call wxWindow::Fit and wxWindow::Layout
+inline
+int getDefaultMenuIconSize()
+{
+ return fastFromDIP(20);
+}
+
+
+inline
+int getDefaultButtonHeight()
+{
+ const int defaultHeight = wxButton::GetDefaultSize().GetHeight(); //buffered by wxWidgets
+ return std::max(defaultHeight, fastFromDIP(31)); //default button height is much too small => increase!
+}
+
@@ -103,8 +117,7 @@ void setStandardButtonLayout(wxBoxSizer& sizer, const StdButtons& buttons)
if (btn)
{
assert(btn->GetMinSize().GetHeight() == -1); //let OS or this routine do the sizing! note: OS X does not allow changing the (visible!) button height!
- const int defaultHeight = wxButton::GetDefaultSize().GetHeight(); //buffered by wxWidgets
- btn->SetMinSize({-1, std::max(defaultHeight, fastFromDIP(31))}); //default button height is much too small => increase!
+ btn->SetMinSize({-1, getDefaultButtonHeight()});
if (settingFirstButton)
settingFirstButton = false;
bgstack15