Vadim Zeitlin pushed to branch master at wxWidgets / wxWidgets
Commits:
8d7c1c6b by Maarten Bent at 2026-06-13T21:14:18+02:00
Fix setting overlay opacity when wxGC is disabled
- - - - -
8746823e by Maarten Bent at 2026-06-13T21:15:14+02:00
Fix overlay in drawing sample when wxGC is disabled
- - - - -
89d19214 by Maarten Bent at 2026-06-13T21:15:23+02:00
Enable saving SVG for graphics context page in drawing sample
- - - - -
8bf3e155 by Maarten Bent at 2026-06-13T22:21:30+02:00
Support pen and brush styles in wxSVGGraphicsContext
SVG does not allow redefining patterns with the same ID, so write each pattern only once.
- - - - -
8386a984 by Vadim Zeitlin at 2026-06-16T20:00:59+02:00
Restrict the new size after DPI change to the display size
wxSizer::GetMinSize() can return a size bigger than the display size,
but we never want to use such size for the window, so ensure that it
fits the display client area.
This also ensures that the window doesn't become bigger than its max
size.
- - - - -
75284bb8 by Vadim Zeitlin at 2026-06-16T20:05:11+02:00
Ensure the window origin is visible after DPI change
Keep the window origin on its display to avoid moving it out of visible
area, which is unexpected and inconvenient.
- - - - -
863e46bb by Vadim Zeitlin at 2026-06-16T20:19:11+02:00
Limit maximum height of wxTreeCtrl best size
A tree control with many items could return a size much bigger than the
size of the screen, resulting in any window containing it and computing
its fitting size becoming vertically maximized, which is not the
expected behaviour as other controls, e.g. multiline wxTextCtrl, don't
behave like this.
Arbitrarily limit the best height to ~20 items.
- - - - -
2da4ea97 by Vadim Zeitlin at 2026-06-20T15:48:13+02:00
Move code for updating sizers on DPI change to wxSizer itself
Replacing the existing global UpdateSizerOnDPIChange() with a member
function will allow accessing private wxSizer variables in it (see the
next commit) and making it virtual will allow overriding it in the
derived classes to update more fields on DPI change.
No real changes yet.
This commit is best viewed with Git --color-moved option.
- - - - -
3a1bcddd by Vadim Zeitlin at 2026-06-20T15:50:14+02:00
Update wxSizer own min size on DPI change
We already updated the min size of wxSizerItem containing the sizer, but when
the sizer has a fixed min size set, this size needs to be updated as well, so
do it too in UpdateOnDPIChange().
See #26498.
- - - - -
0245dea9 by Vadim Zeitlin at 2026-06-20T15:51:21+02:00
Update wxGridSizer gap sizes on DPI change
Rescale gaps between rows/columns when the DPI changes.
See #26498.
- - - - -
81ac052c by Vadim Zeitlin at 2026-06-20T16:57:52+02:00
Always set both components of pane sizer item min size
wxAUI layout uses min size (1,1) if no min size is explicitly set for
the pane but if an explicit size was given in one direction, it used
best size in the other, unspecified, direction, which was unexpected,
especially if the best size of the window was big, as setting min size
resulted in dramatically increasing the pane size.
Now we still set the other component of min size to 1 in this case,
which avoids such surprises.
Closes #26557.
- - - - -
a5932c8a by Vadim Zeitlin at 2026-06-20T18:36:58+02:00
Revert "Force standard button foreground color when highlighted on MSW"
This reverts commit f3ab568a02723dc8b2957bce3b3ee6779698e8d8 because
people do want to use the selected foreground colour even in "current"
state, see #26453.
A better solution will be implemented for the problem of #22721 which
was originally solved by this commit, see #25806.
- - - - -
e069b7f4 by Jorge Moraleda at 2026-06-21T16:02:48+02:00
Add wxGrid::GetFrozenRowLabelWindow() and GetFrozenColLabelWindow()
These accessors for the frozen row and column label sub-windows were
missing from the public API even though the equivalent data cell windows
(GetFrozenRowGridWindow/GetFrozenColGridWindow) are already public.
Without them it is impossible to bind events (e.g. EVT_MOTION) to the
frozen label strips from outside the wxGrid implementation.
Closes #26617.
- - - - -
e786a4c7 by Vadim Zeitlin at 2026-06-21T16:21:54+02:00
Use a variant of background colour in hot state for the buttons
Instead of ignoring the user-set background colour and always using the
system default colour in the hot (a.k.a. current) state, use a slightly
different shade of the custom colour.
This avoids, or at least reduces, problems with the button text becoming
unreadable on the default background but still makes the button change
its visual appearance when the mouse hovers over it.
See #22721, #25806, #26453.
- - - - -
52360028 by Vadim Zeitlin at 2026-06-21T16:30:59+02:00
Merge branch 'svggc-pen-brush' of github.com:MaartenBent/wxWidgets
Support pen and brush styles in wxSVGGraphicsContext.
See #26586.
- - - - -
e871f1a8 by Blake-Madden at 2026-06-21T18:51:38+02:00
Add wxWebView::PrintToPDF()
Add a possibility to save the page as PDF, possibly with some
non-default print settings.
Closes #26583.
- - - - -
17e1af0a by Vadim Zeitlin at 2026-06-22T14:29:16+02:00
Merge branch 'msw-dpi-change-fixes'
Fixes for behaviour after DPI change in wxMSW.
Closes #26498.
See #26604.
- - - - -
0a6b26ea by Vadim Zeitlin at 2026-06-22T14:34:26+02:00
Merge branch 'msw-button-fg-col'
Respect user-set button foreground colour in wxMSW.
See #26618.
- - - - -
25 changed files:
- include/wx/generic/grid.h
- include/wx/gtk/webview_webkit.h
- include/wx/msw/private/webview_edge.h
- include/wx/msw/webview_edge.h
- include/wx/osx/webview_webkit.h
- include/wx/private/svg.h
- include/wx/sizer.h
- include/wx/webview.h
- interface/wx/grid.h
- interface/wx/webview.h
- samples/drawing/drawing.cpp
- samples/webview/webview.cpp
- src/aui/framemanager.cpp
- src/common/dcsvg.cpp
- src/common/sizer.cpp
- src/common/svggc.cpp
- src/common/treebase.cpp
- src/common/webview.cpp
- src/gtk/webview_webkit2.cpp
- src/msw/anybutton.cpp
- src/msw/nonownedwnd.cpp
- src/msw/overlay.cpp
- src/msw/webview_edge.cpp
- src/msw/window.cpp
- src/osx/
webview_webkit.mm
Changes:
=====================================
include/wx/generic/grid.h
=====================================
@@ -2456,6 +2456,8 @@ public:
wxWindow* GetFrozenCornerGridWindow()const { return (wxWindow*)m_frozenCornerGridWin; }
wxWindow* GetFrozenRowGridWindow() const { return (wxWindow*)m_frozenRowGridWin; }
wxWindow* GetFrozenColGridWindow() const { return (wxWindow*)m_frozenColGridWin; }
+ wxWindow* GetFrozenRowLabelWindow() const { return (wxWindow*)m_rowFrozenLabelWin; }
+ wxWindow* GetFrozenColLabelWindow() const { return m_colFrozenLabelWin; }
wxWindow* GetGridRowLabelWindow() const { return (wxWindow*)m_rowLabelWin; }
wxWindow* GetGridColLabelWindow() const { return m_colLabelWin; }
wxWindow* GetGridCornerLabelWindow() const { return (wxWindow*)m_cornerLabelWin; }
=====================================
include/wx/gtk/webview_webkit.h
=====================================
@@ -81,6 +81,12 @@ public:
#else
using wxWebView::Print;
#endif
+#endif
+#if wxUSE_WEBVIEW_WEBKIT2
+ virtual bool PrintToPDF(const wxString& filePath) override;
+#if wxUSE_PRINTING_ARCHITECTURE
+ virtual bool PrintToPDF(const wxString& filePath, const wxPrintData& printData) override;
+#endif
#endif
virtual bool IsBusy() const override;
#if wxUSE_WEBVIEW_WEBKIT2
=====================================
include/wx/msw/private/webview_edge.h
=====================================
@@ -57,6 +57,8 @@ __CRT_UUID_DECL(ICoreWebView2_16, 0x0EB34DC9,0x9F91,0x41E1, 0x86,0x39,0x95,0xCD,
__CRT_UUID_DECL(ICoreWebView2PrintSettings, 0x377f3721,0xc74e,0x48ca, 0x8d,0xb1,0xdf,0x68,0xe5,0x1d,0x60,0xe2);
__CRT_UUID_DECL(ICoreWebView2PrintSettings2, 0xCA7F0E1F,0x3484,0x41D1, 0x8C,0x1A,0x65,0xCD,0x44,0xA6,0x3F,0x8D);
__CRT_UUID_DECL(ICoreWebView2PrintCompletedHandler, 0x8fd80075,0xed08,0x42db, 0x85,0x70,0xf5,0xd1,0x49,0x77,0x46,0x1e);
+__CRT_UUID_DECL(ICoreWebView2PrintToPdfCompletedHandler, 0xccf1ef04,0xfd8e,0x4d5f, 0xb2,0xde,0x09,0x83,0xe4,0x1b,0x8c,0x36);
+__CRT_UUID_DECL(ICoreWebView2_7, 0x79c24d83,0x09a3,0x45ae, 0x94,0x18,0x48,0x7f,0x32,0xa5,0x87,0x40);
#endif
using wxStringToWebHandlerMap = std::unordered_map<wxString, wxSharedPtr<wxWebViewHandler>>;
=====================================
include/wx/msw/webview_edge.h
=====================================
@@ -18,6 +18,7 @@
#include "wx/webview.h"
class wxWebViewEdgeImpl;
+struct ICoreWebView2PrintSettings;
class WXDLLIMPEXP_WEBVIEW wxWebViewEdge : public wxWebView
{
@@ -73,6 +74,11 @@ public:
using wxWebView::Print;
#endif
+ virtual bool PrintToPDF(const wxString& filePath) override;
+#if wxUSE_PRINTING_ARCHITECTURE
+ virtual bool PrintToPDF(const wxString& filePath, const wxPrintData& printData) override;
+#endif
+
virtual float GetZoomFactor() const override;
virtual void SetZoomFactor(float zoom) override;
@@ -124,6 +130,8 @@ protected:
private:
wxWebViewEdgeImpl* m_impl;
+ bool DoCallPrintToPdf(const wxString& filePath, ICoreWebView2PrintSettings* printSettings);
+
void OnSize(wxSizeEvent& event);
void OnSetFocus(wxFocusEvent& event);
=====================================
include/wx/osx/webview_webkit.h
=====================================
@@ -56,6 +56,11 @@ public:
using wxWebView::Print;
#endif
+ virtual bool PrintToPDF(const wxString& filePath) override;
+#if wxUSE_PRINTING_ARCHITECTURE
+ virtual bool PrintToPDF(const wxString& filePath, const wxPrintData& printData) override;
+#endif
+
virtual void LoadURL(const wxString& url) override;
virtual wxString GetCurrentURL() const override;
virtual wxString GetCurrentTitle() const override;
=====================================
include/wx/private/svg.h
=====================================
@@ -26,6 +26,7 @@
#endif
#include <memory>
+#include <set>
class WXDLLIMPEXP_FWD_CORE wxBitmap;
@@ -46,7 +47,7 @@ wxString GetPenStroke(const wxColour& c, int style = wxPENSTYLE_SOLID);
wxString GetBrushFill(const wxColour& c, int style = wxBRUSHSTYLE_SOLID);
// Returns a <pattern> element definition for hatched brushes, or empty.
-wxString CreateBrushFill(const wxBrush& brush, wxSVGShapeRenderingMode mode);
+wxString CreateBrushFill(const wxBrush& brush, wxSVGShapeRenderingMode mode, wxString& patternName);
// Returns a "shape-rendering=..." attribute fragment.
wxString GetRenderMode(wxSVGShapeRenderingMode style);
@@ -123,6 +124,9 @@ public:
// handler on first use). Sets the write-error flag on failure.
void WriteBitmap(const wxBitmap& bmp, wxCoord x, wxCoord y);
+ // Writes a brush fill pattern if it has not been written before
+ void WriteBrushFill(const wxBrush& brush);
+
// Returns the next gradient/clip id and increments the shared counter.
size_t GetNextGradientId() { return ms_gradientUniqueId++; }
size_t GetNextClipId() { return ms_clipUniqueId++; }
@@ -182,6 +186,8 @@ private:
int m_layerDepth = 0;
int m_clipNestingLevel = 0;
+ std::set<wxString> m_usedBrushPatterns;
+
static size_t ms_clipUniqueId;
static size_t ms_gradientUniqueId;
=====================================
include/wx/sizer.h
=====================================
@@ -748,6 +748,15 @@ public:
virtual bool InformFirstDirection( int WXUNUSED(direction), int WXUNUSED(size), int WXUNUSED(availableOtherDir) )
{ return false; }
+ // Update stored dimensions expressed in logical pixels on DPI change.
+ // This is only needed on the platforms where logical pixels differ from
+ // the physical ones, e.g MSW.
+ //
+ // This is an internal function, only called by wxWidgets itself.
+#ifndef wxHAS_DPI_INDEPENDENT_PIXELS
+ virtual void UpdateOnDPIChange(wxSize oldDPI, wxSize newDPI);
+#endif // !wxHAS_DPI_INDEPENDENT_PIXELS
+
protected:
wxSize m_size;
wxSize m_minSize;
@@ -822,6 +831,10 @@ public:
// (for internal use only)
int CalcRowsCols(int& rows, int& cols) const;
+#ifndef wxHAS_DPI_INDEPENDENT_PIXELS
+ virtual void UpdateOnDPIChange(wxSize oldDPI, wxSize newDPI) override;
+#endif // !wxHAS_DPI_INDEPENDENT_PIXELS
+
protected:
// the number of rows/columns in the sizer, if 0 then it is determined
// dynamically depending on the total number of items
=====================================
include/wx/webview.h
=====================================
@@ -275,6 +275,13 @@ public:
virtual void Print() = 0;
#if wxUSE_PRINTING_ARCHITECTURE
virtual void Print(const wxPrintData& printData, int flags = wxWEBVIEW_PRINT_DEFAULT);
+#endif
+ virtual bool PrintToPDF(const wxString& WXUNUSED(filePath))
+ { return false; }
+#if wxUSE_PRINTING_ARCHITECTURE
+ virtual bool PrintToPDF(const wxString& WXUNUSED(filePath),
+ const wxPrintData& WXUNUSED(printData))
+ { return false; }
#endif
virtual void RegisterHandler(wxSharedPtr<wxWebViewHandler> handler) = 0;
virtual void Reload(wxWebViewReloadFlags flags = wxWEBVIEW_RELOAD_DEFAULT) = 0;
@@ -460,6 +467,7 @@ wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_FULLSCREEN_CHANGED,
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, wxWebViewEvent);
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_SCRIPT_RESULT, wxWebViewEvent);
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_BROWSING_DATA_CLEARED, wxWebViewEvent);
+wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_PDF_SAVED, wxWebViewEvent);
typedef void (wxEvtHandler::*wxWebViewEventFunction)
(wxWebViewEvent&);
@@ -507,6 +515,10 @@ typedef void (wxEvtHandler::*wxWebViewEventFunction)
wx__DECLARE_EVT1(wxEVT_WEBVIEW_SCRIPT_RESULT, id, \
wxWebViewEventHandler(fn))
+#define EVT_WEBVIEW_PDF_SAVED(id, fn) \
+ wx__DECLARE_EVT1(wxEVT_WEBVIEW_PDF_SAVED, id, \
+ wxWebViewEventHandler(fn))
+
// old wxEVT_COMMAND_* constants
#define wxEVT_COMMAND_WEBVIEW_NAVIGATING wxEVT_WEBVIEW_NAVIGATING
#define wxEVT_COMMAND_WEBVIEW_NAVIGATED wxEVT_WEBVIEW_NAVIGATED
=====================================
interface/wx/grid.h
=====================================
@@ -6182,6 +6182,28 @@ public:
*/
wxWindow* GetFrozenColGridWindow() const;
+ /**
+ Return the row labels window containing frozen cells.
+
+ This window is shown only when there are frozen rows.
+ This window is not shown if the rows labels were hidden using
+ HideRowLabels().
+
+ @since 3.3.3
+ */
+ wxWindow* GetFrozenRowLabelWindow() const;
+
+ /**
+ Return the column labels window containing frozen cells.
+
+ This window is shown only when there are frozen columns.
+ This window is not shown if the columns labels were hidden using
+ HideColLabels().
+
+ @since 3.3.3
+ */
+ wxWindow* GetFrozenColLabelWindow() const;
+
/**
Return the row labels window.
=====================================
interface/wx/webview.h
=====================================
@@ -1040,6 +1040,12 @@ public:
Process a @c wxEVT_WEBVIEW_BROWSING_DATA_CLEARED event
only available in wxWidgets 3.3.0 or later. For usage details see
ClearBrowsingData().
+ @event{EVT_WEBVIEW_PDF_SAVED(id, func)}
+ Process a @c wxEVT_WEBVIEW_PDF_SAVED event, generated when a
+ PrintToPDF() operation completes. Use wxWebViewEvent::GetURL() to
+ retrieve the output file path and wxWebViewEvent::IsError() to check
+ whether the save succeeded.
+ Only available in wxWidgets 3.3.3 or later.
@endEventTable
@since 2.9.3
@@ -1308,6 +1314,54 @@ public:
virtual void Print(const wxPrintData& printData,
int flags = wxWEBVIEW_PRINT_HIDE_HEADER_FOOTER);
+ /**
+ Saves the currently displayed page as a PDF file to @a filePath.
+
+ This operation is asynchronous. When it completes, a
+ @c wxEVT_WEBVIEW_PDF_SAVED event is generated. Use
+ wxWebViewEvent::GetURL() to retrieve the output file path and
+ wxWebViewEvent::IsError() to check whether the operation succeeded.
+
+ @return @true if the export was started successfully, @false if the
+ backend does not support PDF export or if an error prevented the
+ operation from starting.
+
+ @note Currently implemented on the Edge (MSW), WebKit (macOS 11.0+),
+ and WebKit2GTK (GTK) backends. Returns @false on all other
+ backends.
+
+ @see PrintToPDF(const wxString&, const wxPrintData&)
+
+ @since 3.3.3
+ */
+ virtual bool PrintToPDF(const wxString& filePath);
+
+ /**
+ Saves the currently displayed page as a PDF file using the given print
+ settings.
+
+ This overload allows specifying paper size and orientation via
+ @a printData. Backend support for these settings varies:
+
+ - Edge (MSW): paper size (derived from the wxPrintData paper ID) and
+ orientation are both applied to the output PDF.
+ - macOS: @a printData is not used; this behaves identically to
+ PrintToPDF(const wxString&).
+ - GTK (WebKit2GTK): paper size, orientation, copies, and collation
+ are all applied to the output PDF.
+
+ This overload is only available when @c wxUSE_PRINTING_ARCHITECTURE is
+ set to 1.
+
+ @return @true if the export was started successfully, @false if the
+ backend does not support PDF export.
+
+ @see PrintToPDF(const wxString&)
+
+ @since 3.3.3
+ */
+ virtual bool PrintToPDF(const wxString& filePath, const wxPrintData& printData);
+
/**
Registers a custom scheme handler.
@param handler A shared pointer to a wxWebHandler.
@@ -2153,7 +2207,8 @@ public:
/**
Returns @true if the operation failed.
Only valid for events of type
- @c wxEVT_WEBVIEW_SCRIPT_RESULT and @c wxEVT_WEBVIEW_BROWSING_DATA_CLEARED
+ @c wxEVT_WEBVIEW_SCRIPT_RESULT, @c wxEVT_WEBVIEW_BROWSING_DATA_CLEARED
+ and @c wxEVT_WEBVIEW_PDF_SAVED
@since 3.1.6
*/
@@ -2184,3 +2239,4 @@ wxEventType wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED;
wxEventType wxEVT_WEBVIEW_SCRIPT_RESULT;
wxEventType wxEVT_WEBVIEW_WINDOW_CLOSE_REQUESTED;
wxEventType wxEVT_WEBVIEW_BROWSING_DATA_CLEARED;
+wxEventType wxEVT_WEBVIEW_PDF_SAVED;
=====================================
samples/drawing/drawing.cpp
=====================================
@@ -39,6 +39,7 @@
#include "wx/stdpaths.h"
#if wxUSE_SVG
#include "wx/dcsvg.h"
+#include "wx/svggc.h"
#endif
#if wxUSE_POSTSCRIPT
#include "wx/dcps.h"
@@ -2159,6 +2160,12 @@ void MyCanvas::Draw(wxDC& pdc)
{
context = m_renderer->CreateContext(*metadc);
}
+#endif
+#if wxUSE_SVG
+ else if ( wxSVGFileDC *svgdc = wxDynamicCast(&pdc, wxSVGFileDC) )
+ {
+ context = wxSVGGraphicsContext::Create(*svgdc);
+ }
#endif
else
{
@@ -2339,8 +2346,10 @@ void MyCanvas::OnMouseMove(wxMouseEvent &event)
m_currentpoint = wxPoint( xx , yy ) ;
wxRect newrect ( m_anchorpoint , m_currentpoint ) ;
+#if wxUSE_GRAPHICS_CONTEXT
// This is required with wxMSW to allow per-pixel transparency.
m_overlay.SetOpacity(-1);
+#endif
wxOverlayDC dc(m_overlay, this);
PrepareDC(dc);
@@ -2348,12 +2357,21 @@ void MyCanvas::OnMouseMove(wxMouseEvent &event)
// Note: this must be called on the overlay DC, not wxGCDC.
dc.Clear();
+#if wxUSE_GRAPHICS_CONTEXT
// Use wxGCDC to ensure that brush transparency is taken into account
// even under wxMSW where plain wxDC doesn't support it.
wxGCDC gdc(dc);
gdc.SetPen( *wxGREY_PEN );
gdc.SetBrush( wxColour( 192,192,192,64 ) );
gdc.DrawRectangle( newrect );
+#else
+ // Set the overlay opacity instead of brush transparency.
+ m_overlay.SetOpacity(64);
+
+ dc.SetPen( *wxGREY_PEN );
+ dc.SetBrush( wxColour( 192,192,192 ) );
+ dc.DrawRectangle( newrect );
+#endif
}
#else
wxUnusedVar(event);
@@ -2840,15 +2858,6 @@ void MyFrame::OnSave(wxCommandEvent& WXUNUSED(event))
#if wxUSE_SVG
if (ext == "svg")
{
-#if wxUSE_GRAPHICS_CONTEXT
- // Graphics screen can only be drawn using GraphicsContext
- if (m_canvas->GetPage() == File_ShowGraphics) {
- wxLogMessage("Graphics screen can not be saved as SVG.");
- return;
- }
- wxGraphicsRenderer* tempRenderer = m_canvas->GetRenderer();
- m_canvas->UseGraphicRenderer(nullptr);
-#endif
wxSize svgSize;
wxSVGFileDC tempSvgDC(svgSize);
m_canvas->Draw(tempSvgDC);
@@ -2859,9 +2868,6 @@ void MyFrame::OnSave(wxCommandEvent& WXUNUSED(event))
wxSVGFileDC svgDC(svgSize, dlg.GetPath(), "Drawing sample");
svgDC.SetBitmapHandler(new wxSVGBitmapEmbedHandler());
m_canvas->Draw(svgDC);
-#if wxUSE_GRAPHICS_CONTEXT
- m_canvas->UseGraphicRenderer(tempRenderer);
-#endif
}
else
#endif
=====================================
samples/webview/webview.cpp
=====================================
@@ -50,6 +50,7 @@
#if wxUSE_PRINTING_ARCHITECTURE
#include "wx/cmndata.h"
#include "wx/choicdlg.h"
+#include "wx/filedlgcustomize.h"
#endif
#ifndef wxHAS_IMAGES_IN_RESOURCES
@@ -163,6 +164,10 @@ public:
void OnError(wxWebViewEvent& evt);
void OnPrint(wxCommandEvent& evt);
void OnPrintWithSettings(wxCommandEvent& evt);
+ void OnPrintToPDF(wxCommandEvent& evt);
+#if wxUSE_PRINTING_ARCHITECTURE && (defined(__WXMSW__) || defined(__WXGTK__))
+ void OnPrintToPDFWithSettings(wxCommandEvent& evt);
+#endif
void OnOpenPrivateWindow(wxCommandEvent& evt);
void OnCut(wxCommandEvent& evt);
void OnCopy(wxCommandEvent& evt);
@@ -605,6 +610,14 @@ WebFrame::WebFrame(const wxString& url, int flags, wxWebViewWindowFeatures* wind
}
+ m_browser->Bind(wxEVT_WEBVIEW_PDF_SAVED, [](wxWebViewEvent& event) {
+ if (event.IsError())
+ wxLogError("Failed to save PDF to '%s'", event.GetURL());
+ else
+ wxLogMessage("PDF saved to '%s'", event.GetURL());
+ event.Skip();
+ });
+
m_browser->Bind(wxEVT_WEBVIEW_BROWSING_DATA_CLEARED, [](wxWebViewEvent& event) {
if (event.IsError())
wxLogError("Failed to clear browsing data");
@@ -646,6 +659,10 @@ WebFrame::WebFrame(const wxString& url, int flags, wxWebViewWindowFeatures* wind
wxMenuItem* print = m_tools_menu->Append(wxID_ANY , _("Print"));
#if wxUSE_PRINTING_ARCHITECTURE
wxMenuItem* printWithSettings = m_tools_menu->Append(wxID_ANY , _("Print with Settings..."));
+#endif
+ wxMenuItem* printToPDF = m_tools_menu->Append(wxID_ANY, _("Save as PDF..."));
+#if wxUSE_PRINTING_ARCHITECTURE && (defined(__WXMSW__) || defined(__WXGTK__))
+ wxMenuItem* printToPDFWithSettings = m_tools_menu->Append(wxID_ANY, _("Save as PDF with Settings..."));
#endif
wxMenuItem* setPage = m_tools_menu->Append(wxID_ANY , _("Set page text"));
wxMenuItem* viewSource = m_tools_menu->Append(wxID_ANY , _("View Source"));
@@ -814,6 +831,10 @@ WebFrame::WebFrame(const wxString& url, int flags, wxWebViewWindowFeatures* wind
Bind(wxEVT_MENU, &WebFrame::OnPrint, this, print->GetId());
#if wxUSE_PRINTING_ARCHITECTURE
Bind(wxEVT_MENU, &WebFrame::OnPrintWithSettings, this, printWithSettings->GetId());
+#endif
+ Bind(wxEVT_MENU, &WebFrame::OnPrintToPDF, this, printToPDF->GetId());
+#if wxUSE_PRINTING_ARCHITECTURE && (defined(__WXMSW__) || defined(__WXGTK__))
+ Bind(wxEVT_MENU, &WebFrame::OnPrintToPDFWithSettings, this, printToPDFWithSettings->GetId());
#endif
Bind(wxEVT_MENU, &WebFrame::OnOpenPrivateWindow, this, openPrivate->GetId());
Bind(wxEVT_MENU, &WebFrame::OnZoomLayout, this, m_tools_layout->GetId());
@@ -1753,6 +1774,73 @@ void WebFrame::OnPrintWithSettings(wxCommandEvent& WXUNUSED(evt))
}
#endif // wxUSE_PRINTING_ARCHITECTURE
+void WebFrame::OnPrintToPDF(wxCommandEvent& WXUNUSED(evt))
+{
+ wxFileDialog dlg(this, _("Save as PDF"), wxEmptyString, wxEmptyString,
+ _("PDF files (*.pdf)|*.pdf"),
+ wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+ if (dlg.ShowModal() != wxID_OK)
+ return;
+
+ if (!m_browser->PrintToPDF(dlg.GetPath()))
+ wxLogError("PrintToPDF is not supported by this browser backend.");
+}
+
+#if wxUSE_PRINTING_ARCHITECTURE && (defined(__WXMSW__) || defined(__WXGTK__))
+
+class WebFramePDFSettingsHook : public wxFileDialogCustomizeHook
+{
+public:
+ void AddCustomControls(wxFileDialogCustomize& customizer) override
+ {
+ const wxString choices[] = {
+ _("Letter (Portrait)"), _("Letter (Landscape)"),
+ _("A4 (Portrait)"), _("A4 (Landscape)"),
+ _("Legal (Portrait)"), _("Legal (Landscape)")
+ };
+ customizer.AddStaticText(_("Paper size:"));
+ m_choice = customizer.AddChoice(WXSIZEOF(choices), choices);
+ m_choice->SetSelection(m_sel);
+ }
+
+ void TransferDataFromCustomControls() override
+ {
+ m_sel = m_choice->GetSelection();
+ }
+
+ int GetSelection() const { return m_sel; }
+
+private:
+ wxFileDialogChoice* m_choice = nullptr;
+ int m_sel = 2; // A4 Portrait
+};
+
+void WebFrame::OnPrintToPDFWithSettings(wxCommandEvent& WXUNUSED(evt))
+{
+ WebFramePDFSettingsHook hook;
+ wxFileDialog dlg(this, _("Save as PDF"), wxEmptyString, wxEmptyString,
+ _("PDF files (*.pdf)|*.pdf"),
+ wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+ dlg.SetCustomizeHook(hook);
+ if (dlg.ShowModal() != wxID_OK)
+ return;
+
+ wxPrintData printData;
+ switch (hook.GetSelection())
+ {
+ case 0: printData.SetPaperId(wxPAPER_LETTER); printData.SetOrientation(wxPORTRAIT); break;
+ case 1: printData.SetPaperId(wxPAPER_LETTER); printData.SetOrientation(wxLANDSCAPE); break;
+ case 2: printData.SetPaperId(wxPAPER_A4); printData.SetOrientation(wxPORTRAIT); break;
+ case 3: printData.SetPaperId(wxPAPER_A4); printData.SetOrientation(wxLANDSCAPE); break;
+ case 4: printData.SetPaperId(wxPAPER_LEGAL); printData.SetOrientation(wxPORTRAIT); break;
+ case 5: printData.SetPaperId(wxPAPER_LEGAL); printData.SetOrientation(wxLANDSCAPE); break;
+ }
+
+ if (!m_browser->PrintToPDF(dlg.GetPath(), printData))
+ wxLogError("PrintToPDF is not supported by this browser backend.");
+}
+#endif // wxUSE_PRINTING_ARCHITECTURE && (defined(__WXMSW__) || defined(__WXGTK__))
+
void WebFrame::OnOpenPrivateWindow(wxCommandEvent& WXUNUSED(evt))
{
WebFrame* newFrame = new WebFrame(m_browser->GetCurrentURL(), WebFrame::Private);
=====================================
src/aui/framemanager.cpp
=====================================
@@ -2504,8 +2504,7 @@ void wxAuiManager::LayoutAddPane(wxSizer* cont,
// We need to reset any previous set min size to allow decreasing the pane
// size by dragging the sash between it and other panes, so always set it
// to something, even if it's not specified.
- if (min_size == wxDefaultSize)
- min_size = wxSize(1, 1);
+ min_size.IncTo(wxSize(1, 1));
sizer_item->SetMinSize(min_size);
=====================================
src/common/dcsvg.cpp
=====================================
@@ -319,10 +319,10 @@ wxString GetRenderMode(wxSVGShapeRenderingMode style)
return s;
}
-wxString CreateBrushFill(const wxBrush& brush, wxSVGShapeRenderingMode mode)
+wxString CreateBrushFill(const wxBrush& brush, wxSVGShapeRenderingMode mode, wxString& patternName)
{
wxString s;
- wxString patternName = GetBrushStyleName(brush);
+ patternName = GetBrushStyleName(brush);
if (!patternName.empty())
{
@@ -1455,13 +1455,7 @@ void wxSVGFileDCImpl::SetBrush(const wxBrush& brush)
m_writer->MarkGraphicsChanged();
- wxString pattern = CreateBrushFill(m_brush, m_writer->GetShapeRenderingMode());
- if ( !pattern.empty() )
- {
- NewGraphicsIfNeeded();
-
- write(pattern);
- }
+ m_writer->WriteBrushFill(m_brush);
}
void wxSVGFileDCImpl::SetPen(const wxPen& pen)
@@ -1815,6 +1809,19 @@ void wxSVGWriter::WriteBitmap(const wxBitmap& bmp, wxCoord x, wxCoord y)
m_writeError = true;
}
+void wxSVGWriter::WriteBrushFill(const wxBrush& brush)
+{
+ if ( !brush.IsOk() )
+ return;
+
+ wxString patternName;
+ wxString pattern = CreateBrushFill(brush, GetShapeRenderingMode(), patternName);
+ if ( !pattern.empty() && !patternName.empty() && m_usedBrushPatterns.insert(patternName).second )
+ {
+ Write(pattern);
+ }
+}
+
#if wxUSE_GRAPHICS_CONTEXT
bool wxSVGWriter::SetCompositionMode(wxCompositionMode mode)
=====================================
src/common/sizer.cpp
=====================================
@@ -33,6 +33,10 @@
#include "wx/listimpl.cpp"
#include "wx/private/window.h"
+#ifndef wxHAS_DPI_INDEPENDENT_PIXELS
+ #include "wx/private/rescale.h"
+#endif // !wxHAS_DPI_INDEPENDENT_PIXELS
+
#include <memory>
//---------------------------------------------------------------------------
@@ -1615,6 +1619,46 @@ bool wxSizer::IsShown( size_t index ) const
return node->GetData()->IsShown();
}
+#ifndef wxHAS_DPI_INDEPENDENT_PIXELS
+
+// Recursively update the sizer and any child sizers and spacers.
+void wxSizer::UpdateOnDPIChange(wxSize oldDPI, wxSize newDPI)
+{
+ m_minSize = wxRescaleCoord(m_minSize).From(oldDPI).To(newDPI);
+
+ for ( wxSizerItemList::compatibility_iterator
+ node = GetChildren().GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxSizerItem* sizerItem = node->GetData();
+
+ int border = sizerItem->GetBorder();
+ border = wxRescaleCoord(border).From(oldDPI).To(newDPI);
+ sizerItem->SetBorder(border);
+
+ // only scale sizers and spacers, not windows
+ if ( sizerItem->IsSizer() || sizerItem->IsSpacer() )
+ {
+ wxSize min = sizerItem->GetMinSize();
+ min = wxRescaleCoord(min).From(oldDPI).To(newDPI);
+ sizerItem->SetMinSize(min);
+
+ if ( sizerItem->IsSpacer() )
+ {
+ wxSize size = sizerItem->GetSize();
+ size = wxRescaleCoord(size).From(oldDPI).To(newDPI);
+ sizerItem->SetDimension(wxDefaultPosition, size);
+ }
+
+ // Update any child sizers if this is a sizer
+ if ( wxSizer* childSizer = sizerItem->GetSizer() )
+ childSizer->UpdateOnDPIChange(oldDPI, newDPI);
+ }
+ }
+}
+
+#endif // !wxHAS_DPI_INDEPENDENT_PIXELS
//---------------------------------------------------------------------------
// wxGridSizer
@@ -1844,6 +1888,19 @@ void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
item->SetDimension(pt, sz);
}
+#ifndef wxHAS_DPI_INDEPENDENT_PIXELS
+
+// Recursively update the sizer and any child sizers and spacers.
+void wxGridSizer::UpdateOnDPIChange(wxSize oldDPI, wxSize newDPI)
+{
+ m_vgap = wxRescaleCoord(m_vgap).From(oldDPI).To(newDPI);
+ m_hgap = wxRescaleCoord(m_hgap).From(oldDPI).To(newDPI);
+
+ wxSizer::UpdateOnDPIChange(oldDPI, newDPI);
+}
+
+#endif // !wxHAS_DPI_INDEPENDENT_PIXELS
+
//---------------------------------------------------------------------------
// wxFlexGridSizer
//---------------------------------------------------------------------------
=====================================
src/common/svggc.cpp
=====================================
@@ -786,6 +786,21 @@ wxSVGGraphicsPenData::wxSVGGraphicsPenData(wxGraphicsRenderer* renderer,
m_pen.SetColour(info.GetColour());
m_pen.SetWidth(static_cast<int>(info.GetWidth() + 0.5));
m_pen.SetStyle(info.GetStyle());
+ m_pen.SetCap(info.GetCap());
+ m_pen.SetJoin(info.GetJoin());
+
+ if (m_pen.GetStyle() == wxPENSTYLE_USER_DASH)
+ {
+ wxDash* dashes;
+ if (int nb_dashes = info.GetDashes(&dashes))
+ m_pen.SetDashes(nb_dashes, dashes);
+ }
+
+ if (m_pen.GetStyle() == wxPENSTYLE_STIPPLE)
+ {
+ m_pen.SetStipple(info.GetStipple());
+ }
+
}
wxSVGGraphicsBrushData::wxSVGGraphicsBrushData(wxGraphicsRenderer* renderer, const wxBrush& brush)
@@ -1307,7 +1322,11 @@ void wxSVGGraphicsContext::SetBrush(const wxGraphicsBrush& brush)
auto* data = static_cast<wxSVGGraphicsBrushData*>(brush.GetRefData());
if ( data != nullptr )
+ {
+ m_writer->WriteBrushFill(data->GetBrush());
+
SyncBrushToDC(data->GetBrush());
+ }
}
void wxSVGGraphicsContext::SetFont(const wxGraphicsFont& font)
@@ -1408,11 +1427,12 @@ void wxSVGGraphicsContext::StrokePath(const wxGraphicsPath& path)
m_currentPen.GetStyle());
}
+ const wxString penPattern = wxSVG::GetPenPattern(m_currentPen);
const wxString transform = GetCurrentTransformAttr();
const wxString s = wxString::Format(
- wxS(" <path d=\"%s\" fill=\"none\" %s stroke-width=\"%d\"%s/>\n"),
- data->GetDString(), stroke, m_currentPen.GetWidth(), transform);
+ wxS(" <path d=\"%s\" fill=\"none\" %s stroke-width=\"%d\" %s%s/>\n"),
+ data->GetDString(), stroke, m_currentPen.GetWidth(), penPattern, transform);
m_writer->Write(s);
@@ -1435,6 +1455,13 @@ void wxSVGGraphicsContext::FillPath(const wxGraphicsPath& path, wxPolygonFillMod
if ( !m_brush.IsNull() )
fill = m_writer->WriteGraphicsBrushFill(m_brush);
+ if ( fill.empty() )
+ {
+ auto* brushData = static_cast<wxSVGGraphicsBrushData*>(m_brush.GetRefData());
+ if ( brushData )
+ fill = wxSVG::GetBrushPattern(brushData->GetBrush());
+ }
+
if ( fill.empty() )
{
fill = m_currentBrush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT
@@ -1443,13 +1470,14 @@ void wxSVGGraphicsContext::FillPath(const wxGraphicsPath& path, wxPolygonFillMod
m_currentBrush.GetStyle());
}
+ const wxString penPattern = wxSVG::GetPenPattern(m_currentPen);
const wxString transform = GetCurrentTransformAttr();
const wxString rule = (fillStyle == wxODDEVEN_RULE)
? wxS("evenodd") : wxS("nonzero");
const wxString s = wxString::Format(
- wxS(" <path d=\"%s\" %s fill-rule=\"%s\" stroke=\"none\"%s/>\n"),
- data->GetDString(), fill, rule, transform);
+ wxS(" <path d=\"%s\" %s fill-rule=\"%s\" stroke=\"none\" %s%s/>\n"),
+ data->GetDString(), fill, rule, penPattern, transform);
m_writer->Write(s);
=====================================
src/common/treebase.cpp
=====================================
@@ -210,6 +210,8 @@ namespace
{
// This is used to store context used for determining the best tree size.
+//
+// It should only be used for non-empty tree, i.e. with a valid root item.
class TreeSizer
{
public:
@@ -224,11 +226,7 @@ public:
wxSize GetSize() const
{
- const wxTreeItemId id = treeCtrl->GetRootItem();
- if ( !id.IsOk() )
- return wxSize(0, 0);
-
- return DoGetSizeOf(id, 1);
+ return DoGetSizeOf(treeCtrl->GetRootItem(), 1);
}
private:
@@ -295,6 +293,13 @@ wxSize TreeSizer::DoGetSizeOf(wxTreeItemId id, int depth) const
wxSize wxTreeCtrlBase::DoGetBestSize() const
{
+ const wxTreeItemId root = GetRootItem();
+ if ( !root.IsOk() )
+ {
+ // need some minimal size even for empty tree
+ return wxControl::DoGetBestSize();
+ }
+
wxSize size;
// this doesn't really compute the total bounding rectangle of all items
@@ -303,7 +308,7 @@ wxSize wxTreeCtrlBase::DoGetBestSize() const
if (GetQuickBestSize())
{
- for ( wxTreeItemId item = GetRootItem();
+ for ( wxTreeItemId item = root;
item.IsOk();
item = GetLastChild(item) )
{
@@ -327,11 +332,15 @@ wxSize wxTreeCtrlBase::DoGetBestSize() const
size = TreeSizer{this}.GetSize();
}
- // need some minimal size even for empty tree
- if ( !size.x || !size.y )
- size = wxControl::DoGetBestSize();
- else // add border size
- size += GetWindowBorderSize();
+ // Arbitrarily limit the tree height to ~20 lines of text because we don't
+ // want to make it too high even if it contains a lot of items.
+ const int maxHeight = 25 * GetCharHeight();
+
+ if ( size.y > maxHeight )
+ size.y = maxHeight;
+
+ // add border size
+ size += GetWindowBorderSize();
return size;
}
=====================================
src/common/webview.cpp
=====================================
@@ -60,6 +60,7 @@ wxDEFINE_EVENT( wxEVT_WEBVIEW_FULLSCREEN_CHANGED, wxWebViewEvent);
wxDEFINE_EVENT( wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, wxWebViewEvent);
wxDEFINE_EVENT( wxEVT_WEBVIEW_SCRIPT_RESULT, wxWebViewEvent);
wxDEFINE_EVENT( wxEVT_WEBVIEW_BROWSING_DATA_CLEARED, wxWebViewEvent);
+wxDEFINE_EVENT( wxEVT_WEBVIEW_PDF_SAVED, wxWebViewEvent);
// wxWebViewConfiguration
wxWebViewConfiguration::wxWebViewConfiguration(const wxString& backend, wxWebViewConfigurationImpl* impl):
=====================================
src/gtk/webview_webkit2.cpp
=====================================
@@ -32,6 +32,7 @@
#include "wx/log.h"
#include "wx/gtk/private/webview_webkit2_extension.h"
#include "wx/gtk/private/string.h"
+#include "wx/weakref.h"
#include "wx/gtk/private/webkit.h"
#include "wx/gtk/private/error.h"
#include "wx/gtk/private/object.h"
@@ -1465,8 +1466,9 @@ GtkPaperSize* wxWebViewGetGtkPaperSize(wxPaperSize paperId)
wxSize paperSizeTenthsMM = wxThePrintPaperDatabase->GetSize(paperId);
if (paperSizeTenthsMM.x > 0 && paperSizeTenthsMM.y > 0)
{
+ // "custom" is the internal name; "Custom" is the user-visible label
return gtk_paper_size_new_custom(
- "custom", "Custom",
+ "custom", _("Custom").utf8_str(),
paperSizeTenthsMM.x / 10.0, paperSizeTenthsMM.y / 10.0,
GTK_UNIT_MM);
}
@@ -1477,32 +1479,33 @@ GtkPaperSize* wxWebViewGetGtkPaperSize(wxPaperSize paperId)
} // anonymous namespace
-void wxWebViewWebKit::Print(const wxPrintData& printData, int WXUNUSED(flags))
+static void wxApplyPrintData(WebKitPrintOperation* printop,
+ GtkPrintSettings* settings,
+ const wxPrintData& printData)
{
- wxGtkObject<WebKitPrintOperation> printop(webkit_print_operation_new(m_web_view));
-
- // Use GtkPageSetup for paper size and orientation
wxGtkObject<GtkPageSetup> pageSetup(gtk_page_setup_new());
-
gtk_page_setup_set_orientation(pageSetup,
printData.GetOrientation() == wxLANDSCAPE
? GTK_PAGE_ORIENTATION_LANDSCAPE
: GTK_PAGE_ORIENTATION_PORTRAIT);
-
GtkPaperSize* paperSize = wxWebViewGetGtkPaperSize(printData.GetPaperId());
gtk_page_setup_set_paper_size_and_default_margins(pageSetup, paperSize);
gtk_paper_size_free(paperSize);
-
webkit_print_operation_set_page_setup(printop, pageSetup);
- // Use GtkPrintSettings for copies, collation, duplex, color
- wxGtkObject<GtkPrintSettings> settings(gtk_print_settings_new());
-
int copies = printData.GetNoCopies();
if (copies > 0)
gtk_print_settings_set_n_copies(settings, copies);
-
gtk_print_settings_set_collate(settings, printData.GetCollate());
+}
+
+void wxWebViewWebKit::Print(const wxPrintData& printData, int WXUNUSED(flags))
+{
+ wxGtkObject<WebKitPrintOperation> printop(webkit_print_operation_new(m_web_view));
+
+ wxGtkObject<GtkPrintSettings> settings(gtk_print_settings_new());
+
+ wxApplyPrintData(printop, settings, printData);
switch (printData.GetDuplex())
{
@@ -1525,6 +1528,97 @@ void wxWebViewWebKit::Print(const wxPrintData& printData, int WXUNUSED(flags))
}
#endif // wxUSE_PRINTING_ARCHITECTURE
+struct wxWebViewGtkPDFData
+{
+ wxWebViewGtkPDFData(wxWebViewWebKit* webView_,
+ const wxString& filePath_,
+ WebKitPrintOperation* printop_)
+ : webView(webView_), filePath(filePath_), printop(printop_) {}
+ ~wxWebViewGtkPDFData() { g_object_unref(printop); }
+
+ wxWeakRef<wxWebViewWebKit> webView;
+ wxString filePath;
+ WebKitPrintOperation* printop;
+};
+
+static void wxDoHandlePDFResult(gpointer user_data, int success)
+{
+ wxWebViewGtkPDFData* data = static_cast<wxWebViewGtkPDFData*>(user_data);
+ if (data->webView)
+ {
+ wxWebViewEvent event(wxEVT_WEBVIEW_PDF_SAVED, data->webView->GetId(),
+ data->filePath, wxString());
+ event.SetInt(success);
+ event.SetEventObject(data->webView);
+ data->webView->HandleWindowEvent(event);
+ }
+ delete data;
+}
+
+extern "C"
+{
+
+static void
+wxgtk_webview_webkit_pdf_finished(WebKitPrintOperation*,
+ gpointer user_data)
+{
+ wxDoHandlePDFResult(user_data, 1);
+}
+
+static void
+wxgtk_webview_webkit_pdf_failed(WebKitPrintOperation*,
+ GError*,
+ gpointer user_data)
+{
+ wxDoHandlePDFResult(user_data, 0);
+}
+
+} // extern "C"
+
+static bool wxDoStartPDFPrint(wxWebViewWebKit* webView,
+ const wxString& filePath,
+ const void* printData = nullptr)
+{
+ wxGtkString uri(g_filename_to_uri(filePath.utf8_str(), nullptr, nullptr));
+ if (!uri)
+ return false;
+
+ WebKitPrintOperation* printop = webkit_print_operation_new(
+ static_cast<WebKitWebView*>(webView->GetNativeBackend()));
+
+ wxGtkObject<GtkPrintSettings> settings(gtk_print_settings_new());
+ // Do NOT translate this; this is the name of the "printer" that GTK looks up
+ gtk_print_settings_set_printer(settings, "Print to File");
+ gtk_print_settings_set(settings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT, "pdf");
+ gtk_print_settings_set(settings, GTK_PRINT_SETTINGS_OUTPUT_URI, uri);
+
+#if wxUSE_PRINTING_ARCHITECTURE
+ if (printData)
+ wxApplyPrintData(printop, settings, *static_cast<const wxPrintData*>(printData));
+#endif
+
+ webkit_print_operation_set_print_settings(printop, settings);
+
+ wxWebViewGtkPDFData* data = new wxWebViewGtkPDFData{webView, filePath, printop};
+ g_signal_connect(printop, "finished", G_CALLBACK(wxgtk_webview_webkit_pdf_finished), data);
+ g_signal_connect(printop, "failed", G_CALLBACK(wxgtk_webview_webkit_pdf_failed), data);
+
+ webkit_print_operation_print(printop);
+ return true;
+}
+
+bool wxWebViewWebKit::PrintToPDF(const wxString& filePath)
+{
+ return wxDoStartPDFPrint(this, filePath);
+}
+
+#if wxUSE_PRINTING_ARCHITECTURE
+bool wxWebViewWebKit::PrintToPDF(const wxString& filePath, const wxPrintData& printData)
+{
+ return wxDoStartPDFPrint(this, filePath, &printData);
+}
+#endif // wxUSE_PRINTING_ARCHITECTURE
+
bool wxWebViewWebKit::IsBusy() const
{
return m_busy;
=====================================
src/msw/anybutton.cpp
=====================================
@@ -1262,10 +1262,59 @@ void DrawXPBackground(wxAnyButton *button, HDC hdc, RECT& rectBtn, UINT state)
TMT_CONTENTMARGINS, &rectBtn, &margins);
::InflateRect(&rectBtn, -margins.cxLeftWidth, -margins.cyTopHeight);
- if ( button->UseBgCol() && iState != PBS_HOT )
+ if ( button->UseBgCol() )
{
- COLORREF colBg = wxColourToRGB(button->GetBackgroundColour());
- AutoHBRUSH hbrushBackground(colBg);
+ wxColour col = button->GetBackgroundColour();
+
+ // We don't currently have a way to specify a different background
+ // colour for the hot/current state, but we want it to be visually
+ // different from the normal state, so construct a slightly different
+ // shade of this colour automatically.
+#if wxUSE_IMAGE
+ if ( iState == PBS_HOT )
+ {
+ wxImage::RGBValue rgb(col.Red(), col.Green(), col.Blue());
+ wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
+
+ // If the background is light, make it slightly darker, otherwise
+ // make it lighter.
+ //
+ // Note that we assume that the contrast with the text will remain
+ // good enough, a better solution would be to check the contrast
+ // and somehow find the shade of the background colour which still
+ // gives sufficient contrast with the text colour, but this is more
+ // complicated and this simple version works well enough for the
+ // colours with sufficient contrast.
+ double valueHot = hsv.value;
+ if ( hsv.value < 0.5 )
+ {
+ valueHot += 0.2;
+
+ // Don't make it completely white.
+ if ( valueHot > 0.95 )
+ {
+ // But also don't make it darker than the original colour.
+ valueHot = wxMax(0.95, hsv.value);
+ }
+ }
+ else // Same logic as above, but in reverse.
+ {
+ valueHot -= 0.2;
+
+ if ( valueHot < 0.05 )
+ {
+ hsv.value = wxMin(0.05, hsv.value);
+ }
+ }
+
+ hsv.value = valueHot;
+
+ rgb = wxImage::HSVtoRGB(hsv);
+ col = wxColour(rgb.red, rgb.green, rgb.blue);
+ }
+#endif // wxUSE_IMAGE
+
+ AutoHBRUSH hbrushBackground(wxColourToRGB(col));
FillRect(hdc, &rectBtn, hbrushBackground);
}
@@ -1506,22 +1555,9 @@ bool wxAnyButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis)
// finally draw the label
if ( ShowsLabel() )
{
- COLORREF colFg;
- if ( state & ODS_DISABLED )
- {
- colFg = ::GetSysColor(COLOR_GRAYTEXT);
- }
- else if ( wxUxThemeIsActive() &&
- GetButtonState(this, state) == wxAnyButton::State_Current )
- {
- // The button is highlighted, use the standard colour to ensure
- // that its text is readable.
- colFg = ::GetSysColor(COLOR_BTNTEXT);
- }
- else
- {
- colFg = wxColourToRGB(GetForegroundColour());
- }
+ COLORREF colFg = state & ODS_DISABLED
+ ? ::GetSysColor(COLOR_GRAYTEXT)
+ : wxColourToRGB(GetForegroundColour());
wxTextColoursChanger changeFg(hdc, colFg, CLR_INVALID);
wxBkModeChanger changeBkMode(hdc, wxBRUSHSTYLE_TRANSPARENT);
=====================================
src/msw/nonownedwnd.cpp
=====================================
@@ -34,6 +34,7 @@
#include "wx/graphics.h"
#endif // wxUSE_GRAPHICS_CONTEXT
+#include "wx/display.h"
#include "wx/dynlib.h"
#include "wx/msw/missing.h"
#include "wx/msw/private/darkmode.h"
@@ -318,7 +319,7 @@ bool wxNonOwnedWindow::HandleDPIChange(const wxSize& newDPI, const wxRect& newRe
wxRect actualNewRect = newRect;
if ( wxSizer* sizer = GetSizer() )
{
- const wxSize minSize = ClientToWindowSize(sizer->GetMinSize());
+ const wxSize minSize = sizer->ComputeFittingClientSize(this);
wxSize diff = minSize - newRect.GetSize();
// We don't want to shrink the window as if the user had increased
@@ -338,6 +339,14 @@ bool wxNonOwnedWindow::HandleDPIChange(const wxSize& newDPI, const wxRect& newRe
// which it might have been just moved to this one, as doing this
// would result in an infinite stream of WM_DPICHANGED messages.
actualNewRect.Inflate(diff / 2);
+
+ // However still ensure that the window origin is visible on its
+ // display, we don't move to move it out of visible space.
+ const wxRect screenRect = wxDisplay(this).GetClientArea();
+ if ( actualNewRect.x < screenRect.x )
+ actualNewRect.x = screenRect.x;
+ if ( actualNewRect.y < screenRect.y )
+ actualNewRect.y = screenRect.y;
}
SetSize(actualNewRect);
=====================================
src/msw/overlay.cpp
=====================================
@@ -274,6 +274,8 @@ void wxOverlayImpl::SetOpacity(int alpha)
m_alpha = wxClip(alpha, -1, 255);
}
else if ( IsUsingConstantOpacity() )
+#else
+ if ( IsOk() )
#endif // wxUSE_GRAPHICS_CONTEXT
{
m_alpha = wxClip(alpha, 0, 255);
=====================================
src/msw/webview_edge.cpp
=====================================
@@ -1472,6 +1472,83 @@ void wxWebViewEdge::Print(const wxPrintData& printData, int flags)
}
#endif // wxUSE_PRINTING_ARCHITECTURE
+bool wxWebViewEdge::DoCallPrintToPdf(const wxString& filePath, ICoreWebView2PrintSettings* printSettings)
+{
+ wxCOMPtr<ICoreWebView2_7> webView7;
+ if (FAILED(m_impl->m_webView->QueryInterface(IID_PPV_ARGS(&webView7))))
+ {
+ wxLogError(_("PDF export requires a newer version of the WebView2 runtime."));
+ return false;
+ }
+
+ const wxString filePathCopy = filePath;
+ HRESULT hr = webView7->PrintToPdf(
+ filePath.wc_str(),
+ printSettings,
+ Callback<ICoreWebView2PrintToPdfCompletedHandler>(
+ [this, filePathCopy](HRESULT errorCode, BOOL isSuccessful) -> HRESULT
+ {
+ wxWebViewEvent* event = new wxWebViewEvent(wxEVT_WEBVIEW_PDF_SAVED, GetId(), filePathCopy, wxString());
+ event->SetInt((SUCCEEDED(errorCode) && isSuccessful) ? 1 : 0);
+ event->SetEventObject(this);
+ QueueEvent(event);
+ return S_OK;
+ }).Get());
+
+ if (FAILED(hr))
+ {
+ wxLogApiError("ICoreWebView2_7::PrintToPdf", hr);
+ return false;
+ }
+ return true;
+}
+
+bool wxWebViewEdge::PrintToPDF(const wxString& filePath)
+{
+ if (!m_impl->m_webView)
+ return false;
+
+ return DoCallPrintToPdf(filePath, nullptr);
+}
+
+#if wxUSE_PRINTING_ARCHITECTURE
+bool wxWebViewEdge::PrintToPDF(const wxString& filePath, const wxPrintData& printData)
+{
+ if (!m_impl->m_webView)
+ return false;
+
+ wxCOMPtr<ICoreWebView2Environment6> environment6;
+ if (FAILED(m_impl->m_webViewEnvironment->QueryInterface(IID_PPV_ARGS(&environment6))))
+ return PrintToPDF(filePath);
+
+ wxCOMPtr<ICoreWebView2PrintSettings> printSettings;
+ HRESULT hr = environment6->CreatePrintSettings(&printSettings);
+ if (FAILED(hr))
+ {
+ wxLogApiError("CreatePrintSettings", hr);
+ return PrintToPDF(filePath);
+ }
+
+ printSettings->put_Orientation(
+ printData.GetOrientation() == wxLANDSCAPE
+ ? COREWEBVIEW2_PRINT_ORIENTATION_LANDSCAPE
+ : COREWEBVIEW2_PRINT_ORIENTATION_PORTRAIT);
+
+ wxSize paperSizeTenthsMM = wxThePrintPaperDatabase->GetSize(printData.GetPaperId());
+ if (paperSizeTenthsMM.x > 0 && paperSizeTenthsMM.y > 0)
+ {
+ double widthInches = paperSizeTenthsMM.x / 254.0;
+ double heightInches = paperSizeTenthsMM.y / 254.0;
+ printSettings->put_PageWidth(widthInches);
+ printSettings->put_PageHeight(heightInches);
+ }
+
+ printSettings->put_ShouldPrintHeaderAndFooter(FALSE);
+
+ return DoCallPrintToPdf(filePath, printSettings);
+}
+#endif // wxUSE_PRINTING_ARCHITECTURE
+
float wxWebViewEdge::GetZoomFactor() const
{
double old_zoom_factor = 0.0;
=====================================
src/msw/window.cpp
=====================================
@@ -5011,46 +5011,6 @@ void wxWindowMSW::MSWUpdateFontOnDPIChange(const wxSize& newDPI)
}
}
-// Called from MSWUpdateonDPIChange() to recursively update the window
-// sizer and any child sizers and spacers.
-static void UpdateSizerOnDPIChange(wxSizer* sizer, wxSize oldDPI, wxSize newDPI)
-{
- if ( !sizer )
- {
- return;
- }
-
- for ( wxSizerItemList::compatibility_iterator
- node = sizer->GetChildren().GetFirst();
- node;
- node = node->GetNext() )
- {
- wxSizerItem* sizerItem = node->GetData();
-
- int border = sizerItem->GetBorder();
- border = wxRescaleCoord(border).From(oldDPI).To(newDPI);
- sizerItem->SetBorder(border);
-
- // only scale sizers and spacers, not windows
- if ( sizerItem->IsSizer() || sizerItem->IsSpacer() )
- {
- wxSize min = sizerItem->GetMinSize();
- min = wxRescaleCoord(min).From(oldDPI).To(newDPI);
- sizerItem->SetMinSize(min);
-
- if ( sizerItem->IsSpacer() )
- {
- wxSize size = sizerItem->GetSize();
- size = wxRescaleCoord(size).From(oldDPI).To(newDPI);
- sizerItem->SetDimension(wxDefaultPosition, size);
- }
-
- // Update any child sizers if this is a sizer
- UpdateSizerOnDPIChange(sizerItem->GetSizer(), oldDPI, newDPI);
- }
- }
-}
-
bool
wxWindowMSW::MSWUpdateOnDPIChange(const wxSize& oldDPI, const wxSize& newDPI)
{
@@ -5069,7 +5029,8 @@ wxWindowMSW::MSWUpdateOnDPIChange(const wxSize& oldDPI, const wxSize& newDPI)
MSWUpdateFontOnDPIChange(newDPI);
// update sizers
- UpdateSizerOnDPIChange(GetSizer(), oldDPI, newDPI);
+ if ( wxSizer* const sizer = GetSizer() )
+ sizer->UpdateOnDPIChange(oldDPI, newDPI);
// update children
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
=====================================
src/osx/
webview_webkit.mm
=====================================
@@ -546,6 +546,41 @@ void wxWebViewWebKit::Print(const wxPrintData& printData, int WXUNUSED(flags))
}
#endif // wxUSE_PRINTING_ARCHITECTURE
+bool wxWebViewWebKit::PrintToPDF(const wxString& filePath)
+{
+ if (!m_webView)
+ return false;
+
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0
+ if (WX_IS_MACOS_AVAILABLE(11, 0))
+ {
+ const wxString filePathCopy = filePath;
+ [m_webView createPDFWithConfiguration:nil
+ completionHandler:^(NSData* pdfData, NSError* error)
+ {
+ bool success = (error == nil && pdfData != nil);
+ if (success)
+ success = [pdfData writeToFile:wxCFStringRef(filePathCopy).AsNSString()
+ atomically:YES];
+ wxWebViewEvent event(wxEVT_WEBVIEW_PDF_SAVED, GetId(), filePathCopy, wxString());
+ event.SetInt(success ? 1 : 0);
+ event.SetEventObject(this);
+ ProcessWindowEvent(event);
+ }];
+ return true;
+ }
+#endif // macOS 11.0+
+ return false;
+}
+
+#if wxUSE_PRINTING_ARCHITECTURE
+bool wxWebViewWebKit::PrintToPDF(const wxString& filePath, const wxPrintData& WXUNUSED(printData))
+{
+ // WKWebView's PDF export doesn't expose paper size or orientation settings.
+ return PrintToPDF(filePath);
+}
+#endif // wxUSE_PRINTING_ARCHITECTURE
+
void wxWebViewWebKit::SetEditable(bool WXUNUSED(enable))
{
}
View it on GitLab:
https://gitlab.com/wxwidgets/wxwidgets/-/compare/0ec0518993731403e52f7703be03e6b452f8c8a5...0a6b26ea435f69fb8ea9fd764c1e06cdc148587c
--
View it on GitLab:
https://gitlab.com/wxwidgets/wxwidgets/-/compare/0ec0518993731403e52f7703be03e6b452f8c8a5...0a6b26ea435f69fb8ea9fd764c1e06cdc148587c
You're receiving this email because of your account on
gitlab.com. Manage all notifications:
https://gitlab.com/-/profile/notifications | Help:
https://gitlab.com/help