diff --git a/.github/workflows/code_checks.yml b/.github/workflows/code_checks.yml
index 121701be0b..fc46f8354c 100644
--- a/.github/workflows/code_checks.yml
+++ b/.github/workflows/code_checks.yml
@@ -41,3 +41,28 @@ jobs:
- name: Run codespell
run: |
CODESPELL=$HOME/.local/bin/codespell ./misc/scripts/spellcheck
+
+
+ check-whitespace:
+ runs-on: ubuntu-20.04
+ name: Check Whitespace
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Check for trailing whitespace and TABs
+ run: |
+ git fetch --depth=1 origin master
+ git -c core.whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol,tab-in-indent \
+ diff --check origin/master \
+ ':!Makefile.in' \
+ ':!config.guess' \
+ ':!config.sub' \
+ ':!configure' \
+ ':!descrip.mms' \
+ ':!install-sh' \
+ ':!**/*akefile*' \
+ ':!**/*.sln' \
+ ':!**/*.vcproj' \
+ ':!**/*.xpm'
diff --git a/Makefile.in b/Makefile.in
index 62beaa8482..74838af176 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -949,8 +949,8 @@ MONODLL_CFLAGS = $(__monodll_PCH_INC) $(__INC_TIFF_BUILD_p) $(__INC_TIFF_p) \
-I$(top_srcdir)/src/stc/scintilla/include \
-I$(top_srcdir)/src/stc/scintilla/lexlib \
-I$(top_srcdir)/src/stc/scintilla/src -D__WX__ -DSCI_LEXER -DNO_CXX11_REGEX \
- -DLINK_LEXERS -DwxUSE_BASE=1 -DWXMAKINGDLL $(__webviewdll_ext_dir_define_p) \
- $(PIC_FLAG) $(WX_CFLAGS) $(CPPFLAGS) $(CFLAGS)
+ -DLINK_LEXERS -DwxUSE_BASE=1 -DWXMAKINGDLL $(PIC_FLAG) $(WX_CFLAGS) \
+ $(CPPFLAGS) $(CFLAGS)
MONODLL_CXXFLAGS = $(__monodll_PCH_INC) $(__INC_TIFF_BUILD_p) $(__INC_TIFF_p) \
$(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) $(__INC_REGEX_p) \
$(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p) \
@@ -959,8 +959,8 @@ MONODLL_CXXFLAGS = $(__monodll_PCH_INC) $(__INC_TIFF_BUILD_p) $(__INC_TIFF_p) \
-I$(top_srcdir)/src/stc/scintilla/include \
-I$(top_srcdir)/src/stc/scintilla/lexlib \
-I$(top_srcdir)/src/stc/scintilla/src -D__WX__ -DSCI_LEXER -DNO_CXX11_REGEX \
- -DLINK_LEXERS -DwxUSE_BASE=1 -DWXMAKINGDLL $(__webviewdll_ext_dir_define_p) \
- $(PIC_FLAG) $(WX_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS)
+ -DLINK_LEXERS -DwxUSE_BASE=1 -DWXMAKINGDLL $(PIC_FLAG) $(WX_CXXFLAGS) \
+ $(CPPFLAGS) $(CXXFLAGS)
MONODLL_OBJCXXFLAGS = $(__monodll_PCH_INC) $(__INC_TIFF_BUILD_p) \
$(__INC_TIFF_p) $(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) \
$(__INC_REGEX_p) $(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ \
@@ -969,8 +969,8 @@ MONODLL_OBJCXXFLAGS = $(__monodll_PCH_INC) $(__INC_TIFF_BUILD_p) \
-I$(top_srcdir)/src/stc/scintilla/include \
-I$(top_srcdir)/src/stc/scintilla/lexlib \
-I$(top_srcdir)/src/stc/scintilla/src -D__WX__ -DSCI_LEXER -DNO_CXX11_REGEX \
- -DLINK_LEXERS -DwxUSE_BASE=1 -DWXMAKINGDLL $(__webviewdll_ext_dir_define_p) \
- $(PIC_FLAG) $(CPPFLAGS) $(OBJCXXFLAGS)
+ -DLINK_LEXERS -DwxUSE_BASE=1 -DWXMAKINGDLL $(PIC_FLAG) $(CPPFLAGS) \
+ $(OBJCXXFLAGS)
MONODLL_OBJECTS = \
monodll_any.o \
monodll_appbase.o \
@@ -1092,8 +1092,7 @@ MONOLIB_CFLAGS = $(__monolib_PCH_INC) $(__INC_TIFF_BUILD_p) $(__INC_TIFF_p) \
-I$(top_srcdir)/src/stc/scintilla/include \
-I$(top_srcdir)/src/stc/scintilla/lexlib \
-I$(top_srcdir)/src/stc/scintilla/src -D__WX__ -DSCI_LEXER -DNO_CXX11_REGEX \
- -DLINK_LEXERS -DwxUSE_BASE=1 $(__webviewdll_ext_dir_define_p) $(WX_CFLAGS) \
- $(CPPFLAGS) $(CFLAGS)
+ -DLINK_LEXERS -DwxUSE_BASE=1 $(WX_CFLAGS) $(CPPFLAGS) $(CFLAGS)
MONOLIB_CXXFLAGS = $(__monolib_PCH_INC) $(__INC_TIFF_BUILD_p) $(__INC_TIFF_p) \
$(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) $(__INC_REGEX_p) \
$(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p) \
@@ -1102,8 +1101,7 @@ MONOLIB_CXXFLAGS = $(__monolib_PCH_INC) $(__INC_TIFF_BUILD_p) $(__INC_TIFF_p) \
-I$(top_srcdir)/src/stc/scintilla/include \
-I$(top_srcdir)/src/stc/scintilla/lexlib \
-I$(top_srcdir)/src/stc/scintilla/src -D__WX__ -DSCI_LEXER -DNO_CXX11_REGEX \
- -DLINK_LEXERS -DwxUSE_BASE=1 $(__webviewdll_ext_dir_define_p) \
- $(WX_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS)
+ -DLINK_LEXERS -DwxUSE_BASE=1 $(WX_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS)
MONOLIB_OBJCXXFLAGS = $(__monolib_PCH_INC) $(__INC_TIFF_BUILD_p) \
$(__INC_TIFF_p) $(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) \
$(__INC_REGEX_p) $(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ \
@@ -1112,8 +1110,7 @@ MONOLIB_OBJCXXFLAGS = $(__monolib_PCH_INC) $(__INC_TIFF_BUILD_p) \
-I$(top_srcdir)/src/stc/scintilla/include \
-I$(top_srcdir)/src/stc/scintilla/lexlib \
-I$(top_srcdir)/src/stc/scintilla/src -D__WX__ -DSCI_LEXER -DNO_CXX11_REGEX \
- -DLINK_LEXERS -DwxUSE_BASE=1 $(__webviewdll_ext_dir_define_p) $(CPPFLAGS) \
- $(OBJCXXFLAGS)
+ -DLINK_LEXERS -DwxUSE_BASE=1 $(CPPFLAGS) $(OBJCXXFLAGS)
MONOLIB_OBJECTS = \
monolib_any.o \
monolib_appbase.o \
@@ -1669,16 +1666,15 @@ WEBVIEWDLL_CXXFLAGS = $(__webviewdll_PCH_INC) $(__INC_TIFF_BUILD_p) \
$(__INC_REGEX_p) $(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ \
$(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) $(__EXCEPTIONS_DEFINE_p) \
$(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) -DWXBUILDING -DWXUSINGDLL \
- -DWXMAKINGDLL_WEBVIEW $(__webviewdll_ext_dir_define_p) \
- $(__webview_additional_include_p) $(PIC_FLAG) $(WX_CXXFLAGS) $(CPPFLAGS) \
- $(CXXFLAGS)
+ -DWXMAKINGDLL_WEBVIEW $(__webview_additional_include_p) $(PIC_FLAG) \
+ $(WX_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS)
WEBVIEWDLL_OBJCXXFLAGS = $(__webviewdll_PCH_INC) $(__INC_TIFF_BUILD_p) \
$(__INC_TIFF_p) $(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) \
$(__INC_REGEX_p) $(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ \
$(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) $(__EXCEPTIONS_DEFINE_p) \
$(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) -DWXBUILDING -DWXUSINGDLL \
- -DWXMAKINGDLL_WEBVIEW $(__webviewdll_ext_dir_define_p) \
- $(__webview_additional_include_p) $(PIC_FLAG) $(CPPFLAGS) $(OBJCXXFLAGS)
+ -DWXMAKINGDLL_WEBVIEW $(__webview_additional_include_p) $(PIC_FLAG) \
+ $(CPPFLAGS) $(OBJCXXFLAGS)
WEBVIEWDLL_OBJECTS = \
$(__WEBVIEW_SRC_PLATFORM_OBJECTS_2) \
webviewdll_webview.o \
@@ -1691,15 +1687,13 @@ WEBVIEWLIB_CXXFLAGS = $(__webviewlib_PCH_INC) $(__INC_TIFF_BUILD_p) \
$(__INC_REGEX_p) $(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ \
$(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) $(__EXCEPTIONS_DEFINE_p) \
$(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) -DWXBUILDING \
- $(__webviewdll_ext_dir_define_p) $(__webview_additional_include_p) \
- $(WX_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS)
+ $(__webview_additional_include_p) $(WX_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS)
WEBVIEWLIB_OBJCXXFLAGS = $(__webviewlib_PCH_INC) $(__INC_TIFF_BUILD_p) \
$(__INC_TIFF_p) $(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) \
$(__INC_REGEX_p) $(__INC_EXPAT_p) $(WX_CPPFLAGS) -D__WX$(TOOLKIT)__ \
$(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) $(__EXCEPTIONS_DEFINE_p) \
$(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) -DWXBUILDING \
- $(__webviewdll_ext_dir_define_p) $(__webview_additional_include_p) \
- $(CPPFLAGS) $(OBJCXXFLAGS)
+ $(__webview_additional_include_p) $(CPPFLAGS) $(OBJCXXFLAGS)
WEBVIEWLIB_OBJECTS = \
$(__WEBVIEW_SRC_PLATFORM_OBJECTS_3) \
webviewlib_webview.o \
@@ -13341,9 +13335,6 @@ COND_PLATFORM_MACOSX_1___OSX_LOWLEVEL_SRC_OBJECTS = \
monodll_core_timer.o \
monodll_utilsexc_cf.o
@COND_PLATFORM_MACOSX_1@__OSX_LOWLEVEL_SRC_OBJECTS = $(COND_PLATFORM_MACOSX_1___OSX_LOWLEVEL_SRC_OBJECTS)
-COND_USE_WEBVIEW_WEBKIT2_1___webviewdll_ext_dir_define_p_0 = --define \
- WX_WEB_EXTENSIONS_DIRECTORY=\"$(PLUGINS_INST_DIR)/web-extensions\"
-@COND_USE_WEBVIEW_WEBKIT2_1@__webviewdll_ext_dir_define_p_0 = $(COND_USE_WEBVIEW_WEBKIT2_1___webviewdll_ext_dir_define_p_0)
@COND_PLATFORM_MACOSX_1@__PLATFORM_SRC_OBJECTS_0 = monolib_unix_apptraits.o
@COND_PLATFORM_UNIX_1@__PLATFORM_SRC_OBJECTS_0 = monolib_unix_apptraits.o
COND_PLATFORM_MACOSX_1___OSX_COMMON_SRC_OBJECTS_0 = \
@@ -13758,9 +13749,6 @@ COND_PLATFORM_MACOSX_1___OSX_LOWLEVEL_SRC_OBJECTS_1_4 = \
corelib_core_timer.o \
corelib_utilsexc_cf.o
@COND_PLATFORM_MACOSX_1@__OSX_LOWLEVEL_SRC_OBJECTS_1_4 = $(COND_PLATFORM_MACOSX_1___OSX_LOWLEVEL_SRC_OBJECTS_1_4)
-@COND_USE_WEBVIEW_WEBKIT2_1@__webviewdll_ext_dir_define_p \
-@COND_USE_WEBVIEW_WEBKIT2_1@ = \
-@COND_USE_WEBVIEW_WEBKIT2_1@ -DWX_WEB_EXTENSIONS_DIRECTORY=\"$(PLUGINS_INST_DIR)/web-extensions\"
@COND_TOOLKIT_MSW@__webview_additional_include_p = \
@COND_TOOLKIT_MSW@ -I$(top_srcdir)/3rdparty/webview2/build/native/include
@COND_MONOLITHIC_0_SHARED_1_USE_GUI_1_USE_HTML_1@__htmldll_library_link_DEP \
@@ -20872,7 +20860,7 @@ monodll_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONODLL_ODEP)
@COND_PLATFORM_MACOSX_1_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/html/chm.cpp
monodll_version_rc.o: $(srcdir)/src/msw/version.rc $(MONODLL_ODEP)
- $(WINDRES) -i$< -o$@ $(__INC_TIFF_BUILD_p_54) $(__INC_TIFF_p_54) $(__INC_JPEG_p_54) $(__INC_PNG_p_53) $(__INC_ZLIB_p_67) $(__INC_REGEX_p_65) $(__INC_EXPAT_p_65) --define __WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p_67) $(__DEBUG_DEFINE_p_66) $(__EXCEPTIONS_DEFINE_p_65) $(__RTTI_DEFINE_p_65) $(__THREAD_DEFINE_p_65) --define WXBUILDING --define WXDLLNAME=$(WXDLLNAMEPREFIXGUI)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)$(WXCOMPILER)$(VENDORTAG)$(WXDLLVERSIONTAG) $(__RCDEFDIR_p) --include-dir $(top_srcdir)/include --include-dir $(top_srcdir)/src/stc/scintilla/include --include-dir $(top_srcdir)/src/stc/scintilla/lexlib --include-dir $(top_srcdir)/src/stc/scintilla/src --define __WX__ --define SCI_LEXER --define NO_CXX11_REGEX --define LINK_LEXERS --define wxUSE_BASE=1 --define WXMAKINGDLL $(__webviewdll_ext_dir_define_p_0)
+ $(WINDRES) -i$< -o$@ $(__INC_TIFF_BUILD_p_54) $(__INC_TIFF_p_54) $(__INC_JPEG_p_54) $(__INC_PNG_p_53) $(__INC_ZLIB_p_67) $(__INC_REGEX_p_65) $(__INC_EXPAT_p_65) --define __WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p_67) $(__DEBUG_DEFINE_p_66) $(__EXCEPTIONS_DEFINE_p_65) $(__RTTI_DEFINE_p_65) $(__THREAD_DEFINE_p_65) --define WXBUILDING --define WXDLLNAME=$(WXDLLNAMEPREFIXGUI)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)$(WXCOMPILER)$(VENDORTAG)$(WXDLLVERSIONTAG) $(__RCDEFDIR_p) --include-dir $(top_srcdir)/include --include-dir $(top_srcdir)/src/stc/scintilla/include --include-dir $(top_srcdir)/src/stc/scintilla/lexlib --include-dir $(top_srcdir)/src/stc/scintilla/src --define __WX__ --define SCI_LEXER --define NO_CXX11_REGEX --define LINK_LEXERS --define wxUSE_BASE=1 --define WXMAKINGDLL
monolib_any.o: $(srcdir)/src/common/any.cpp $(MONOLIB_ODEP)
$(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/any.cpp
@@ -36010,7 +35998,7 @@ webviewdll_webviewfshandler.o: $(srcdir)/src/common/webviewfshandler.cpp $(WEBVI
$(CXXC) -c -o $@ $(WEBVIEWDLL_CXXFLAGS) $(srcdir)/src/common/webviewfshandler.cpp
webviewdll_version_rc.o: $(srcdir)/src/msw/version.rc $(WEBVIEWDLL_ODEP)
- $(WINDRES) -i$< -o$@ $(__INC_TIFF_BUILD_p_54) $(__INC_TIFF_p_54) $(__INC_JPEG_p_54) $(__INC_PNG_p_53) $(__INC_ZLIB_p_67) $(__INC_REGEX_p_65) $(__INC_EXPAT_p_65) --define __WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p_67) $(__DEBUG_DEFINE_p_66) $(__EXCEPTIONS_DEFINE_p_65) $(__RTTI_DEFINE_p_65) $(__THREAD_DEFINE_p_65) --define WXBUILDING --define WXDLLNAME=$(WXDLLNAMEPREFIXGUI)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)_webview$(WXCOMPILER)$(VENDORTAG)$(WXDLLVERSIONTAG) $(__RCDEFDIR_p) --include-dir $(top_srcdir)/include --define WXUSINGDLL --define WXMAKINGDLL_WEBVIEW $(__webviewdll_ext_dir_define_p_0) $(__webview_additional_include_p_1)
+ $(WINDRES) -i$< -o$@ $(__INC_TIFF_BUILD_p_54) $(__INC_TIFF_p_54) $(__INC_JPEG_p_54) $(__INC_PNG_p_53) $(__INC_ZLIB_p_67) $(__INC_REGEX_p_65) $(__INC_EXPAT_p_65) --define __WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p_67) $(__DEBUG_DEFINE_p_66) $(__EXCEPTIONS_DEFINE_p_65) $(__RTTI_DEFINE_p_65) $(__THREAD_DEFINE_p_65) --define WXBUILDING --define WXDLLNAME=$(WXDLLNAMEPREFIXGUI)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)_webview$(WXCOMPILER)$(VENDORTAG)$(WXDLLVERSIONTAG) $(__RCDEFDIR_p) --include-dir $(top_srcdir)/include --define WXUSINGDLL --define WXMAKINGDLL_WEBVIEW $(__webview_additional_include_p_1)
webviewlib_webview_ie.o: $(srcdir)/src/msw/webview_ie.cpp $(WEBVIEWLIB_ODEP)
$(CXXC) -c -o $@ $(WEBVIEWLIB_CXXFLAGS) $(srcdir)/src/msw/webview_ie.cpp
diff --git a/appveyor.yml b/appveyor.yml
index 0c75abc35b..0b43c6da5c 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -12,6 +12,7 @@ skip_commits:
- misc/
- include/wx/osx/
- src/osx/
+ - .github/workflows/
- .travis.yml
- build/tools/travis-ci.sh
- build/tools/before_install.sh
diff --git a/autoconf_inc.m4 b/autoconf_inc.m4
index eae0f23231..9f06e653b9 100644
--- a/autoconf_inc.m4
+++ b/autoconf_inc.m4
@@ -980,7 +980,7 @@ dnl ### begin block 20_COND_USE_THREADS_1[../../demos/bombs/bombs.bkl,../../demo
COND_USE_THREADS_1=""
fi
AC_SUBST(COND_USE_THREADS_1)
-dnl ### begin block 20_COND_USE_WEBVIEW_WEBKIT2_1[../../demos/bombs/bombs.bkl,../../demos/forty/forty.bkl,../../demos/fractal/fractal.bkl,../../demos/life/life.bkl,../../demos/poem/poem.bkl,../../samples/access/access.bkl,../../samples/animate/anitest.bkl,../../samples/archive/archive.bkl,../../samples/artprov/artprov.bkl,../../samples/aui/auidemo.bkl,../../samples/calendar/calendar.bkl,../../samples/caret/caret.bkl,../../samples/clipboard/clipboard.bkl,../../samples/collpane/collpane.bkl,../../samples/combo/combo.bkl,../../samples/config/config.bkl,../../samples/console/console.bkl,../../samples/dataview/dataview.bkl,../../samples/debugrpt/debugrpt.bkl,../../samples/dialogs/dialogs.bkl,../../samples/dialup/dialup.bkl,../../samples/display/display.bkl,../../samples/dll/dll.bkl,../../samples/dnd/dnd.bkl,../../samples/docview/docview.bkl,../../samples/dragimag/dragimag.bkl,../../samples/drawing/drawing.bkl,../../samples/erase/erase.bkl,../../samples/event/event.bkl,../../samples/except/except.bkl,../../samples/exec/exec.bkl,../../samples/font/font.bkl,../../samples/fswatcher/fswatcher.bkl,../../samples/grid/grid.bkl,../../samples/help/help.bkl,../../samples/htlbox/htlbox.bkl,../../samples/html/about/about.bkl,../../samples/html/help/help.bkl,../../samples/html/helpview/helpview.bkl,../../samples/html/htmlctrl/htmlctrl.bkl,../../samples/html/printing/printing.bkl,../../samples/html/test/test.bkl,../../samples/html/virtual/virtual.bkl,../../samples/html/widget/widget.bkl,../../samples/html/zip/zip.bkl,../../samples/image/image.bkl,../../samples/internat/internat.bkl,../../samples/ipc/ipc.bkl,../../samples/joytest/joytest.bkl,../../samples/keyboard/keyboard.bkl,../../samples/layout/layout.bkl,../../samples/listctrl/listctrl.bkl,../../samples/mdi/mdi.bkl,../../samples/mediaplayer/mediaplayer.bkl,../../samples/memcheck/memcheck.bkl,../../samples/menu/menu.bkl,../../samples/minimal/minimal.bkl,../../samples/nativdlg/nativdlg.bkl,../../samples/notebook/notebook.bkl,../../samples/oleauto/oleauto.bkl,../../samples/opengl/cube/cube.bkl,../../samples/opengl/isosurf/isosurf.bkl,../../samples/opengl/penguin/penguin.bkl,../../samples/opengl/pyramid/pyramid.bkl,../../samples/ownerdrw/ownerdrw.bkl,../../samples/popup/popup.bkl,../../samples/power/power.bkl,../../samples/preferences/preferences.bkl,../../samples/printing/printing.bkl,../../samples/propgrid/propgrid.bkl,../../samples/regtest/regtest.bkl,../../samples/render/render.bkl,../../samples/ribbon/ribbon.bkl,../../samples/richtext/richtext.bkl,../../samples/sashtest/sashtest.bkl,../../samples/scroll/scroll.bkl,../../samples/secretstore/secretstore.bkl,../../samples/shaped/shaped.bkl,../../samples/sockets/sockets.bkl,../../samples/sound/sound.bkl,../../samples/splash/splash.bkl,../../samples/splitter/splitter.bkl,../../samples/statbar/statbar.bkl,../../samples/stc/stctest.bkl,../../samples/svg/svgtest.bkl,../../samples/taborder/taborder.bkl,../../samples/taskbar/taskbar.bkl,../../samples/taskbarbutton/taskbarbutton.bkl,../../samples/text/text.bkl,../../samples/thread/thread.bkl,../../samples/toolbar/toolbar.bkl,../../samples/treectrl/treectrl.bkl,../../samples/treelist/treelist.bkl,../../samples/typetest/typetest.bkl,../../samples/uiaction/uiaction.bkl,../../samples/validate/validate.bkl,../../samples/vscroll/vscroll.bkl,../../samples/webview/webview.bkl,../../samples/widgets/widgets.bkl,../../samples/wizard/wizard.bkl,../../samples/wrapsizer/wrapsizer.bkl,../../samples/xrc/xrcdemo.bkl,../../samples/xti/xti.bkl,../../tests/benchmarks/bench.bkl,../../tests/test.bkl,../../utils/emulator/src/emulator.bkl,../../utils/execmon/execmon.bkl,../../utils/helpview/src/helpview.bkl,../../utils/hhp2cached/hhp2cached.bkl,../../utils/ifacecheck/src/ifacecheck.bkl,../../utils/screenshotgen/src/screenshotgen.bkl,../../utils/wxrc/wxrc.bkl,wx.bkl] ###
+dnl ### begin block 20_COND_USE_WEBVIEW_WEBKIT2_1[wx.bkl] ###
COND_USE_WEBVIEW_WEBKIT2_1="#"
if test "x$USE_WEBVIEW_WEBKIT2" = "x1" ; then
COND_USE_WEBVIEW_WEBKIT2_1=""
diff --git a/build/autogen.mk b/build/autogen.mk
index f72b447808..537a3f5438 100644
--- a/build/autogen.mk
+++ b/build/autogen.mk
@@ -56,7 +56,6 @@ ACLOCAL_SOURCES = \
build/aclocal/ax_func_which_gethostbyname_r.m4 \
build/aclocal/bakefile-lang.m4 \
build/aclocal/bakefile.m4 \
- build/aclocal/cppunit.m4 \
build/aclocal/gst-element-check.m4 \
build/aclocal/gtk-2.0.m4 \
build/aclocal/gtk.m4 \
diff --git a/build/bakefiles/common.bkl b/build/bakefiles/common.bkl
index e22e718bbb..62748bbb32 100644
--- a/build/bakefiles/common.bkl
+++ b/build/bakefiles/common.bkl
@@ -897,9 +897,4 @@ $(TAB)cl /EP /nologo "$(DOLLAR)(InputPath)" > "$(SETUPHDIR)\wx\msw\rcdefs.h"
top_srcdir
-
- WX_WEB_EXTENSIONS_DIRECTORY=\"$(PLUGINS_INST_DIR)/web-extensions\"
-
-
-
diff --git a/build/bakefiles/monolithic.bkl b/build/bakefiles/monolithic.bkl
index 278a308af4..90cdc085ed 100644
--- a/build/bakefiles/monolithic.bkl
+++ b/build/bakefiles/monolithic.bkl
@@ -28,7 +28,6 @@
WXMAKINGDLL
- $(webviewdll_ext_dir_define)
$(EXTRALIBS_XML)
$(EXTRALIBS_HTML)
$(EXTRALIBS_MEDIA)
@@ -40,7 +39,6 @@
- $(webviewdll_ext_dir_define)
8192
diff --git a/build/bakefiles/multilib.bkl b/build/bakefiles/multilib.bkl
index 3367df44bc..c378688dd7 100644
--- a/build/bakefiles/multilib.bkl
+++ b/build/bakefiles/multilib.bkl
@@ -184,7 +184,6 @@
cond="SHARED=='1' and USE_GUI=='1' and USE_WEBVIEW=='1' and MONOLITHIC=='0'">
WXUSINGDLL
WXMAKINGDLL_WEBVIEW
- $(webviewdll_ext_dir_define)
$(WEBVIEW_SRC)
coredll
basedll
@@ -195,7 +194,6 @@
- $(webviewdll_ext_dir_define)
$(WEBVIEW_SRC)
$(WEBVIEW_HDR)
$(webview_additional_include)
diff --git a/build/cmake/config.cmake b/build/cmake/config.cmake
index 6978cc2725..15dff884ea 100644
--- a/build/cmake/config.cmake
+++ b/build/cmake/config.cmake
@@ -33,7 +33,12 @@ macro(wx_get_dependencies var lib)
get_target_property(deps wx${lib} LINK_LIBRARIES)
foreach(dep IN LISTS deps)
if(TARGET ${dep})
- get_target_property(dep_name ${dep} OUTPUT_NAME)
+ get_target_property(dep_type ${dep} TYPE)
+ if (dep_type STREQUAL "INTERFACE_LIBRARY")
+ get_target_property(dep_name ${dep} INTERFACE_OUTPUT_NAME)
+ else()
+ get_target_property(dep_name ${dep} OUTPUT_NAME)
+ endif()
set(dep_name "-l${dep_name}")
else()
get_filename_component(dep_name ${dep} NAME)
diff --git a/build/cmake/lib/webview/CMakeLists.txt b/build/cmake/lib/webview/CMakeLists.txt
index dc9850fa27..1e2e7057a9 100644
--- a/build/cmake/lib/webview/CMakeLists.txt
+++ b/build/cmake/lib/webview/CMakeLists.txt
@@ -26,10 +26,11 @@ endif()
wx_add_library(wxwebview ${WEBVIEW_FILES})
if(WXGTK AND wxUSE_WEBVIEW_WEBKIT2)
- set(WX_WEB_EXTENSIONS_DIRECTORY "lib/wx/${wxMAJOR_VERSION}.${wxMINOR_VERSION}/web-extensions")
- wx_lib_compile_definitions(wxwebview PRIVATE
- -DWX_WEB_EXTENSIONS_DIRECTORY="${CMAKE_INSTALL_PREFIX}/${WX_WEB_EXTENSIONS_DIRECTORY}"
- )
+ if(wxVERSION_IS_DEV)
+ set(WX_WEB_EXTENSIONS_DIRECTORY "lib/wx/${wxMAJOR_VERSION}.${wxMINOR_VERSION}.${wxRELEASE_NUMBER}/web-extensions")
+ else()
+ set(WX_WEB_EXTENSIONS_DIRECTORY "lib/wx/${wxMAJOR_VERSION}.${wxMINOR_VERSION}/web-extensions")
+ endif()
endif()
if(APPLE)
diff --git a/build/cmake/tests/gui/CMakeLists.txt b/build/cmake/tests/gui/CMakeLists.txt
index c0f62ff77e..61cc082cc6 100644
--- a/build/cmake/tests/gui/CMakeLists.txt
+++ b/build/cmake/tests/gui/CMakeLists.txt
@@ -22,9 +22,11 @@ set(TEST_GUI_SRC
graphics/affinematrix.cpp
graphics/boundingbox.cpp
graphics/clippingbox.cpp
+ graphics/coords.cpp
graphics/graphmatrix.cpp
graphics/graphpath.cpp
config/config.cpp
+ controls/auitest.cpp
controls/bitmapcomboboxtest.cpp
controls/bitmaptogglebuttontest.cpp
controls/bookctrlbasetest.cpp
@@ -102,11 +104,13 @@ set(TEST_GUI_SRC
net/socket.cpp
persistence/tlw.cpp
persistence/dataview.cpp
+ rowheightcache/rowheightcachetest.cpp
sizers/boxsizer.cpp
sizers/gridsizer.cpp
sizers/wrapsizer.cpp
toplevel/toplevel.cpp
validators/valnum.cpp
+ validators/valtext.cpp
window/clientsize.cpp
window/setsize.cpp
xml/xrctest.cpp
@@ -169,6 +173,9 @@ wx_add_test(test_gui ${TEST_GUI_SRC}
RES ../samples/sample.rc
)
wx_exe_link_libraries(test_gui wxcore)
+if(wxUSE_AUI)
+ wx_exe_link_libraries(test_gui wxaui)
+endif()
if(wxUSE_RICHTEXT)
wx_exe_link_libraries(test_gui wxrichtext)
endif()
diff --git a/docs/changes.txt b/docs/changes.txt
index a5196548aa..ba14312ee6 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -105,6 +105,8 @@ Changes in behaviour not resulting in compilation errors
- wxFileDialog::GetPath() and wxFileDialog::GetFilename() now assert and return
an empty string if called on dialogs with the wxFD_MULTIPLE style.
+- wxGetInstallPrefix() now returns wxString.
+
Changes in behaviour which may result in build errors
-----------------------------------------------------
diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile
index 36bbbf3132..030a80bc3c 100644
--- a/docs/doxygen/Doxyfile
+++ b/docs/doxygen/Doxyfile
@@ -384,6 +384,7 @@ GENERATE_CHI = NO
CHM_INDEX_ENCODING =
BINARY_TOC = NO
TOC_EXPAND = NO
+TOC_INCLUDE_HEADINGS = 3
#---------------------------------------------------------------------------
diff --git a/docs/doxygen/images/overview_highdpi_text_144.png b/docs/doxygen/images/overview_highdpi_text_144.png
new file mode 100644
index 0000000000..10d430d7b9
Binary files /dev/null and b/docs/doxygen/images/overview_highdpi_text_144.png differ
diff --git a/docs/doxygen/images/overview_highdpi_text_72.png b/docs/doxygen/images/overview_highdpi_text_72.png
new file mode 100644
index 0000000000..f1173329ed
Binary files /dev/null and b/docs/doxygen/images/overview_highdpi_text_72.png differ
diff --git a/docs/doxygen/mainpages/topics.h b/docs/doxygen/mainpages/topics.h
index 7a0a6228b5..ceb5b4c6ea 100644
--- a/docs/doxygen/mainpages/topics.h
+++ b/docs/doxygen/mainpages/topics.h
@@ -99,5 +99,6 @@ topics related to building applications with wxWidgets.
@li @subpage overview_windowdeletion
@li @subpage overview_envvars
@li @subpage overview_customwidgets
+@li @subpage overview_high_dpi
*/
diff --git a/docs/doxygen/overviews/high_dpi.md b/docs/doxygen/overviews/high_dpi.md
new file mode 100644
index 0000000000..9770a232d2
--- /dev/null
+++ b/docs/doxygen/overviews/high_dpi.md
@@ -0,0 +1,149 @@
+High DPI Support in wxWidgets {#overview_high_dpi}
+=============================
+[TOC]
+
+Introduction
+============
+
+Many modern displays have way more pixels on the same surface than used to be
+the norm, resulting in much higher values of DPI (dots, i.e. pixels, per inch)
+than the traditionally used values. This allows to render texts, or geometric
+shapes in general much more smoothly.
+
+As an illustration here are two scaled up views of the same text in 11 pt
+Helvetica using up the same space on screen. First on an original Mac display
+at 72 dpi, then on a High DPI Display, called "Retina" by Apple with twice as
+many pixels in both dimensions (144 dpi), thus 4 times the number of pixels on
+the same surface. Using these the contours are much more detailed.
+
+![11 pt Helvetica at 72 DPI](overview_highdpi_text_72.png)
+
+![11 pt Helvetica at 144 DPI](overview_highdpi_text_144.png)
+
+To the user the DPI is typically expressed using a scaling factor, by which the
+baseline DPI value is multiplied. For example, MSW systems may use 125% or 150%
+scaling, meaning that they use DPI of 120 or 144 respectively, as baseline DPI
+value is 96. Similarly, Linux systems may use "2x" scaling, resulting in DPI
+value of 192. Macs are slightly different, as even they also may use "2x"
+scaling, as in the example above, the effective DPI corresponding to it is 144,
+as the baseline value on this platform is 72.
+
+
+The Problem with High DPI Displays
+----------------------------------
+
+If high DPI displays were treated in the same way as normal ones, existing
+applications would look tiny of them. For example, a square window 500 pixels
+in size would take half of a standard 1920×1080 ("Full HD") display vertically,
+but only a quarter on a 3840×2160 ("4K UHD") display. To prevent this from
+happening, most platforms automatically scale the windows by the scaling
+factor, defined above, when displaying them on high DPI displays. In this
+example, scaling factor is 2 and so the actual size of the window on screen
+would become 1000 when automatic scaling is in effect.
+
+Automatic scaling is convenient, but doesn't really allow the application to
+use the extra pixels available on the display. Visually, this means that the
+scaled application appears blurry, in contrast to sharper applications using
+the full display resolution, so a better solution for interpreting pixel values
+on high DPI displays is needed: one which allows to scale some pixel values
+(e.g. the total window size), but not some other ones (e.g. those used for
+drawing, which should remain unscaled to use the full available resolution).
+
+
+Pixel Values in wxWidgets
+=========================
+
+Logical and Device-Independent Pixels
+-------------------------------------
+
+Some systems like eg Apple's OSes automatically scale all the coordinates by
+the DPI scaling factor, however not all systems supported by wxWidgets do it --
+notably, MSW does not. This means that **logical pixels**, in which all
+coordinates and sizes are expressed in wxWidgets API, do _not_ have the same
+meaning on all platforms when using high DPI displays. So while on macOS you
+can always pass in a size of (500,500) to create the window from the previous
+paragraph, whatever the resolution of the display is, you would have to
+increase this to (1000,1000) on MSW when working on a 200% display. To hide
+this difference from the application, wxWidgets provides **device-independent
+pixels**, abbreviated as "DIP", that are always of the same size on all
+displays and all platforms.
+
+Thus, the first thing do when preparing your application for high DPI support
+is to stop using raw pixel values. Actually, using any pixel values is not
+recommended and replacing them with the values based on the text metrics, i.e.
+obtained using wxWindow::GetTextExtent(), or expressing them in dialog units
+(see wxWindow::ConvertDialogToPixels()) is preferable. However the simplest
+change is to just replace the pixel values with the values in DIP: for this,
+just use wxWindow::FromDIP() to convert from one to the other.
+
+For example, if you have the existing code:
+```cpp
+myFrame->SetClientSize(wxSize(400, 300));
+```
+you can just replace it with
+```cpp
+myFrame->SetClientSize(myFrame->FromDIP(wxSize(400, 300)));
+```
+
+Physical Pixels
+---------------
+
+In addition to (logical) pixels and DIPs discussed above, you may also need to
+work in physical pixel coordinates, corresponding to the actual display pixels.
+Physical pixels are never scaled, on any platform, and must be used when
+drawing graphics elements to ensure that the best possible resolution is used.
+For example, all operations on wxGLCanvas use physical pixels.
+
+To convert between logical and physical pixels, you can use
+wxWindow::GetContentScaleFactor(): this is a value greater than or equal to 1,
+so a value in logical pixels needs to be multiplied by it in order to obtain
+the value in physical pixels.
+
+For example, in a wxGLCanvas created with the size of 100 (logical) pixels, the
+rightmost physical pixel coordinate will be `100*GetContentScaleFactor()`.
+
+
+High-Resolution Images and Artwork
+==================================
+
+In order to benefit from the increased detail on High DPI devices you might want
+to provide the images or artwork your application uses in higher resolutions as
+well. Note that it is not recommended to just provide a high-resolution version
+and let the system scale that down on 1x displays. Apart from performance
+consideration also the quality might suffer, contours become more blurry.
+
+You can use vector based graphics like SVG or you can add the same image at different
+sizes / resolutions.
+
+[comment]: # (TODO: API and Use Cases)
+
+Platform-Specific Build Issues
+==============================
+
+Generally speaking, all systems handle applications not specifically marked as
+being "DPI-aware" by emulating low-resolution display for them and scaling them
+up, resulting in blurry graphics and fonts, but globally preserving the
+application appearance. For the best results, the application needs to be
+explicitly marked as DPI-aware in a platform-dependent way.
+
+MSW
+---
+
+The behaviour of the application when running on a high-DPI display depends on
+the values in its [manifest][1]. If your application include `wx/msw/wx.rc`
+from its resource file, you need to predefine `wxUSE_DPI_AWARE_MANIFEST` to
+opt-in into [high DPI support][2]: define it as `1` for minimal DPI awareness and
+`2` for full, per-monitor DPI awareness supported by Windows 10 version 1703 or
+later.
+
+[1]: https://docs.microsoft.com/en-us/windows/win32/sbscs/application-manifests
+[2]: https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows
+
+macOS
+-----
+
+DPI-aware applications must set their `NSPrincipalClass` to `wxNSApplication`
+(or at least `NSApplication`) in their `Info.plist` file. Also see Apple [high
+resolution guidelines][2] for more information.
+
+[2]: https://developer.apple.com/library/archive/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
diff --git a/include/wx/caret.h b/include/wx/caret.h
index e6e9728ff8..b625b5f0ac 100644
--- a/include/wx/caret.h
+++ b/include/wx/caret.h
@@ -153,6 +153,7 @@ protected:
m_window = window;
m_width = width;
m_height = height;
+ DoSize();
return true;
}
diff --git a/include/wx/convauto.h b/include/wx/convauto.h
index 3da6c6adc4..d7ed45592f 100644
--- a/include/wx/convauto.h
+++ b/include/wx/convauto.h
@@ -78,6 +78,8 @@ public:
virtual size_t GetMBNulLen() const wxOVERRIDE { return m_conv->GetMBNulLen(); }
+ virtual bool IsUTF8() const wxOVERRIDE { return m_conv && m_conv->IsUTF8(); }
+
virtual wxMBConv *Clone() const wxOVERRIDE { return new wxConvAuto(*this); }
// return the BOM type of this buffer
@@ -91,6 +93,14 @@ public:
return m_bomType;
}
+ wxFontEncoding GetEncoding() const;
+
+ // Return true if the fall-back encoding is used
+ bool IsUsingFallbackEncoding() const
+ {
+ return m_ownsConv && m_bomType == wxBOM_None;
+ }
+
private:
// common part of all ctors
void Init()
diff --git a/include/wx/dc.h b/include/wx/dc.h
index 7cf8ba7873..6dcf24c1c3 100644
--- a/include/wx/dc.h
+++ b/include/wx/dc.h
@@ -325,6 +325,8 @@ public:
// coordinates conversions and transforms
virtual wxPoint DeviceToLogical(wxCoord x, wxCoord y) const;
virtual wxPoint LogicalToDevice(wxCoord x, wxCoord y) const;
+ virtual wxSize DeviceToLogicalRel(int x, int y) const;
+ virtual wxSize LogicalToDeviceRel(int x, int y) const;
// bounding box
@@ -1012,6 +1014,14 @@ public:
{ return m_pimpl->DeviceToLogicalXRel(x); }
wxCoord DeviceToLogicalYRel(wxCoord y) const
{ return m_pimpl->DeviceToLogicalYRel(y); }
+ wxPoint DeviceToLogical(const wxPoint& pt) const
+ { return m_pimpl->DeviceToLogical(pt.x, pt.y); }
+ wxPoint DeviceToLogical(wxCoord x, wxCoord y) const
+ { return m_pimpl->DeviceToLogical(x, y); }
+ wxSize DeviceToLogicalRel(const wxSize& dim) const
+ { return m_pimpl->DeviceToLogicalRel(dim.x, dim.y); }
+ wxSize DeviceToLogicalRel(int x, int y) const
+ { return m_pimpl->DeviceToLogicalRel(x, y); }
wxCoord LogicalToDeviceX(wxCoord x) const
{ return m_pimpl->LogicalToDeviceX(x); }
wxCoord LogicalToDeviceY(wxCoord y) const
@@ -1020,6 +1030,14 @@ public:
{ return m_pimpl->LogicalToDeviceXRel(x); }
wxCoord LogicalToDeviceYRel(wxCoord y) const
{ return m_pimpl->LogicalToDeviceYRel(y); }
+ wxPoint LogicalToDevice(const wxPoint& pt) const
+ { return m_pimpl->LogicalToDevice(pt.x, pt.y); }
+ wxPoint LogicalToDevice(wxCoord x, wxCoord y) const
+ { return m_pimpl->LogicalToDevice(x, y); }
+ wxSize LogicalToDeviceRel(const wxSize& dim) const
+ { return m_pimpl->LogicalToDeviceRel(dim.x, dim.y); }
+ wxSize LogicalToDeviceRel(int x, int y) const
+ { return m_pimpl->LogicalToDeviceRel(x, y); }
void SetMapMode(wxMappingMode mode)
{ m_pimpl->SetMapMode(mode); }
diff --git a/include/wx/dcgraph.h b/include/wx/dcgraph.h
index 4622a3534a..e483d58e81 100644
--- a/include/wx/dcgraph.h
+++ b/include/wx/dcgraph.h
@@ -124,6 +124,8 @@ public:
// coordinates conversions and transforms
virtual wxPoint DeviceToLogical(wxCoord x, wxCoord y) const wxOVERRIDE;
virtual wxPoint LogicalToDevice(wxCoord x, wxCoord y) const wxOVERRIDE;
+ virtual wxSize DeviceToLogicalRel(int x, int y) const wxOVERRIDE;
+ virtual wxSize LogicalToDeviceRel(int x, int y) const wxOVERRIDE;
// the true implementations
virtual bool DoFloodFill(wxCoord x, wxCoord y, const wxColour& col,
diff --git a/include/wx/generic/bmpcbox.h b/include/wx/generic/bmpcbox.h
index 90a6ba4351..058a389ad9 100644
--- a/include/wx/generic/bmpcbox.h
+++ b/include/wx/generic/bmpcbox.h
@@ -84,6 +84,8 @@ public:
virtual ~wxBitmapComboBox();
+ virtual wxString GetStringSelection() const wxOVERRIDE;
+
// Adds item with image to the end of the combo box.
int Append(const wxString& item, const wxBitmap& bitmap = wxNullBitmap);
int Append(const wxString& item, const wxBitmap& bitmap, void *clientData);
diff --git a/include/wx/generic/private/listctrl.h b/include/wx/generic/private/listctrl.h
index c5741b6b13..4087889098 100644
--- a/include/wx/generic/private/listctrl.h
+++ b/include/wx/generic/private/listctrl.h
@@ -519,14 +519,26 @@ public:
// all these functions only do something if the line is currently visible
+ // Make sure that _line_ is the only item highlighted in the control.
+ // _oldLine_ is the old focused item.
+ void HighlightOnly( size_t line, size_t oldLine = (size_t)-1 );
+
+ // In multiple selection mode, instead of sending one notification per item
+ // (which is too slow if a lot of items are selected) we send only one notification
+ // for all of them which is the wxMSW behaviour. Currently done for virtual
+ // list controls and for deselection only.
+ enum SendEvent { SendEvent_None, SendEvent_Normal };
+
// change the line "selected" state, return true if it really changed
- bool HighlightLine( size_t line, bool highlight = true);
+ bool HighlightLine( size_t line, bool highlight = true,
+ SendEvent sendEvent = SendEvent_Normal );
// as HighlightLine() but do it for the range of lines: this is incredibly
// more efficient for virtual list controls!
//
// NB: unlike HighlightLine() this one does refresh the lines on screen
- void HighlightLines( size_t lineFrom, size_t lineTo, bool on = true );
+ void HighlightLines( size_t lineFrom, size_t lineTo, bool on = true,
+ SendEvent sendEvent = SendEvent_Normal );
// toggle the line state and refresh it
void ReverseHighlight( size_t line )
@@ -753,6 +765,16 @@ public:
return m_hasFocus;
}
+ void UpdateSelectionCount(bool selected)
+ {
+ wxASSERT_MSG( !IsVirtual(), "Can be called for non virtual lists only" );
+
+ if ( IsSingleSel() )
+ return;
+
+ selected ? ++m_selCount : --m_selCount;
+ }
+
protected:
// the array of all line objects for a non virtual list control (for the
// virtual list control we only ever use m_lines[0])
@@ -803,11 +825,18 @@ protected:
m_lineBeforeLastClicked,
m_lineSelectSingleOnUp;
+ // Multiple selection extends from the anchor. Not used in single-selection mode.
+ size_t m_anchor;
+
bool m_hasCheckBoxes;
protected:
wxWindow *GetMainWindowOfCompositeControl() wxOVERRIDE { return GetParent(); }
+ // the total count of items selected in a non virtual list control with
+ // multiple selections (always 0 otherwise)
+ size_t m_selCount;
+
// the total count of items in a virtual list control
size_t m_countVirt;
@@ -858,6 +887,24 @@ private:
// initialize the current item if needed
void UpdateCurrent();
+ // change the current (== focused) item, without sending any event
+ // return true if m_current really changed.
+ bool ChangeCurrentWithoutEvent(size_t current);
+
+ // Trying to activate the current item from keyboard is only possible
+ // if it is actually selected. We don't send wxEVT_LIST_ITEM_ACTIVATED
+ // event if it is not, and wxEVT_LIST_KEY_DOWN event should carry -1
+ // in this case, as the wxMSW implementation does.
+ bool ShouldSendEventForCurrent() const
+ {
+ return HasCurrent() && IsHighlighted(m_current);
+ }
+
+ // For multiple selection mode.
+ // Change the selected range from [anchor, oldCurrent] to [anchor, newCurrent]
+ // without generating unnecessary wxEVT_LIST_ITEM_{DE}SELECTED events.
+ void ExtendSelection(size_t oldCurrent, size_t newCurrent);
+
// delete all items but don't refresh: called from dtor
void DoDeleteAllItems();
diff --git a/include/wx/gtk/radiobut.h b/include/wx/gtk/radiobut.h
index cf6492a623..8a19a022dd 100644
--- a/include/wx/gtk/radiobut.h
+++ b/include/wx/gtk/radiobut.h
@@ -13,7 +13,7 @@
// wxRadioButton
//-----------------------------------------------------------------------------
-class WXDLLIMPEXP_CORE wxRadioButton: public wxControl
+class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase
{
public:
wxRadioButton() { }
@@ -39,8 +39,8 @@ public:
const wxString& name = wxASCII_STR(wxRadioButtonNameStr) );
virtual void SetLabel(const wxString& label) wxOVERRIDE;
- virtual void SetValue(bool val);
- virtual bool GetValue() const;
+ virtual void SetValue(bool val) wxOVERRIDE;
+ virtual bool GetValue() const wxOVERRIDE;
static wxVisualAttributes
GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL);
diff --git a/include/wx/gtk/textctrl.h b/include/wx/gtk/textctrl.h
index 13bf1a36a5..ebc2f02e0a 100644
--- a/include/wx/gtk/textctrl.h
+++ b/include/wx/gtk/textctrl.h
@@ -143,6 +143,7 @@ public:
GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL);
void GTKOnTextChanged() wxOVERRIDE;
+ void GTKAfterLayout();
protected:
// overridden wxWindow virtual methods
@@ -216,8 +217,9 @@ private:
// a dummy one when frozen
GtkTextBuffer *m_buffer;
- GtkTextMark* m_showPositionOnThaw;
+ GtkTextMark* m_showPositionDefer;
GSList* m_anonymousMarkList;
+ unsigned m_afterLayoutId;
// For wxTE_AUTO_URL
void OnUrlMouseEvent(wxMouseEvent&);
diff --git a/include/wx/gtk/webview_webkit.h b/include/wx/gtk/webview_webkit.h
index acabc88e94..fccdfcd8d8 100644
--- a/include/wx/gtk/webview_webkit.h
+++ b/include/wx/gtk/webview_webkit.h
@@ -162,6 +162,7 @@ private:
#if wxUSE_WEBVIEW_WEBKIT2
bool CanExecuteEditingCommand(const gchar* command) const;
void SetupWebExtensionServer();
+ GDBusProxy *GetExtensionProxy() const;
bool RunScriptSync(const wxString& javascript, wxString* output = NULL);
#endif
diff --git a/include/wx/gtk1/radiobut.h b/include/wx/gtk1/radiobut.h
index d958079729..d467f7100c 100644
--- a/include/wx/gtk1/radiobut.h
+++ b/include/wx/gtk1/radiobut.h
@@ -13,7 +13,7 @@
// wxRadioButton
//-----------------------------------------------------------------------------
-class WXDLLIMPEXP_CORE wxRadioButton: public wxControl
+class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase
{
public:
wxRadioButton() { }
diff --git a/include/wx/html/helpwnd.h b/include/wx/html/helpwnd.h
index 54639ad877..ffa8369c41 100644
--- a/include/wx/html/helpwnd.h
+++ b/include/wx/html/helpwnd.h
@@ -80,7 +80,7 @@ class WXDLLIMPEXP_HTML wxHtmlHelpWindow : public wxWindow
public:
wxHtmlHelpWindow(wxHtmlHelpData* data = NULL) { Init(data); }
- wxHtmlHelpWindow(wxWindow* parent, wxWindowID wxWindowID,
+ wxHtmlHelpWindow(wxWindow* parent, wxWindowID id,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
int style = wxTAB_TRAVERSAL|wxNO_BORDER,
diff --git a/include/wx/image.h b/include/wx/image.h
index d53ff0b116..f73fa70fab 100644
--- a/include/wx/image.h
+++ b/include/wx/image.h
@@ -73,6 +73,16 @@ enum wxImageResizeQuality
wxIMAGE_QUALITY_HIGH = 4
};
+// Constants for wxImage::Paste() for specifying alpha blending option.
+enum wxImageAlphaBlendMode
+{
+ // Overwrite the original alpha values with the ones being pasted.
+ wxIMAGE_ALPHA_BLEND_OVER = 0,
+
+ // Compose the original alpha values with the ones being pasted.
+ wxIMAGE_ALPHA_BLEND_COMPOSE = 1
+};
+
// alpha channel values: fully transparent, default threshold separating
// transparent pixels from opaque for a few functions dealing with alpha and
// fully opaque
@@ -348,9 +358,12 @@ public:
wxImage Size( const wxSize& size, const wxPoint& pos,
int r = -1, int g = -1, int b = -1 ) const;
- // pastes image into this instance and takes care of
- // the mask colour and out of bounds problems
- void Paste( const wxImage &image, int x, int y );
+ // Copy the data of the given image to the specified position of this one
+ // taking care of the out of bounds problems. Mask is respected, but alpha
+ // is simply replaced by default, use wxIMAGE_ALPHA_BLEND_COMPOSE to
+ // combine it with the original image alpha values if needed.
+ void Paste(const wxImage& image, int x, int y,
+ wxImageAlphaBlendMode alphaBlend = wxIMAGE_ALPHA_BLEND_OVER);
// return the new image with size width*height
wxImage Scale( int width, int height,
diff --git a/include/wx/math.h b/include/wx/math.h
index 241c3841ea..8c39bb2aa5 100644
--- a/include/wx/math.h
+++ b/include/wx/math.h
@@ -68,7 +68,7 @@
wxASSERT_MSG(x > (double)INT_MIN - 0.5 && x < (double)INT_MAX + 0.5,
wxT("argument out of supported range"));
- return std::lround(x);
+ return (int)std::lround(x);
}
#else /* C++98 */
diff --git a/include/wx/motif/radiobut.h b/include/wx/motif/radiobut.h
index 43414438a7..0233364946 100644
--- a/include/wx/motif/radiobut.h
+++ b/include/wx/motif/radiobut.h
@@ -11,7 +11,7 @@
#ifndef _WX_RADIOBUT_H_
#define _WX_RADIOBUT_H_
-class WXDLLIMPEXP_CORE wxRadioButton: public wxControl
+class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase
{
wxDECLARE_DYNAMIC_CLASS(wxRadioButton);
public:
diff --git a/include/wx/msw/dc.h b/include/wx/msw/dc.h
index faaab34283..677eeac823 100644
--- a/include/wx/msw/dc.h
+++ b/include/wx/msw/dc.h
@@ -88,6 +88,8 @@ public:
virtual wxPoint DeviceToLogical(wxCoord x, wxCoord y) const wxOVERRIDE;
virtual wxPoint LogicalToDevice(wxCoord x, wxCoord y) const wxOVERRIDE;
+ virtual wxSize DeviceToLogicalRel(int x, int y) const wxOVERRIDE;
+ virtual wxSize LogicalToDeviceRel(int x, int y) const wxOVERRIDE;
#if wxUSE_DC_TRANSFORM_MATRIX
virtual bool CanUseTransformMatrix() const wxOVERRIDE;
diff --git a/include/wx/msw/radiobut.h b/include/wx/msw/radiobut.h
index a568316edf..765f6bcc8f 100644
--- a/include/wx/msw/radiobut.h
+++ b/include/wx/msw/radiobut.h
@@ -13,7 +13,7 @@
#include "wx/msw/ownerdrawnbutton.h"
-class WXDLLIMPEXP_CORE wxRadioButton : public wxMSWOwnerDrawnButton
+class WXDLLIMPEXP_CORE wxRadioButton : public wxMSWOwnerDrawnButton
{
public:
// ctors and creation functions
@@ -43,8 +43,8 @@ public:
const wxString& name = wxASCII_STR(wxRadioButtonNameStr));
// implement the radio button interface
- virtual void SetValue(bool value);
- virtual bool GetValue() const;
+ virtual void SetValue(bool value) wxOVERRIDE;
+ virtual bool GetValue() const wxOVERRIDE;
// implementation only from now on
virtual bool MSWCommand(WXUINT param, WXWORD id) wxOVERRIDE;
diff --git a/include/wx/osx/radiobut.h b/include/wx/osx/radiobut.h
index e968d80acd..3934f839f8 100644
--- a/include/wx/osx/radiobut.h
+++ b/include/wx/osx/radiobut.h
@@ -11,7 +11,7 @@
#ifndef _WX_RADIOBUT_H_
#define _WX_RADIOBUT_H_
-class WXDLLIMPEXP_CORE wxRadioButton: public wxControl
+class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase
{
wxDECLARE_DYNAMIC_CLASS(wxRadioButton);
@@ -35,8 +35,8 @@ public:
const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxASCII_STR(wxRadioButtonNameStr));
- virtual void SetValue(bool val);
- virtual bool GetValue() const ;
+ virtual void SetValue(bool val) wxOVERRIDE;
+ virtual bool GetValue() const wxOVERRIDE;
// implementation
diff --git a/include/wx/private/unicode.h b/include/wx/private/unicode.h
new file mode 100644
index 0000000000..6c81c23504
--- /dev/null
+++ b/include/wx/private/unicode.h
@@ -0,0 +1,16 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name: wx/private/unicode.h
+// Purpose: Unicode private declsrations
+// Author: Pavel Tyunin
+// Created: 2020-10-06
+// Copyright: (c) 2020 Pavel Tyunin
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_PRIVATE_UNICODEH__
+#define _WX_PRIVATE_UNICODEH__
+
+// this table gives the length of the UTF-8 encoding from its first character:
+extern const unsigned char tableUtf8Lengths[256];
+
+#endif // _WX_PRIVATE_UNICODEH__
diff --git a/include/wx/propgrid/propgrid.h b/include/wx/propgrid/propgrid.h
index 7a34b8f4f1..6f2bff9894 100644
--- a/include/wx/propgrid/propgrid.h
+++ b/include/wx/propgrid/propgrid.h
@@ -1591,11 +1591,12 @@ protected:
// 0 = not dragging, 1 = drag just started, 2 = drag in progress
unsigned char m_dragStatus;
+#if WXWIN_COMPATIBILITY_3_0
+ // Unused variable.
// 0 = margin, 1 = label, 2 = value.
unsigned char m_mouseSide;
// True when editor control is focused.
-#if WXWIN_COMPATIBILITY_3_0
unsigned char m_editorFocused;
#else
bool m_editorFocused;
@@ -1634,8 +1635,8 @@ protected:
int m_clearThisMany;
#endif
- // Mouse is hovering over this column (index)
- unsigned int m_colHover;
+ // Mouse is hovering over this column (index), -1 for margin
+ int m_colHover;
// pointer to property that has mouse hovering
wxPGProperty* m_propHover;
diff --git a/include/wx/qt/radiobut.h b/include/wx/qt/radiobut.h
index 5a1ab5ad14..145b97a4ea 100644
--- a/include/wx/qt/radiobut.h
+++ b/include/wx/qt/radiobut.h
@@ -10,7 +10,7 @@
class QRadioButton;
-class WXDLLIMPEXP_CORE wxRadioButton : public wxControl
+class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase
{
public:
wxRadioButton();
@@ -32,8 +32,8 @@ public:
const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxASCII_STR(wxRadioButtonNameStr) );
- virtual void SetValue(bool value);
- virtual bool GetValue() const;
+ virtual void SetValue(bool value) wxOVERRIDE;
+ virtual bool GetValue() const wxOVERRIDE;
virtual QWidget *GetHandle() const wxOVERRIDE;
diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h
index 11f466cdbe..f4cf3b1a09 100644
--- a/include/wx/radiobut.h
+++ b/include/wx/radiobut.h
@@ -15,23 +15,42 @@
#if wxUSE_RADIOBTN
-/*
- There is no wxRadioButtonBase class as wxRadioButton interface is the same
- as wxCheckBox(Base), but under some platforms wxRadioButton really
- derives from wxCheckBox and on the others it doesn't.
-
- The pseudo-declaration of wxRadioButtonBase would look like this:
-
- class wxRadioButtonBase : public ...
- {
- public:
- virtual void SetValue(bool value);
- virtual bool GetValue() const;
- };
- */
-
#include "wx/control.h"
+class WXDLLIMPEXP_FWD_CORE wxRadioButton;
+
+// TODO: In wxUniv, wxRadioButton must derive from wxCheckBox as it reuses
+// much of its code. This should be fixed by refactoring wxCheckBox to allow
+// this class to reuse its functionality without inheriting from it, but for
+// now use this hack to allow the existing code to compile.
+#ifdef __WXUNIVERSAL__
+ #include "wx/checkbox.h"
+
+ typedef wxCheckBox wxRadioButtonBaseBase;
+#else
+ typedef wxControl wxRadioButtonBaseBase;
+#endif
+
+class WXDLLIMPEXP_CORE wxRadioButtonBase : public wxRadioButtonBaseBase
+{
+public:
+ wxRadioButtonBase() { }
+
+ // Methods to be implemented by the derived classes:
+ virtual void SetValue(bool value) = 0;
+ virtual bool GetValue() const = 0;
+
+
+ // Methods implemented by this class itself.
+ wxRadioButton* GetFirstInGroup() const;
+ wxRadioButton* GetLastInGroup() const;
+ wxRadioButton* GetPreviousInGroup() const;
+ wxRadioButton* GetNextInGroup() const;
+
+private:
+ wxDECLARE_NO_COPY_CLASS(wxRadioButtonBase);
+};
+
extern WXDLLIMPEXP_DATA_CORE(const char) wxRadioButtonNameStr[];
#if defined(__WXUNIVERSAL__)
diff --git a/include/wx/stringops.h b/include/wx/stringops.h
index 150554f341..dd46e6616c 100644
--- a/include/wx/stringops.h
+++ b/include/wx/stringops.h
@@ -94,15 +94,15 @@ struct WXDLLIMPEXP_BASE wxStringOperationsUtf8
return (c <= 0x7F) || (c >= 0xC2 && c <= 0xF4);
}
- // table of offsets to skip forward when iterating over UTF-8 sequence
- static const unsigned char ms_utf8IterTable[256];
+ // returns offset to skip forward when iterating over UTF-8 sequence
+ static unsigned char GetUTF8IterOffset(unsigned char c);
template
static void IncIter(Iterator& i)
{
wxASSERT( IsValidUtf8LeadByte(*i) );
- i += ms_utf8IterTable[(unsigned char)*i];
+ i += GetUTF8IterOffset(*i);
}
template
@@ -178,7 +178,7 @@ struct WXDLLIMPEXP_BASE wxStringOperationsUtf8
static size_t GetUtf8CharLength(char c)
{
wxASSERT( IsValidUtf8LeadByte(c) );
- return ms_utf8IterTable[(unsigned char)c];
+ return GetUTF8IterOffset(c);
}
// decodes single UTF-8 character from UTF-8 string
diff --git a/include/wx/tbarbase.h b/include/wx/tbarbase.h
index 6d1b423015..a4b380d6ee 100644
--- a/include/wx/tbarbase.h
+++ b/include/wx/tbarbase.h
@@ -295,10 +295,10 @@ public:
wxItemKind kind = wxITEM_NORMAL,
const wxString& shortHelp = wxEmptyString,
const wxString& longHelp = wxEmptyString,
- wxObject *data = NULL)
+ wxObject *clientData = NULL)
{
return DoAddTool(toolid, label, bitmap, bmpDisabled, kind,
- shortHelp, longHelp, data);
+ shortHelp, longHelp, clientData);
}
// the most common AddTool() version
@@ -318,10 +318,10 @@ public:
const wxBitmap& bmpDisabled = wxNullBitmap,
const wxString& shortHelp = wxEmptyString,
const wxString& longHelp = wxEmptyString,
- wxObject *data = NULL)
+ wxObject *clientData = NULL)
{
return AddTool(toolid, label, bitmap, bmpDisabled, wxITEM_CHECK,
- shortHelp, longHelp, data);
+ shortHelp, longHelp, clientData);
}
// add a radio tool, i.e. a tool which can be toggled and releases any
@@ -332,10 +332,10 @@ public:
const wxBitmap& bmpDisabled = wxNullBitmap,
const wxString& shortHelp = wxEmptyString,
const wxString& longHelp = wxEmptyString,
- wxObject *data = NULL)
+ wxObject *clientData = NULL)
{
return AddTool(toolid, label, bitmap, bmpDisabled, wxITEM_RADIO,
- shortHelp, longHelp, data);
+ shortHelp, longHelp, clientData);
}
diff --git a/include/wx/univ/radiobut.h b/include/wx/univ/radiobut.h
index ae16aa25ce..711e0a676c 100644
--- a/include/wx/univ/radiobut.h
+++ b/include/wx/univ/radiobut.h
@@ -11,13 +11,11 @@
#ifndef _WX_UNIV_RADIOBUT_H_
#define _WX_UNIV_RADIOBUT_H_
-#include "wx/checkbox.h"
-
// ----------------------------------------------------------------------------
// wxRadioButton
// ----------------------------------------------------------------------------
-class WXDLLIMPEXP_CORE wxRadioButton : public wxCheckBox
+class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase
{
public:
// constructors
@@ -46,6 +44,10 @@ public:
const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxASCII_STR(wxRadioButtonNameStr));
+ // (re)implement pure virtuals from wxRadioButtonBase
+ virtual void SetValue(bool value) wxOVERRIDE { return wxCheckBox::SetValue(value); }
+ virtual bool GetValue() const wxOVERRIDE { return wxCheckBox::GetValue(); }
+
// override some base class methods
virtual void ChangeValue(bool value) wxOVERRIDE;
diff --git a/include/wx/utils.h b/include/wx/utils.h
index c6d35299c2..3f4aea8daf 100644
--- a/include/wx/utils.h
+++ b/include/wx/utils.h
@@ -162,7 +162,7 @@ WXDLLIMPEXP_BASE wxLinuxDistributionInfo wxGetLinuxDistributionInfo();
WXDLLIMPEXP_BASE wxString wxNow();
// Return path where wxWidgets is installed (mostly useful in Unices)
-WXDLLIMPEXP_BASE const wxChar *wxGetInstallPrefix();
+WXDLLIMPEXP_BASE wxString wxGetInstallPrefix();
// Return path to wxWin data (/usr/share/wx/%{version}) (Unices)
WXDLLIMPEXP_BASE wxString wxGetDataDir();
diff --git a/include/wx/xml/xml.h b/include/wx/xml/xml.h
index a596ae92e4..a816ce22ff 100644
--- a/include/wx/xml/xml.h
+++ b/include/wx/xml/xml.h
@@ -241,10 +241,12 @@ class WXDLLIMPEXP_XML wxXmlDoctype
{
public:
explicit
- wxXmlDoctype(const wxString& name = wxString(),
- const wxString& sysid = wxString(),
- const wxString& pubid = wxString())
- : m_rootName(name), m_systemId(sysid), m_publicId(pubid)
+ wxXmlDoctype(const wxString& rootName = wxString(),
+ const wxString& systemId = wxString(),
+ const wxString& publicId = wxString())
+ : m_rootName(rootName),
+ m_systemId(systemId),
+ m_publicId(publicId)
{}
// Default copy ctor and assignment operators are ok.
diff --git a/interface/wx/clipbrd.h b/interface/wx/clipbrd.h
index c8fb6fc277..ab9ed206cb 100644
--- a/interface/wx/clipbrd.h
+++ b/interface/wx/clipbrd.h
@@ -57,7 +57,7 @@
the end-user's machine. In order for the clipboard data to persist after
the window closes, a clipboard manager must be installed. Some clipboard
managers will automatically flush the clipboard after each new piece of
- data is added, while others will not. The @Flush() function will force
+ data is added, while others will not. The Flush() function will force
the clipboard manager to flush the data.
@library{wxcore}
diff --git a/interface/wx/convauto.h b/interface/wx/convauto.h
index 7ddfb26927..324b5b24e7 100644
--- a/interface/wx/convauto.h
+++ b/interface/wx/convauto.h
@@ -146,6 +146,22 @@ public:
*/
wxBOM GetBOM() const;
+ /**
+ Return the detected encoding
+
+ Returns @c wxFONTENCODING_MAX if called before the first use.
+
+ @since 3.1.5
+ */
+ wxBOM GetEncoding() const;
+
+ /**
+ Check if the fall-back encoding is used.
+
+ @since 3.1.5
+ */
+ bool IsUsingFallbackEncoding() const;
+
/**
Return a pointer to the characters that makes up this BOM.
diff --git a/interface/wx/dataview.h b/interface/wx/dataview.h
index f975b5c286..2abf7e778b 100644
--- a/interface/wx/dataview.h
+++ b/interface/wx/dataview.h
@@ -73,9 +73,10 @@
associating the model with a control like this:
@code
- wxDataViewCtrl *musicCtrl = new wxDataViewCtrl( this, wxID_ANY );
+ wxDataViewCtrl *musicCtrl = new wxDataViewCtrl(this, wxID_ANY);
wxDataViewModel *musicModel = new MyMusicModel;
- m_musicCtrl->AssociateModel( musicModel );
+
+ musicCtrl->AssociateModel(musicModel);
musicModel->DecRef(); // avoid memory leak !!
// add columns now
@@ -84,11 +85,10 @@
A potentially better way to avoid memory leaks is to use wxObjectDataPtr
@code
- wxObjectDataPtr musicModel;
-
- wxDataViewCtrl *musicCtrl = new wxDataViewCtrl( this, wxID_ANY );
- musicModel = new MyMusicModel;
- m_musicCtrl->AssociateModel( musicModel.get() );
+ wxDataViewCtrl *musicCtrl = new wxDataViewCtrl(this, wxID_ANY);
+ wxObjectDataPtr musicModel(new MyMusicModel);
+
+ musicCtrl->AssociateModel(musicModel.get());
// add columns now
@endcode
diff --git a/interface/wx/dc.h b/interface/wx/dc.h
index bf1ca7db64..e5af4c2491 100644
--- a/interface/wx/dc.h
+++ b/interface/wx/dc.h
@@ -206,55 +206,151 @@ public:
/**
Convert @e device X coordinate to logical coordinate, using the current
mapping mode, user scale factor, device origin and axis orientation.
+
+ @note Affine transformation applied to the coordinate system
+ with SetTransformMatrix() is not taken into account.
*/
wxCoord DeviceToLogicalX(wxCoord x) const;
/**
Convert @e device X coordinate to relative logical coordinate, using the
current mapping mode and user scale factor but ignoring the
- axis orientation. Use this for converting a width, for example.
+ axis orientation. Use this for converting a horizontal distance like
+ for example a width.
+
+ @note Affine transformation applied to the coordinate system
+ with SetTransformMatrix() is not taken into account.
*/
wxCoord DeviceToLogicalXRel(wxCoord x) const;
/**
Converts @e device Y coordinate to logical coordinate, using the current
mapping mode, user scale factor, device origin and axis orientation.
+
+ @note Affine transformation applied to the coordinate system
+ with SetTransformMatrix() is not taken into account.
*/
wxCoord DeviceToLogicalY(wxCoord y) const;
/**
Convert @e device Y coordinate to relative logical coordinate, using the
current mapping mode and user scale factor but ignoring the
- axis orientation. Use this for converting a height, for example.
+ axis orientation. Use this for converting a vertical distance like
+ for example a height.
+
+ @note Affine transformation applied to the coordinate system
+ with SetTransformMatrix() is not taken into account.
*/
wxCoord DeviceToLogicalYRel(wxCoord y) const;
/**
Converts logical X coordinate to device coordinate, using the current
mapping mode, user scale factor, device origin and axis orientation.
+
+ @note Affine transformation applied to the coordinate system
+ with SetTransformMatrix() is not taken into account.
*/
wxCoord LogicalToDeviceX(wxCoord x) const;
/**
Converts logical X coordinate to relative device coordinate, using the
current mapping mode and user scale factor but ignoring the
- axis orientation. Use this for converting a width, for example.
+ axis orientation. Use this for converting a horizontal distance like
+ for example a width.
+
+ @note Affine transformation applied to the coordinate system
+ with SetTransformMatrix() is not taken into account.
*/
wxCoord LogicalToDeviceXRel(wxCoord x) const;
/**
Converts logical Y coordinate to device coordinate, using the current
mapping mode, user scale factor, device origin and axis orientation.
+
+ @note Affine transformation applied to the coordinate system
+ with SetTransformMatrix() is not taken into account.
*/
wxCoord LogicalToDeviceY(wxCoord y) const;
/**
Converts logical Y coordinate to relative device coordinate, using the
current mapping mode and user scale factor but ignoring the
- axis orientation. Use this for converting a height, for example.
+ axis orientation. Use this for converting a vertical distance like
+ for example a height.
+
+ @note Affine transformation applied to the coordinate system
+ with SetTransformMatrix() is not taken into account.
*/
wxCoord LogicalToDeviceYRel(wxCoord y) const;
+ /**
+ Converts device (@a x, @a y) coordinates to logical coordinates
+ taking into account all applied transformations like the current
+ mapping mode, scale factors, device origin, axes orientation,
+ affine transformation.
+
+ @since 3.1.5
+ */
+ wxPoint DeviceToLogical(wxCoord x, wxCoord y) const;
+
+ /**
+ @overload
+
+ @since 3.1.5
+ */
+ wxPoint DeviceToLogical(const wxPoint& pt) const;
+
+ /**
+ Converts device @a x, @a y coordinates to relative logical coordinates
+ taking into account all applied transformations like the current
+ mapping mode, scale factors, affine transformation.
+ Use this for converting distances like e.g. width and height.
+
+ @since 3.1.5
+ */
+ wxSize DeviceToLogicalRel(int x, int y) const;
+
+ /**
+ @overload
+
+ @since 3.1.5
+ */
+ wxSize DeviceToLogicalRel(const wxSize& dim) const;
+
+ /**
+ Converts logical (@a x, @a y) coordinates to device coordinates
+ taking into account all applied transformations like the current
+ mapping mode, scale factors, device origin, axes orientation,
+ affine transformation.
+
+ @since 3.1.5
+ */
+ wxPoint LogicalToDevice(wxCoord x, wxCoord y) const;
+
+ /**
+ @overload
+
+ @since 3.1.5
+ */
+ wxPoint LogicalToDevice(const wxPoint& pt) const;
+
+ /**
+ Converts logical @a x, @a y coordinates to relative device coordinates
+ taking into account all applied transformations like the current
+ mapping mode, scale factors, affine transformation.
+ Use this for converting distances like e.g. width and height.
+
+ @since 3.1.5
+ */
+ wxSize LogicalToDeviceRel(int x, int y) const;
+
+ /**
+ @overload
+
+ @since 3.1.5
+ */
+ wxSize LogicalToDeviceRel(const wxSize& dim) const;
+
//@}
diff --git a/interface/wx/html/helpwnd.h b/interface/wx/html/helpwnd.h
index e2b17d7fbe..99f67fc0e5 100644
--- a/interface/wx/html/helpwnd.h
+++ b/interface/wx/html/helpwnd.h
@@ -77,7 +77,7 @@ public:
For the values of @a helpStyle, please see the documentation for
wxHtmlHelpController.
*/
- wxHtmlHelpWindow(wxWindow* parent, int wxWindowID,
+ wxHtmlHelpWindow(wxWindow* parent, wxWindowID id,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
int style = wxTAB_TRAVERSAL|wxBORDER_NONE,
diff --git a/interface/wx/image.h b/interface/wx/image.h
index 57bee46b41..1c7288bd82 100644
--- a/interface/wx/image.h
+++ b/interface/wx/image.h
@@ -60,6 +60,21 @@ enum wxImageResizeQuality
wxIMAGE_QUALITY_HIGH
};
+
+/**
+ Constants for wxImage::Paste() for specifying alpha blending option.
+
+ @since 3.1.5
+*/
+enum wxImageAlphaBlendMode
+{
+ /// Overwrite the original alpha values with the ones being pasted.
+ wxIMAGE_ALPHA_BLEND_OVER = 0,
+
+ /// Compose the original alpha values with the ones being pasted.
+ wxIMAGE_ALPHA_BLEND_COMPOSE = 1
+};
+
/**
Possible values for PNG image type option.
@@ -803,8 +818,17 @@ public:
/**
Copy the data of the given @a image to the specified position in this image.
+
+ Takes care of the mask colour and out of bounds problems.
+
+ @param alphaBlend
+ This parameter (new in wx 3.1.5) determines whether the alpha values
+ of the original image replace (default) or are composed with the
+ alpha channel of this image. Notice that alpha blending overrides
+ the mask handling.
*/
- void Paste(const wxImage& image, int x, int y);
+ void Paste(const wxImage& image, int x, int y,
+ wxImageAlphaBlendMode alphaBlend = wxIMAGE_ALPHA_BLEND_OVER);
/**
Replaces the colour specified by @e r1,g1,b1 by the colour @e r2,g2,b2.
diff --git a/interface/wx/radiobut.h b/interface/wx/radiobut.h
index d037412e55..0a42c1c0f9 100644
--- a/interface/wx/radiobut.h
+++ b/interface/wx/radiobut.h
@@ -12,18 +12,28 @@
mutually exclusive options. It has a text label next to a (usually) round
button.
- You can create a group of mutually-exclusive radio buttons by specifying
- @c wxRB_GROUP for the first in the group. The group ends when another
- radio button group is created, or there are no more radio buttons.
+ Radio buttons are typically used in groups of mutually-exclusive buttons,
+ i.e. exactly one of the buttons in the group is checked, and the other ones
+ are unchecked automatically. Such groups are created implicitly, but can
+ also be started explicitly by using @c wxRB_GROUP style: a button with this
+ style starts a new group and will become the initial selection in this
+ group. Alternatively, a radio button may be excluded from the group that it
+ would otherwise belong to by using @c wxRB_SINGLE style.
+
+ To find the other elements of the same radio button group, you can use
+ GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup() and
+ GetLastInGroup() functions.
+
@beginStyleTable
@style{wxRB_GROUP}
Marks the beginning of a new group of radio buttons.
@style{wxRB_SINGLE}
- In some circumstances, radio buttons that are not consecutive
- siblings trigger a hang bug in Windows (only). If this happens, add
- this style to mark the button as not belonging to a group, and
- implement the mutually-exclusive group behaviour yourself.
+ Creates a radio button which is not part of any radio button group.
+ When this style is used, no other radio buttons will be turned off
+ automatically when this button is turned on and such behaviour will
+ need to be implemented manually, in the event handler for this
+ button.
@endStyleTable
@beginEventEmissionTable{wxCommandEvent}
@@ -119,5 +129,64 @@ public:
@true to check, @false to uncheck.
*/
virtual void SetValue(bool value);
+
+ /**
+ Returns the first button of the radio button group this button belongs
+ to.
+
+ For a radio button with @c wxRB_SINGLE style, this function returns this
+ button itself, as it is the only member of its group. Otherwise, the
+ function returns the closest previous radio button with @c wxRB_GROUP
+ style (which could still be this button itself) or the first radio
+ button in the same window.
+
+ The returned value is never @NULL.
+
+ @see GetPreviousInGroup(), GetNextInGroup(), GetLastInGroup()
+
+ @since 3.1.5
+ */
+ wxRadioButton* GetFirstInGroup() const;
+
+ /**
+ Returns the last button of the radio button group this button belongs
+ to.
+
+ Similarly to GetFirstInGroup(), this function returns this button
+ itself if it has @c wxRB_SINGLE style. Otherwise, the function returns
+ the last button before the next button with @c wxRB_GROUP style or the
+ last radio button in the same window.
+
+ The returned value is never @NULL.
+
+ @see GetPreviousInGroup(), GetNextInGroup()
+
+ @since 3.1.5
+ */
+ wxRadioButton* GetLastInGroup() const;
+
+ /**
+ Returns the previous radio button in the same group.
+
+ The return value is @NULL if there is no predecessor or if this button
+ has @c wxRB_SINGLE style.
+
+ @see GetFirstInGroup(), GetNextInGroup(), GetLastInGroup()
+
+ @since 3.1.5
+ */
+ wxRadioButton* GetPreviousInGroup() const;
+
+ /**
+ Returns the next radio button in the same group.
+
+ The return value is @NULL if there is no successor or if this button
+ has @c wxRB_SINGLE style.
+
+ @see GetFirstInGroup(), GetPreviousInGroup(), GetLastInGroup()
+
+ @since 3.1.5
+ */
+ wxRadioButton* GetNextInGroup() const;
};
diff --git a/interface/wx/ribbon/art.h b/interface/wx/ribbon/art.h
index 167f440c3a..d551f3466f 100644
--- a/interface/wx/ribbon/art.h
+++ b/interface/wx/ribbon/art.h
@@ -1251,6 +1251,12 @@ public:
wxRect* normal_region,
wxRect* dropdown_region);
+ wxCoord GetButtonBarButtonTextWidth(
+ wxDC& dc,
+ const wxString& label,
+ wxRibbonButtonKind kind,
+ wxRibbonButtonBarButtonState size);
+
wxSize GetMinimisedPanelMinimumSize(
wxDC& dc,
const wxRibbonPanel* wnd,
diff --git a/interface/wx/ribbon/toolbar.h b/interface/wx/ribbon/toolbar.h
index cb6045d665..77fff36f0e 100644
--- a/interface/wx/ribbon/toolbar.h
+++ b/interface/wx/ribbon/toolbar.h
@@ -130,7 +130,7 @@ public:
The UI help string to associate with the new tool.
@param kind
The kind of tool to add.
- @param client_data
+ @param clientData
Client data to associate with the new tool.
@return An opaque pointer which can be used only with other tool bar
@@ -144,7 +144,7 @@ public:
const wxBitmap& bitmap_disabled = wxNullBitmap,
const wxString& help_string = wxEmptyString,
wxRibbonButtonKind kind = wxRIBBON_BUTTON_NORMAL,
- wxObject* client_data = NULL);
+ wxObject* clientData = NULL);
/**
Add a separator to the tool bar.
@@ -232,7 +232,7 @@ public:
The UI help string to associate with the new tool.
@param kind
The kind of tool to add.
- @param client_data
+ @param clientData
Client data to associate with the new tool.
@return An opaque pointer which can be used only with other tool bar
@@ -249,7 +249,7 @@ public:
const wxBitmap& bitmap_disabled = wxNullBitmap,
const wxString& help_string = wxEmptyString,
wxRibbonButtonKind kind = wxRIBBON_BUTTON_NORMAL,
- wxObject* client_data = NULL);
+ wxObject* clientData = NULL);
/**
Insert a separator to the tool bar at the specified position.
diff --git a/interface/wx/toolbar.h b/interface/wx/toolbar.h
index 84506d9589..3cdb064c73 100644
--- a/interface/wx/toolbar.h
+++ b/interface/wx/toolbar.h
@@ -462,9 +462,9 @@ public:
whenever another button in the group is checked. ::wxITEM_DROPDOWN
specifies that a drop-down menu button will appear next to the
tool button (only GTK+ and MSW). Call SetDropdownMenu() afterwards.
- @param shortHelpString
+ @param shortHelp
This string is used for the tools tooltip.
- @param longHelpString
+ @param longHelp
This string is shown in the statusbar (if any) of the parent frame
when the mouse pointer is inside the tool.
@param clientData
@@ -481,8 +481,8 @@ public:
const wxBitmap& bitmap,
const wxBitmap& bmpDisabled,
wxItemKind kind = wxITEM_NORMAL,
- const wxString& shortHelpString = wxEmptyString,
- const wxString& longHelpString = wxEmptyString,
+ const wxString& shortHelp = wxEmptyString,
+ const wxString& longHelp = wxEmptyString,
wxObject* clientData = NULL);
//@}
diff --git a/interface/wx/xml/xml.h b/interface/wx/xml/xml.h
index 0eaad72423..4c58080b75 100644
--- a/interface/wx/xml/xml.h
+++ b/interface/wx/xml/xml.h
@@ -494,16 +494,16 @@ public:
/**
Creates and possible initializes the DOCTYPE.
- @param name
+ @param rootName
The root name.
- @param sysid
+ @param systemId
The system identifier.
- @param pubid
+ @param publicId
The public identifier.
*/
- wxXmlDoctype(const wxString& name = wxString(),
- const wxString& sysid = wxString(),
- const wxString& pubid = wxString());
+ wxXmlDoctype(const wxString& rootName = wxString(),
+ const wxString& systemId = wxString(),
+ const wxString& publicId = wxString());
/**
Removes all the DOCTYPE values.
diff --git a/samples/drawing/drawing.cpp b/samples/drawing/drawing.cpp
index acd2eeaa47..89e785a6ba 100644
--- a/samples/drawing/drawing.cpp
+++ b/samples/drawing/drawing.cpp
@@ -1338,8 +1338,8 @@ void MyCanvas::DrawSplines(wxDC& dc)
{
angle += angles[ angle_pos ];
int r = R * radii[ radius_pos ] / 100;
- pts[ i ].x = center.x + (wxCoord)( r * cos( M_PI * angle / 180.0) );
- pts[ i ].y = center.y + (wxCoord)( r * sin( M_PI * angle / 180.0) );
+ pts[ i ].x = center.x + (wxCoord)( r * cos(wxDegToRad(angle)) );
+ pts[ i ].y = center.y + (wxCoord)( r * sin(wxDegToRad(angle)) );
angle_pos++;
if ( angle_pos >= WXSIZEOF(angles) ) angle_pos = 0;
@@ -2013,11 +2013,9 @@ void MyCanvas::OnMouseMove(wxMouseEvent &event)
PrepareDC(dc);
m_owner->PrepareDC(dc);
- wxPoint pos = event.GetPosition();
- long x = dc.DeviceToLogicalX( pos.x );
- long y = dc.DeviceToLogicalY( pos.y );
+ wxPoint pos = dc.DeviceToLogical(event.GetPosition());
wxString str;
- str.Printf( "Current mouse position: %d,%d", (int)x, (int)y );
+ str.Printf( "Current mouse position: %d,%d", pos.x, pos.y );
m_owner->SetStatusText( str );
}
diff --git a/samples/listctrl/listtest.cpp b/samples/listctrl/listtest.cpp
index 1c4213098b..4ef123fa73 100644
--- a/samples/listctrl/listtest.cpp
+++ b/samples/listctrl/listtest.cpp
@@ -564,6 +564,15 @@ void MyFrame::InitWithReportItems()
itemCol.SetAlign(wxLIST_FORMAT_RIGHT);
m_listCtrl->InsertColumn(2, itemCol);
+ if ( m_numListItems <= 0 )
+ {
+ m_listCtrl->SetColumnWidth( 0, 100 );
+ m_listCtrl->SetColumnWidth( 1, wxLIST_AUTOSIZE );
+ m_listCtrl->SetColumnWidth( 2, wxLIST_AUTOSIZE_USEHEADER );
+
+ return;
+ }
+
// to speed up inserting we hide the control temporarily
m_listCtrl->Hide();
@@ -584,25 +593,38 @@ void MyFrame::InitWithReportItems()
item.SetTextColour(*wxRED);
m_listCtrl->SetItem( item );
- item.m_itemId = 2;
- item.SetTextColour(*wxGREEN);
- m_listCtrl->SetItem( item );
- item.m_itemId = 4;
- item.SetTextColour(*wxLIGHT_GREY);
- item.SetFont(*wxITALIC_FONT);
- item.SetBackgroundColour(*wxRED);
- m_listCtrl->SetItem( item );
+ if ( m_numListItems > 2 )
+ {
+ item.m_itemId = 2;
+ item.SetTextColour(*wxGREEN);
+ m_listCtrl->SetItem( item );
+ }
+
+ if ( m_numListItems > 4 )
+ {
+ item.m_itemId = 4;
+ item.SetTextColour(*wxLIGHT_GREY);
+ item.SetFont(*wxITALIC_FONT);
+ item.SetBackgroundColour(*wxRED);
+ m_listCtrl->SetItem( item );
+ }
m_listCtrl->SetTextColour(*wxBLUE);
- // Set images in columns
- m_listCtrl->SetItemColumnImage(1, 1, 0);
+ if ( m_numListItems > 1 )
+ {
+ // Set images in columns
+ m_listCtrl->SetItemColumnImage(1, 1, 0);
+ }
- wxListItem info;
- info.SetImage(0);
- info.SetId(3);
- info.SetColumn(2);
- m_listCtrl->SetItem(info);
+ if ( m_numListItems > 3 )
+ {
+ wxListItem info;
+ info.SetImage(0);
+ info.SetId(3);
+ info.SetColumn(2);
+ m_listCtrl->SetItem(info);
+ }
// test SetItemFont too
m_listCtrl->SetItemFont(0, *wxITALIC_FONT);
@@ -1073,6 +1095,11 @@ void MyListCtrl::OnColClick(wxListEvent& event)
{
int col = event.GetColumn();
+ if ( col == -1 )
+ {
+ return; // clicked outside any column.
+ }
+
// set or unset image
static bool x = false;
x = !x;
@@ -1409,8 +1436,6 @@ void MyListCtrl::OnListKeyDown(wxListEvent& event)
wxFALLTHROUGH;
default:
- LogEvent(event, "OnListKeyDown");
-
event.Skip();
}
}
@@ -1442,7 +1467,6 @@ void MyListCtrl::OnRightClick(wxMouseEvent& event)
case wxLIST_HITTEST_NOWHERE: where = "nowhere near"; break;
case wxLIST_HITTEST_ONITEMICON: where = "on icon of"; break;
case wxLIST_HITTEST_ONITEMLABEL: where = "on label of"; break;
- case wxLIST_HITTEST_ONITEMRIGHT: where = "right on"; break;
case wxLIST_HITTEST_TOLEFT: where = "to the left of"; break;
case wxLIST_HITTEST_TORIGHT: where = "to the right of"; break;
default: where = "not clear exactly where on"; break;
diff --git a/samples/widgets/slider.cpp b/samples/widgets/slider.cpp
index 32bf2fad60..383be8b14a 100644
--- a/samples/widgets/slider.cpp
+++ b/samples/widgets/slider.cpp
@@ -119,7 +119,8 @@ protected:
void OnCheckOrRadioBox(wxCommandEvent& event);
- void OnSlider(wxScrollEvent& event);
+ void OnSliderScroll(wxScrollEvent& event);
+ void OnSlider(wxCommandEvent& event);
void OnUpdateUIValueButton(wxUpdateUIEvent& event);
void OnUpdateUIMinMaxButton(wxUpdateUIEvent& event);
@@ -161,6 +162,8 @@ protected:
bool IsValidValue(int val) const
{ return (val >= m_min) && (val <= m_max); }
+ static int ms_numSliderEvents;
+
// the slider range
int m_min, m_max;
@@ -200,6 +203,8 @@ private:
DECLARE_WIDGETS_PAGE(SliderWidgetsPage)
};
+int SliderWidgetsPage::ms_numSliderEvents = 0;
+
// ----------------------------------------------------------------------------
// event tables
// ----------------------------------------------------------------------------
@@ -229,7 +234,8 @@ wxBEGIN_EVENT_TABLE(SliderWidgetsPage, WidgetsPage)
EVT_UPDATE_UI(SliderPage_CurValueText, SliderWidgetsPage::OnUpdateUICurValueText)
- EVT_COMMAND_SCROLL(SliderPage_Slider, SliderWidgetsPage::OnSlider)
+ EVT_COMMAND_SCROLL(SliderPage_Slider, SliderWidgetsPage::OnSliderScroll)
+ EVT_SLIDER(SliderPage_Slider, SliderWidgetsPage::OnSlider)
EVT_CHECKBOX(wxID_ANY, SliderWidgetsPage::OnCheckOrRadioBox)
EVT_RADIOBOX(wxID_ANY, SliderWidgetsPage::OnCheckOrRadioBox)
@@ -801,7 +807,7 @@ void SliderWidgetsPage::OnUpdateUISelectRange(wxUpdateUIEvent& event)
#endif // defined(__WXMSW__)
}
-void SliderWidgetsPage::OnSlider(wxScrollEvent& event)
+void SliderWidgetsPage::OnSliderScroll(wxScrollEvent& event)
{
wxASSERT_MSG( event.GetInt() == m_slider->GetValue(),
"slider value should be the same" );
@@ -835,14 +841,17 @@ void SliderWidgetsPage::OnSlider(wxScrollEvent& event)
wxASSERT_MSG(index >= 0 && (size_t)index < WXSIZEOF(eventNames),
"Unknown slider event" );
-
- static int s_numSliderEvents = 0;
-
wxLogMessage("Slider event #%d: %s (pos = %d, int value = %d)",
- s_numSliderEvents++,
+ ms_numSliderEvents++,
eventNames[index],
event.GetPosition(),
event.GetInt());
}
+void SliderWidgetsPage::OnSlider(wxCommandEvent& event)
+{
+ wxLogMessage("Slider event #%d: wxEVT_SLIDER (value = %d)",
+ ms_numSliderEvents++, event.GetInt());
+}
+
#endif // wxUSE_SLIDER
diff --git a/src/aui/auibar.cpp b/src/aui/auibar.cpp
index b07b2ca296..72ee06218d 100644
--- a/src/aui/auibar.cpp
+++ b/src/aui/auibar.cpp
@@ -2839,7 +2839,7 @@ void wxAuiToolBar::OnMotion(wxMouseEvent& evt)
const bool button_pressed = HasCapture();
// start a drag event
- if (!m_dragging && button_pressed &&
+ if (!m_dragging && button_pressed && m_actionItem &&
abs(evt.GetX() - m_actionPos.x) + abs(evt.GetY() - m_actionPos.y) > 5)
{
// TODO: sending this event only makes sense if there is an 'END_DRAG'
diff --git a/src/common/containr.cpp b/src/common/containr.cpp
index b418a3b8c2..cf5f630665 100644
--- a/src/common/containr.cpp
+++ b/src/common/containr.cpp
@@ -234,101 +234,19 @@ void wxControlContainer::SetLastFocus(wxWindow *win)
}
// --------------------------------------------------------------------
-// The following four functions are used to find other radio buttons
-// within the same group. Used by wxSetFocusToChild
+// The following functions is used by wxSetFocusToChild()
// --------------------------------------------------------------------
-#if wxUSE_RADIOBTN
+#if defined(USE_RADIOBTN_NAV)
-wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn)
+namespace
{
- if ( btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) )
- return NULL;
- const wxWindowList& siblings = btn->GetParent()->GetChildren();
- wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn);
- wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") );
-
- // Iterate over all previous siblings until we find the next radio button
- wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious();
- wxRadioButton *prevBtn = 0;
- while (nodeBefore)
- {
- prevBtn = wxDynamicCast(nodeBefore->GetData(), wxRadioButton);
- if (prevBtn)
- break;
-
- nodeBefore = nodeBefore->GetPrevious();
- }
-
- if (!prevBtn || prevBtn->HasFlag(wxRB_SINGLE))
- {
- // no more buttons in group
- return NULL;
- }
-
- return prevBtn;
-}
-
-wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn)
-{
- if (btn->HasFlag(wxRB_SINGLE))
- return NULL;
-
- const wxWindowList& siblings = btn->GetParent()->GetChildren();
- wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn);
- wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") );
-
- // Iterate over all previous siblings until we find the next radio button
- wxWindowList::compatibility_iterator nodeNext = nodeThis->GetNext();
- wxRadioButton *nextBtn = 0;
- while (nodeNext)
- {
- nextBtn = wxDynamicCast(nodeNext->GetData(), wxRadioButton);
- if (nextBtn)
- break;
-
- nodeNext = nodeNext->GetNext();
- }
-
- if ( !nextBtn || nextBtn->HasFlag(wxRB_GROUP) || nextBtn->HasFlag(wxRB_SINGLE) )
- {
- // no more buttons or the first button of the next group
- return NULL;
- }
-
- return nextBtn;
-}
-
-wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn)
-{
- while (true)
- {
- wxRadioButton* prevBtn = wxGetPreviousButtonInGroup(btn);
- if (!prevBtn)
- return btn;
-
- btn = prevBtn;
- }
-}
-
-wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn)
-{
- while (true)
- {
- wxRadioButton* nextBtn = wxGetNextButtonInGroup(btn);
- if (!nextBtn)
- return btn;
-
- btn = nextBtn;
- }
-}
-
-wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn)
+wxRadioButton* wxGetSelectedButtonInGroup(const wxRadioButton *btn)
{
// Find currently selected button
if (btn->GetValue())
- return btn;
+ return const_cast(btn);
if (btn->HasFlag(wxRB_SINGLE))
return NULL;
@@ -336,19 +254,21 @@ wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn)
wxRadioButton *selBtn;
// First check all previous buttons
- for (selBtn = wxGetPreviousButtonInGroup(btn); selBtn; selBtn = wxGetPreviousButtonInGroup(selBtn))
+ for (selBtn = btn->GetPreviousInGroup(); selBtn; selBtn = selBtn->GetPreviousInGroup())
if (selBtn->GetValue())
return selBtn;
// Now all following buttons
- for (selBtn = wxGetNextButtonInGroup(btn); selBtn; selBtn = wxGetNextButtonInGroup(selBtn))
+ for (selBtn = btn->GetNextInGroup(); selBtn; selBtn = selBtn->GetNextInGroup())
if (selBtn->GetValue())
return selBtn;
return NULL;
}
-#endif // wxUSE_RADIOBTN
+} // anonymous namespace
+
+#endif // USE_RADIOBTN_NAV
// ----------------------------------------------------------------------------
// Keyboard handling - this is the place where the TAB traversal logic is
@@ -468,7 +388,7 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event )
// If we are in a radio button group, start from the first item in the
// group
if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) )
- winFocus = wxGetFirstButtonInGroup((wxRadioButton*)winFocus);
+ winFocus = static_cast(winFocus)->GetFirstInGroup();
#endif // USE_RADIOBTN_NAV
// ok, we found the focus - now is it our child?
start_node = children.Find( winFocus );
@@ -586,20 +506,20 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event )
// find the correct radio button to focus
if ( forward )
{
- child = wxGetNextButtonInGroup(lastBtn);
+ child = lastBtn->GetNextInGroup();
if ( !child )
{
// no next button in group, set it to the first button
- child = wxGetFirstButtonInGroup(lastBtn);
+ child = lastBtn->GetFirstInGroup();
}
}
else
{
- child = wxGetPreviousButtonInGroup(lastBtn);
+ child = lastBtn->GetPreviousInGroup();
if ( !child )
{
// no previous button in group, set it to the last button
- child = wxGetLastButtonInGroup(lastBtn);
+ child = lastBtn->GetLastInGroup();
}
}
diff --git a/src/common/convauto.cpp b/src/common/convauto.cpp
index 952b4455f5..708096de5d 100644
--- a/src/common/convauto.cpp
+++ b/src/common/convauto.cpp
@@ -23,6 +23,7 @@
#endif
#include "wx/convauto.h"
+#include "wx/private/unicode.h"
// we use latin1 by default as it seems the least bad choice: the files we need
// to detect input of don't always come from the user system (they are often
@@ -266,6 +267,23 @@ bool wxConvAuto::InitFromInput(const char *src, size_t len)
return true;
}
+// checks if the input can be the beginning of a valid UTF-8 sequence
+static bool wxCanBeUTF8SequencePrefix(const char *src, size_t len)
+{
+ size_t i = 0;
+ unsigned char l = tableUtf8Lengths[(unsigned char)src[i]];
+ if ( !l )
+ return false; // invalid leading byte
+ while ( --l )
+ {
+ if ( ++i == len )
+ return true; // truncated sequence
+ if ( (src[i] & 0xC0) != 0x80 )
+ return false; // invalid continuation byte
+ }
+ return false; // complete sequence
+}
+
size_t
wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen,
const char *src, size_t srcLen) const
@@ -307,25 +325,28 @@ wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen,
// try to convert using the auto-detected encoding
size_t rc = m_conv->ToWChar(dst, dstLen, src, srcLen);
- if ( rc == wxCONV_FAILED && m_bomType == wxBOM_None )
+ if ( rc == wxCONV_FAILED && m_bomType == wxBOM_None && !m_ownsConv )
{
// we may need more bytes before we can decode the input, don't switch
// to the fall-back conversion in this case as it would prevent us from
// decoding UTF-8 input when fed it byte by byte, as done by
// wxTextInputStream, for example
- if ( srcLen < m_conv->GetMaxCharLen() )
+ // up to 2 extra bytes are needed for inputs that start with null bytes
+ // that look like the start of UTF-32BE BOM, but can be in UTF-8 too
+ size_t nNull = 0;
+ if ( srcLen != wxNO_LEN && srcLen >= 2 && !src[0] )
+ nNull = ( src[1]? 1 : 2 );
+ if ( srcLen < nNull + m_conv->GetMaxCharLen() &&
+ wxCanBeUTF8SequencePrefix(src + nNull, srcLen - nNull) )
return wxCONV_FAILED;
// if the conversion failed but we didn't really detect anything and
// simply tried UTF-8 by default, retry it using the fall-back
+ if ( m_encDefault == wxFONTENCODING_DEFAULT )
+ self->m_encDefault = GetFallbackEncoding();
if ( m_encDefault != wxFONTENCODING_MAX )
{
- if ( m_ownsConv )
- delete m_conv;
-
- self->m_conv = new wxCSConv(m_encDefault == wxFONTENCODING_DEFAULT
- ? GetFallbackEncoding()
- : m_encDefault);
+ self->m_conv = new wxCSConv(m_encDefault);
self->m_ownsConv = true;
rc = m_conv->ToWChar(dst, dstLen, src, srcLen);
@@ -351,3 +372,32 @@ wxConvAuto::FromWChar(char *dst, size_t dstLen,
return m_conv->FromWChar(dst, dstLen, src, srcLen);
}
+
+wxFontEncoding wxConvAuto::GetEncoding() const
+{
+ switch ( m_bomType )
+ {
+ case wxBOM_UTF32BE:
+ return wxFONTENCODING_UTF32BE;
+ case wxBOM_UTF32LE:
+ return wxFONTENCODING_UTF32LE;
+ case wxBOM_UTF16BE:
+ return wxFONTENCODING_UTF16BE;
+ case wxBOM_UTF16LE:
+ return wxFONTENCODING_UTF16LE;
+ case wxBOM_UTF8:
+ return wxFONTENCODING_UTF8;
+
+ case wxBOM_Unknown:
+ case wxBOM_None:
+ if ( !m_conv )
+ return wxFONTENCODING_MAX;
+ else if ( !m_ownsConv )
+ return wxFONTENCODING_UTF8;
+ else
+ return m_encDefault;
+ }
+
+ wxFAIL_MSG( "unknown BOM type" );
+ return wxFONTENCODING_MAX;
+}
diff --git a/src/common/dcbase.cpp b/src/common/dcbase.cpp
index 59f61bce0a..6f351dfdc1 100644
--- a/src/common/dcbase.cpp
+++ b/src/common/dcbase.cpp
@@ -512,6 +512,16 @@ wxPoint wxDCImpl::LogicalToDevice(wxCoord x, wxCoord y) const
return wxPoint(LogicalToDeviceX(x), LogicalToDeviceY(y));
}
+wxSize wxDCImpl::DeviceToLogicalRel(int x, int y) const
+{
+ return wxSize(DeviceToLogicalXRel(x), DeviceToLogicalYRel(y));
+}
+
+wxSize wxDCImpl::LogicalToDeviceRel(int x, int y) const
+{
+ return wxSize(LogicalToDeviceXRel(x), LogicalToDeviceYRel(y));
+}
+
void wxDCImpl::ComputeScaleAndOrigin()
{
m_scaleX = m_logicalScaleX * m_userScaleX;
diff --git a/src/common/dcgraph.cpp b/src/common/dcgraph.cpp
index cd6c8d206e..2e3afe25fe 100644
--- a/src/common/dcgraph.cpp
+++ b/src/common/dcgraph.cpp
@@ -27,12 +27,6 @@
#include "wx/geometry.h"
#endif
-//-----------------------------------------------------------------------------
-// constants
-//-----------------------------------------------------------------------------
-
-static const double RAD2DEG = 180.0 / M_PI;
-
//-----------------------------------------------------------------------------
// Local functions
//-----------------------------------------------------------------------------
@@ -613,6 +607,22 @@ wxPoint wxGCDCImpl::LogicalToDevice(wxCoord x, wxCoord y) const
return wxPoint(wxRound(px), wxRound(py));
}
+wxSize wxGCDCImpl::DeviceToLogicalRel(int x, int y) const
+{
+ wxDouble dx = x;
+ wxDouble dy = y;
+ m_matrixCurrentInv.TransformDistance(&dx, &dy);
+ return wxSize(wxRound(dx), wxRound(dy));
+}
+
+wxSize wxGCDCImpl::LogicalToDeviceRel(int x, int y) const
+{
+ wxDouble dx = x;
+ wxDouble dy = y;
+ m_matrixCurrent.TransformDistance(&dx, &dy);
+ return wxSize(wxRound(dx), wxRound(dy));
+}
+
bool wxGCDCImpl::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
const wxColour& WXUNUSED(col),
wxFloodFillStyle WXUNUSED(style))
@@ -670,11 +680,11 @@ void wxGCDCImpl::DoDrawArc( wxCoord x1, wxCoord y1,
double dy = y1 - yc;
double radius = sqrt((double)(dx * dx + dy * dy));
wxCoord rad = (wxCoord)radius;
- double sa, ea;
+ double sa, ea; // In radians
if (x1 == x2 && y1 == y2)
{
sa = 0.0;
- ea = 360.0;
+ ea = 2.0 * M_PI;
}
else if (radius == 0.0)
{
@@ -683,11 +693,11 @@ void wxGCDCImpl::DoDrawArc( wxCoord x1, wxCoord y1,
else
{
sa = (x1 - xc == 0) ?
- (y1 - yc < 0) ? 90.0 : -90.0 :
- -atan2(double(y1 - yc), double(x1 - xc)) * RAD2DEG;
+ (y1 - yc < 0) ? M_PI / 2.0 : -M_PI / 2.0 :
+ -atan2(double(y1 - yc), double(x1 - xc));
ea = (x2 - xc == 0) ?
- (y2 - yc < 0) ? 90.0 : -90.0 :
- -atan2(double(y2 - yc), double(x2 - xc)) * RAD2DEG;
+ (y2 - yc < 0) ? M_PI / 2.0 : -M_PI / 2.0 :
+ -atan2(double(y2 - yc), double(x2 - xc));
}
bool fill = m_brush.GetStyle() != wxBRUSHSTYLE_TRANSPARENT;
@@ -697,7 +707,7 @@ void wxGCDCImpl::DoDrawArc( wxCoord x1, wxCoord y1,
path.MoveToPoint( xc, yc );
// since these angles (ea,sa) are measured counter-clockwise, we invert them to
// get clockwise angles
- path.AddArc( xc, yc , rad, wxDegToRad(-sa), wxDegToRad(-ea), false );
+ path.AddArc( xc, yc , rad, -sa, -ea, false );
if ( fill && ((x1!=x2)||(y1!=y2)) )
path.AddLineToPoint( xc, yc );
m_graphicContext->DrawPath(path);
diff --git a/src/common/dynlib.cpp b/src/common/dynlib.cpp
index 37fea09768..8130f93f9d 100644
--- a/src/common/dynlib.cpp
+++ b/src/common/dynlib.cpp
@@ -227,6 +227,8 @@ wxString wxDynamicLibrary::GetPluginsDirectory()
{
#ifdef __UNIX__
wxString format = wxGetInstallPrefix();
+ if ( format.empty() )
+ return wxEmptyString;
wxString dir;
format << wxFILE_SEP_PATH
<< wxT("lib") << wxFILE_SEP_PATH
diff --git a/src/common/geometry.cpp b/src/common/geometry.cpp
index 57bdcb40c7..cd2fc3c59f 100644
--- a/src/common/geometry.cpp
+++ b/src/common/geometry.cpp
@@ -176,8 +176,7 @@ wxDouble wxPoint2DInt::GetVectorAngle() const
return 180;
}
- // casts needed for MIPSpro compiler under SGI
- wxDouble deg = atan2( (double)m_y , (double)m_x ) * 180 / M_PI;
+ wxDouble deg = wxRadToDeg(atan2( (double)m_y , (double)m_x ));
if ( deg < 0 )
{
deg += 360;
@@ -189,8 +188,9 @@ wxDouble wxPoint2DInt::GetVectorAngle() const
void wxPoint2DInt::SetVectorAngle( wxDouble degrees )
{
wxDouble length = GetVectorLength();
- m_x = (int)(length * cos( degrees / 180 * M_PI ));
- m_y = (int)(length * sin( degrees / 180 * M_PI ));
+ double rad = wxDegToRad(degrees);
+ m_x = (int)(length * cos(rad));
+ m_y = (int)(length * sin(rad));
}
wxDouble wxPoint2DDouble::GetVectorAngle() const
@@ -209,7 +209,7 @@ wxDouble wxPoint2DDouble::GetVectorAngle() const
else
return 180;
}
- wxDouble deg = atan2( m_y , m_x ) * 180 / M_PI;
+ wxDouble deg = wxRadToDeg(atan2( m_y , m_x ));
if ( deg < 0 )
{
deg += 360;
@@ -220,8 +220,9 @@ wxDouble wxPoint2DDouble::GetVectorAngle() const
void wxPoint2DDouble::SetVectorAngle( wxDouble degrees )
{
wxDouble length = GetVectorLength();
- m_x = length * cos( degrees / 180 * M_PI );
- m_y = length * sin( degrees / 180 * M_PI );
+ double rad = wxDegToRad(degrees);
+ m_x = length * cos(rad);
+ m_y = length * sin(rad);
}
// wxRect2D
diff --git a/src/common/image.cpp b/src/common/image.cpp
index 880c1c4ea7..d6febece49 100644
--- a/src/common/image.cpp
+++ b/src/common/image.cpp
@@ -1608,7 +1608,9 @@ wxImage wxImage::Size( const wxSize& size, const wxPoint& pos,
return image;
}
-void wxImage::Paste( const wxImage &image, int x, int y )
+void
+wxImage::Paste(const wxImage & image, int x, int y,
+ wxImageAlphaBlendMode alphaBlend)
{
wxCHECK_RET( IsOk(), wxT("invalid image") );
wxCHECK_RET( image.IsOk(), wxT("invalid image") );
@@ -1639,15 +1641,18 @@ void wxImage::Paste( const wxImage &image, int x, int y )
if (width < 1) return;
if (height < 1) return;
+ bool copiedPixels = false;
+
// If we can, copy the data using memcpy() as this is the fastest way. But
- // for this the image being pasted must have "compatible" mask with this
- // one meaning that either it must not have one at all or it must use the
- // same masked colour.
- if ( !image.HasMask() ||
+ // for this we must not do alpha compositing and the image being pasted
+ // must have "compatible" mask with this one meaning that either it must
+ // not have one at all or it must use the same masked colour.
+ if (alphaBlend == wxIMAGE_ALPHA_BLEND_OVER &&
+ (!image.HasMask() ||
((HasMask() &&
(GetMaskRed()==image.GetMaskRed()) &&
(GetMaskGreen()==image.GetMaskGreen()) &&
- (GetMaskBlue()==image.GetMaskBlue()))) )
+ (GetMaskBlue()==image.GetMaskBlue())))) )
{
const unsigned char* source_data = image.GetData() + 3*(xx + yy*image.GetWidth());
int source_step = image.GetWidth()*3;
@@ -1660,6 +1665,8 @@ void wxImage::Paste( const wxImage &image, int x, int y )
source_data += source_step;
target_data += target_step;
}
+
+ copiedPixels = true;
}
// Copy over the alpha channel from the original image
@@ -1668,45 +1675,126 @@ void wxImage::Paste( const wxImage &image, int x, int y )
if ( !HasAlpha() )
InitAlpha();
- const unsigned char* source_data = image.GetAlpha() + xx + yy*image.GetWidth();
- int source_step = image.GetWidth();
+ const unsigned char*
+ alpha_source_data = image.GetAlpha() + xx + yy * image.GetWidth();
+ const int source_step = image.GetWidth();
- unsigned char* target_data = GetAlpha() + (x+xx) + (y+yy)*M_IMGDATA->m_width;
- int target_step = M_IMGDATA->m_width;
+ unsigned char*
+ alpha_target_data = GetAlpha() + (x + xx) + (y + yy) * M_IMGDATA->m_width;
+ const int target_step = M_IMGDATA->m_width;
- for (int j = 0; j < height; j++,
- source_data += source_step,
- target_data += target_step)
+ switch (alphaBlend)
{
- memcpy( target_data, source_data, width );
+ case wxIMAGE_ALPHA_BLEND_OVER:
+ {
+ // Copy just the alpha values.
+ for (int j = 0; j < height; j++,
+ alpha_source_data += source_step,
+ alpha_target_data += target_step)
+ {
+ memcpy(alpha_target_data, alpha_source_data, width);
+ }
+ break;
+ }
+ case wxIMAGE_ALPHA_BLEND_COMPOSE:
+ {
+ const unsigned char*
+ source_data = image.GetData() + 3 * (xx + yy * image.GetWidth());
+
+ unsigned char*
+ target_data = GetData() + 3 * ((x + xx) + (y + yy) * M_IMGDATA->m_width);
+
+ // Combine the alpha values but also apply alpha blending to
+ // the pixels themselves while we copy them.
+ for (int j = 0; j < height; j++,
+ alpha_source_data += source_step,
+ alpha_target_data += target_step,
+ source_data += 3 * source_step,
+ target_data += 3 * target_step)
+ {
+ for (int i = 0; i < width; i++)
+ {
+ float source_alpha = alpha_source_data[i] / 255.0f;
+ float light_left = (alpha_target_data[i] / 255.0f) * (1.0f - source_alpha);
+ float result_alpha = source_alpha + light_left;
+ alpha_target_data[i] = (unsigned char)((result_alpha * 255) +0.5);
+ for (int c = 3 * i; c < 3 * (i + 1); c++)
+ {
+ target_data[c] =
+ (unsigned char)(((source_data[c] * source_alpha +
+ target_data[c] * light_left) /
+ result_alpha) + 0.5);
+ }
+ }
+ }
+
+ copiedPixels = true;
+ break;
+ }
}
+
}
- if (!HasMask() && image.HasMask())
+ // If we hadn't copied them yet we must need to take the mask of the image
+ // being pasted into account.
+ if (!copiedPixels)
{
- unsigned char r = image.GetMaskRed();
- unsigned char g = image.GetMaskGreen();
- unsigned char b = image.GetMaskBlue();
+ const unsigned char* source_data = image.GetData() + 3 * (xx + yy * image.GetWidth());
+ int source_step = image.GetWidth() * 3;
- const unsigned char* source_data = image.GetData() + 3*(xx + yy*image.GetWidth());
- int source_step = image.GetWidth()*3;
+ unsigned char* target_data = GetData() + 3 * ((x + xx) + (y + yy) * M_IMGDATA->m_width);
+ int target_step = M_IMGDATA->m_width * 3;
- unsigned char* target_data = GetData() + 3*((x+xx) + (y+yy)*M_IMGDATA->m_width);
- int target_step = M_IMGDATA->m_width*3;
-
- for (int j = 0; j < height; j++)
+ unsigned char* alpha_target_data = NULL;
+ const int target_alpha_step = M_IMGDATA->m_width;
+ if (HasAlpha())
{
- for (int i = 0; i < width*3; i+=3)
+ alpha_target_data = GetAlpha() + (x + xx) + (y + yy) * M_IMGDATA->m_width;
+ }
+
+ // The mask colours should only be taken into account if the mask is actually enabled
+ if (!image.HasMask())
+ {
+ // Copy all pixels
+ for (int j = 0; j < height; j++)
{
- if ((source_data[i] != r) ||
- (source_data[i+1] != g) ||
- (source_data[i+2] != b))
+ memcpy(target_data, source_data, width * 3);
+ source_data += source_step;
+ target_data += target_step;
+ // Make all the copied pixels fully opaque
+ if (alpha_target_data != NULL)
{
- memcpy( target_data+i, source_data+i, 3 );
+ memset(alpha_target_data, wxALPHA_OPAQUE, width);
+ alpha_target_data += target_alpha_step;
}
}
- source_data += source_step;
- target_data += target_step;
+ }
+ else
+ {
+ // Copy all 'non masked' pixels
+ unsigned char r = image.GetMaskRed();
+ unsigned char g = image.GetMaskGreen();
+ unsigned char b = image.GetMaskBlue();
+
+ for (int j = 0; j < height; j++)
+ {
+ for (int i = 0; i < width * 3; i += 3)
+ {
+ if ((source_data[i] != r) ||
+ (source_data[i + 1] != g) ||
+ (source_data[i + 2] != b))
+ {
+ // Copy the non masked pixel
+ memcpy(target_data + i, source_data + i, 3);
+ if (alpha_target_data != NULL) // Make the copied pixel fully opaque
+ alpha_target_data[i / 3] = wxALPHA_OPAQUE;
+ }
+ }
+ source_data += source_step;
+ target_data += target_step;
+ if (alpha_target_data != NULL)
+ alpha_target_data += target_alpha_step;
+ }
}
}
}
diff --git a/src/common/radiobtncmn.cpp b/src/common/radiobtncmn.cpp
index dc2bd09240..5e847c7ab9 100644
--- a/src/common/radiobtncmn.cpp
+++ b/src/common/radiobtncmn.cpp
@@ -92,4 +92,96 @@ wxCONSTRUCTOR_6( wxRadioButton, wxWindow*, Parent, wxWindowID, Id, \
wxString, Label, wxPoint, Position, wxSize, Size, long, WindowStyle )
+// ----------------------------------------------------------------------------
+// wxRadioButton group navigation
+// ----------------------------------------------------------------------------
+
+wxRadioButton* wxRadioButtonBase::GetFirstInGroup() const
+{
+ wxRadioButton*
+ btn = static_cast(const_cast(this));
+ while (true)
+ {
+ wxRadioButton* prevBtn = btn->GetPreviousInGroup();
+ if (!prevBtn)
+ return btn;
+
+ btn = prevBtn;
+ }
+}
+
+wxRadioButton* wxRadioButtonBase::GetLastInGroup() const
+{
+ wxRadioButton*
+ btn = static_cast(const_cast(this));
+ while (true)
+ {
+ wxRadioButton* nextBtn = btn->GetNextInGroup();
+ if (!nextBtn)
+ return btn;
+
+ btn = nextBtn;
+ }
+}
+
+wxRadioButton* wxRadioButtonBase::GetPreviousInGroup() const
+{
+ if ( HasFlag(wxRB_GROUP) || HasFlag(wxRB_SINGLE) )
+ return NULL;
+
+ const wxWindowList& siblings = GetParent()->GetChildren();
+ wxWindowList::compatibility_iterator nodeThis = siblings.Find(this);
+ wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") );
+
+ // Iterate over all previous siblings until we find the next radio button
+ wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious();
+ wxRadioButton *prevBtn = 0;
+ while (nodeBefore)
+ {
+ prevBtn = wxDynamicCast(nodeBefore->GetData(), wxRadioButton);
+ if (prevBtn)
+ break;
+
+ nodeBefore = nodeBefore->GetPrevious();
+ }
+
+ if (!prevBtn || prevBtn->HasFlag(wxRB_SINGLE))
+ {
+ // no more buttons in group
+ return NULL;
+ }
+
+ return prevBtn;
+}
+
+wxRadioButton* wxRadioButtonBase::GetNextInGroup() const
+{
+ if ( HasFlag(wxRB_SINGLE) )
+ return NULL;
+
+ const wxWindowList& siblings = GetParent()->GetChildren();
+ wxWindowList::compatibility_iterator nodeThis = siblings.Find(this);
+ wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") );
+
+ // Iterate over all previous siblings until we find the next radio button
+ wxWindowList::compatibility_iterator nodeNext = nodeThis->GetNext();
+ wxRadioButton *nextBtn = 0;
+ while (nodeNext)
+ {
+ nextBtn = wxDynamicCast(nodeNext->GetData(), wxRadioButton);
+ if (nextBtn)
+ break;
+
+ nodeNext = nodeNext->GetNext();
+ }
+
+ if ( !nextBtn || nextBtn->HasFlag(wxRB_GROUP) || nextBtn->HasFlag(wxRB_SINGLE) )
+ {
+ // no more buttons or the first button of the next group
+ return NULL;
+ }
+
+ return nextBtn;
+}
+
#endif // wxUSE_RADIOBTN
diff --git a/src/common/strconv.cpp b/src/common/strconv.cpp
index ba25dae157..23c2b0a545 100644
--- a/src/common/strconv.cpp
+++ b/src/common/strconv.cpp
@@ -46,6 +46,7 @@
#include "wx/encconv.h"
#include "wx/fontmap.h"
+#include "wx/private/unicode.h"
#ifdef __DARWIN__
#include "wx/osx/core/private/strconv_cf.h"
@@ -921,7 +922,7 @@ const wxUint32 wxUnicodePUA = 0x100000;
const wxUint32 wxUnicodePUAEnd = wxUnicodePUA + 256;
// this table gives the length of the UTF-8 encoding from its first character:
-const unsigned char tableUtf8Lengths[256] = {
+extern const unsigned char tableUtf8Lengths[256] = {
// single-byte sequences (ASCII):
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00..0F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10..1F
diff --git a/src/common/stringops.cpp b/src/common/stringops.cpp
index 85629406a3..84017ae523 100644
--- a/src/common/stringops.cpp
+++ b/src/common/stringops.cpp
@@ -23,6 +23,8 @@
#include "wx/stringops.h"
#endif
+#include "wx/private/unicode.h"
+
// ===========================================================================
// implementation
// ===========================================================================
@@ -97,40 +99,13 @@ wxWxCharBuffer wxStringOperationsWchar::EncodeNChars(size_t n, const wxUniChar&
// UTF-8 sequences lengths
// ---------------------------------------------------------------------------
-const unsigned char wxStringOperationsUtf8::ms_utf8IterTable[256] = {
- // single-byte sequences (ASCII):
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00..0F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10..1F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 20..2F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 30..3F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40..4F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 50..5F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60..6F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 70..7F
-
- // these are invalid, we use step 1 to skip
- // over them (should never happen):
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80..8F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 90..9F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A0..AF
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B0..BF
- 1, 1, // C0,C1
-
- // two-byte sequences:
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C2..CF
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // D0..DF
-
- // three-byte sequences:
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // E0..EF
-
- // four-byte sequences:
- 4, 4, 4, 4, 4, // F0..F4
-
- // these are invalid again (5- or 6-byte
- // sequences and sequences for code points
- // above U+10FFFF, as restricted by RFC 3629):
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F5..FF
-};
+unsigned char wxStringOperationsUtf8::GetUTF8IterOffset(unsigned char c)
+{
+ unsigned char l = tableUtf8Lengths[c];
+ if ( !l ) //skip over invalid characters
+ l = 1;
+ return l;
+}
// ---------------------------------------------------------------------------
// UTF-8 operations
@@ -166,7 +141,7 @@ bool wxStringOperationsUtf8::IsValidUtf8String(const char *str, size_t len)
{
// if the string is not NULL-terminated, verify we have enough
// bytes in it left for current character's encoding:
- if ( c + ms_utf8IterTable[*c] > end )
+ if ( c + GetUTF8IterOffset(*c) > end )
return false;
}
@@ -364,7 +339,7 @@ wxCharBuffer wxStringOperationsUtf8::EncodeNChars(size_t n, const wxUniChar& ch)
{
Utf8CharBuffer once(EncodeChar(ch));
// the IncIter() table can be used to determine the length of ch's encoding:
- size_t len = ms_utf8IterTable[(unsigned char)once.data[0]];
+ size_t len = GetUTF8IterOffset(once.data[0]);
wxCharBuffer buf(n * len);
char *ptr = buf.data();
diff --git a/src/common/txtstrm.cpp b/src/common/txtstrm.cpp
index c38f7c29ab..1332bb3cf0 100644
--- a/src/common/txtstrm.cpp
+++ b/src/common/txtstrm.cpp
@@ -97,10 +97,11 @@ wxChar wxTextInputStream::GetChar()
m_validEnd = 0;
}
- // We may need to decode up to 4 characters if we have input starting with
- // 3 BOM-like bytes, but not actually containing a BOM, as decoding it will
- // only succeed when 4 bytes are read -- and will yield 4 wide characters.
- wxChar wbuf[4];
+ // We may need to decode up to 6 characters if we have input starting with
+ // 2 null bytes (like in UTF-32BE BOM), and then 3 bytes that look like
+ // the start of UTF-8 sequence, as decoding it will only succeed when
+ // 6 bytes are read -- and will yield 6 wide characters.
+ wxChar wbuf[6];
for(size_t inlen = 0; inlen < sizeof(m_lastBytes); inlen++)
{
if ( inlen >= m_validEnd )
@@ -134,12 +135,13 @@ wxChar wxTextInputStream::GetChar()
// one extra byte, the only explanation is that we were using a
// wxConvAuto conversion recognizing the initial BOM and that
// it couldn't detect the presence or absence of BOM so far,
- // but now finally has enough data to see that there is none.
- // As we must have fallen back to Latin-1 in this case, return
- // just the first byte and keep the other ones for the next
- // time.
- m_validBegin = 1;
- return wbuf[0];
+ // but now finally has enough data to see that there is none, or
+ // it was trying to decode the data as UTF-8 sequence, but now
+ // recognized that it's not valid UTF-8 and switched to fallback.
+ // We don't know how long is the first character or if it's decoded
+ // as 1 or 2 wchar_t characters, so we need to start with 1 byte again.
+ inlen = -1;
+ break;
#if SIZEOF_WCHAR_T == 2
case 2:
diff --git a/src/common/ustring.cpp b/src/common/ustring.cpp
index 6e1768064b..531ee41b9c 100644
--- a/src/common/ustring.cpp
+++ b/src/common/ustring.cpp
@@ -15,6 +15,7 @@
#endif
#include "wx/ustring.h"
+#include "wx/private/unicode.h"
#ifndef WX_PRECOMP
#include "wx/crt.h"
@@ -67,41 +68,6 @@ wxUString &wxUString::assignFromAscii( const char *str, size_type n )
// UTF-8
// ----------------------------------------------------------------------------
-// this table gives the length of the UTF-8 encoding from its first character:
-const unsigned char tableUtf8Lengths[256] = {
- // single-byte sequences (ASCII):
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00..0F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10..1F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 20..2F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 30..3F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40..4F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 50..5F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60..6F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 70..7F
-
- // these are invalid:
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80..8F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90..9F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A0..AF
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B0..BF
- 0, 0, // C0,C1
-
- // two-byte sequences:
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C2..CF
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // D0..DF
-
- // three-byte sequences:
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // E0..EF
-
- // four-byte sequences:
- 4, 4, 4, 4, 4, // F0..F4
-
- // these are invalid again (5- or 6-byte
- // sequences and sequences for code points
- // above U+10FFFF, as restricted by RFC 3629):
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F5..FF
-};
-
wxUString &wxUString::assignFromUTF8( const char *str )
{
if (!str)
diff --git a/src/common/utilscmn.cpp b/src/common/utilscmn.cpp
index 05b6fa002f..bcfee48b33 100644
--- a/src/common/utilscmn.cpp
+++ b/src/common/utilscmn.cpp
@@ -182,12 +182,12 @@ void wxUsleep(unsigned long milliseconds)
}
#endif
-const wxChar *wxGetInstallPrefix()
+wxString wxGetInstallPrefix()
{
wxString prefix;
if ( wxGetEnv(wxT("WXPREFIX"), &prefix) )
- return prefix.c_str();
+ return prefix;
#ifdef wxINSTALL_PREFIX
return wxT(wxINSTALL_PREFIX);
diff --git a/src/generic/bmpcboxg.cpp b/src/generic/bmpcboxg.cpp
index 6432bccaf0..1e3bfff452 100644
--- a/src/generic/bmpcboxg.cpp
+++ b/src/generic/bmpcboxg.cpp
@@ -135,6 +135,11 @@ wxBitmapComboBox::~wxBitmapComboBox()
DoClear();
}
+wxString wxBitmapComboBox::GetStringSelection() const
+{
+ return wxItemContainer::GetStringSelection();
+}
+
// ----------------------------------------------------------------------------
// Item manipulation
// ----------------------------------------------------------------------------
diff --git a/src/generic/caret.cpp b/src/generic/caret.cpp
index 0f5aa7ac51..603888570b 100644
--- a/src/generic/caret.cpp
+++ b/src/generic/caret.cpp
@@ -103,7 +103,8 @@ void wxCaret::InitGeneric()
#ifndef wxHAS_CARET_USING_OVERLAYS
m_xOld =
m_yOld = -1;
- m_bmpUnderCaret.Create(m_width, m_height);
+ if (m_width && m_height)
+ m_bmpUnderCaret.Create(m_width, m_height);
#endif
}
@@ -174,7 +175,10 @@ void wxCaret::DoSize()
m_overlay.Reset();
#else
// Change bitmap size
- m_bmpUnderCaret = wxBitmap(m_width, m_height);
+ if (m_width && m_height)
+ m_bmpUnderCaret = wxBitmap(m_width, m_height);
+ else
+ m_bmpUnderCaret = wxBitmap();
#endif
if (countVisible > 0)
{
diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp
index 45e698960d..c47314ee24 100644
--- a/src/generic/listctrl.cpp
+++ b/src/generic/listctrl.cpp
@@ -950,6 +950,7 @@ bool wxListLineData::Highlight( bool on )
return false;
m_highlighted = on;
+ m_owner->UpdateSelectionCount(on);
return true;
}
@@ -1571,6 +1572,7 @@ wxEND_EVENT_TABLE()
void wxListMainWindow::Init()
{
m_dirty = true;
+ m_selCount =
m_countVirt = 0;
m_lineFrom =
m_lineTo = (size_t)-1;
@@ -1598,7 +1600,8 @@ void wxListMainWindow::Init()
m_current =
m_lineLastClicked =
m_lineSelectSingleOnUp =
- m_lineBeforeLastClicked = (size_t)-1;
+ m_lineBeforeLastClicked =
+ m_anchor = (size_t)-1;
m_hasCheckBoxes = false;
}
@@ -1866,8 +1869,13 @@ bool wxListMainWindow::IsHighlighted(size_t line) const
void wxListMainWindow::HighlightLines( size_t lineFrom,
size_t lineTo,
- bool highlight )
+ bool highlight,
+ SendEvent sendEvent )
{
+ // It is safe to swap the bounds here if they are not in order.
+ if ( lineFrom > lineTo )
+ wxSwap(lineFrom, lineTo);
+
if ( IsVirtual() )
{
wxArrayInt linesChanged;
@@ -1890,13 +1898,13 @@ void wxListMainWindow::HighlightLines( size_t lineFrom,
{
for ( size_t line = lineFrom; line <= lineTo; line++ )
{
- if ( HighlightLine(line, highlight) )
+ if ( HighlightLine(line, highlight, sendEvent) )
RefreshLine(line);
}
}
}
-bool wxListMainWindow::HighlightLine( size_t line, bool highlight )
+bool wxListMainWindow::HighlightLine( size_t line, bool highlight, SendEvent sendEvent )
{
bool changed;
@@ -1912,7 +1920,7 @@ bool wxListMainWindow::HighlightLine( size_t line, bool highlight )
changed = ld->Highlight(highlight);
}
- if ( changed )
+ if ( changed && sendEvent )
{
SendNotify( line, highlight ? wxEVT_LIST_ITEM_SELECTED
: wxEVT_LIST_ITEM_DESELECTED );
@@ -2197,6 +2205,58 @@ void wxListMainWindow::HighlightAll( bool on )
}
}
+void wxListMainWindow::HighlightOnly( size_t line, size_t oldLine )
+{
+ const unsigned selCount = GetSelectedItemCount();
+
+ if ( selCount == 1 && IsHighlighted(line) )
+ {
+ return; // Nothing changed.
+ }
+
+ if ( oldLine != (size_t)-1 )
+ {
+ IsHighlighted(oldLine) ? ReverseHighlight(oldLine)
+ : RefreshLine(oldLine); // refresh the old focus to remove it
+ }
+
+ if ( selCount > 1 ) // multiple-selection only
+ {
+ // Deselecting many items at once will generate wxEVT_XXX_DESELECTED event
+ // for each one of them. although this may be inefficient if the number of
+ // deselected items is too much, we keep doing this (for non-virtual list
+ // controls) for backward compatibility concerns. For virtual listctrl (in
+ // multi-selection mode), wxMSW sends only a notification to indicate that
+ // something has been deselected. Notice that to be fully compatible with
+ // wxMSW behaviour, _line_ shouldn't be deselected if it was selected.
+
+ const SendEvent sendEvent = IsVirtual() ? SendEvent_None : SendEvent_Normal;
+
+ size_t lineFrom = 0,
+ lineTo = GetItemCount() - 1;
+
+ if ( line > lineFrom && line < lineTo )
+ {
+ HighlightLines(lineFrom, line - 1, false, sendEvent);
+ HighlightLines(line + 1, lineTo, false, sendEvent);
+ }
+ else // _line_ is equal to lineFrom or lineTo
+ {
+ line == lineFrom ? ++lineFrom : --lineTo;
+ HighlightLines(lineFrom, lineTo, false, sendEvent);
+ }
+
+ // If we didn't send the event for individual items above, send it for all of them now.
+ if ( sendEvent == SendEvent_None )
+ SendNotify((size_t)-1, wxEVT_LIST_ITEM_DESELECTED);
+ }
+
+ // _line_ should be the only selected item.
+ HighlightLine(line);
+ // refresh the new focus to add it.
+ RefreshLine(line);
+}
+
void wxListMainWindow::OnChildFocus(wxChildFocusEvent& WXUNUSED(event))
{
// Do nothing here. This prevents the default handler in wxScrolledWindow
@@ -2241,8 +2301,13 @@ void wxListMainWindow::SendNotify( size_t line,
GetParent()->GetEventHandler()->ProcessEvent( le );
}
-void wxListMainWindow::ChangeCurrent(size_t current)
+bool wxListMainWindow::ChangeCurrentWithoutEvent(size_t current)
{
+ if ( current == m_current )
+ {
+ return false; // Nothing changed!
+ }
+
m_current = current;
// as the current item changed, we shouldn't start editing it when the
@@ -2250,7 +2315,13 @@ void wxListMainWindow::ChangeCurrent(size_t current)
if ( m_renameTimer->IsRunning() )
m_renameTimer->Stop();
- SendNotify(current, wxEVT_LIST_ITEM_FOCUSED);
+ return true;
+}
+
+void wxListMainWindow::ChangeCurrent(size_t current)
+{
+ if ( ChangeCurrentWithoutEvent(current) )
+ SendNotify(current, wxEVT_LIST_ITEM_FOCUSED);
}
wxTextCtrl *wxListMainWindow::EditLabel(long item, wxClassInfo* textControlClass)
@@ -2396,7 +2467,11 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
evtCtx.SetEventObject(GetParent());
GetParent()->GetEventHandler()->ProcessEvent(evtCtx);
}
- return;
+
+ if ( IsEmpty() )
+ return;
+
+ // Continue processing...
}
if (m_dirty)
@@ -2521,8 +2596,7 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
if (m_lineSelectSingleOnUp != (size_t)-1)
{
// select single line
- HighlightAll( false );
- ReverseHighlight(m_lineSelectSingleOnUp);
+ HighlightOnly(m_lineSelectSingleOnUp);
}
if (m_lastOnSame)
@@ -2542,6 +2616,14 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
m_lastOnSame = false;
}
+ if ( GetSelectedItemCount() == 1 || event.CmdDown() )
+ {
+ // In multiple selection mode, the anchor is set to the first selected
+ // item or can be changed to m_current if Ctrl key is down, as is the
+ // case under wxMSW.
+ m_anchor = m_current;
+ }
+
m_lineSelectSingleOnUp = (size_t)-1;
}
else
@@ -2561,9 +2643,8 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
// Multi-selections should not be cleared if a selected item is clicked.
if (!IsHighlighted(current))
{
- HighlightAll(false);
ChangeCurrent(current);
- ReverseHighlight(m_current);
+ HighlightOnly(m_current);
}
SendNotify( current, wxEVT_LIST_ITEM_RIGHT_CLICK, event.GetPosition() );
@@ -2581,7 +2662,7 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
m_lineLastClicked = current;
size_t oldCurrent = m_current;
- bool oldWasSelected = IsHighlighted(m_current);
+ bool oldWasSelected = HasCurrent() && IsHighlighted(m_current);
bool cmdModifierDown = event.CmdDown();
if ( IsSingleSel() || !(cmdModifierDown || event.ShiftDown()) )
@@ -2592,11 +2673,8 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
}
else if (IsSingleSel() || !IsHighlighted(current))
{
- HighlightAll(false);
-
ChangeCurrent(current);
-
- ReverseHighlight(m_current);
+ HighlightOnly(m_current, oldWasSelected ? oldCurrent : (size_t)-1);
}
else // multi sel & current is highlighted & no mod keys
{
@@ -2616,16 +2694,15 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
{
ChangeCurrent(current);
- size_t lineFrom = oldCurrent,
- lineTo = current;
-
- if ( lineTo < lineFrom )
+ if ( oldCurrent == (size_t)-1 )
{
- lineTo = lineFrom;
- lineFrom = m_current;
+ // Highlight m_current only if there is no previous selection.
+ HighlightLine(m_current);
+ }
+ else if ( oldCurrent != current && m_anchor != (size_t)-1 )
+ {
+ ExtendSelection(oldCurrent, current);
}
-
- HighlightLines(lineFrom, lineTo);
}
else // !ctrl, !shift
{
@@ -2634,7 +2711,7 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
}
}
- if (m_current != oldCurrent)
+ if (m_current != oldCurrent && oldCurrent != (size_t)-1)
RefreshLine( oldCurrent );
// Set the flag telling us whether the next click on this item should
@@ -2739,6 +2816,81 @@ bool wxListMainWindow::ScrollList(int WXUNUSED(dx), int dy)
// keyboard handling
// ----------------------------------------------------------------------------
+// Helper function which handles items selection correctly and efficiently. and
+// simply, mimic the wxMSW behaviour. And The benefit of this function is that it
+// ensures that wxEVT_LIST_ITEM_{DE}SELECTED events are only generated for items
+// freshly (de)selected (i.e. items that have really changed state). Useful for
+// multi-selection mode when selecting using mouse or arrows with Shift key down.
+void wxListMainWindow::ExtendSelection(size_t oldCurrent, size_t newCurrent)
+{
+ // Refresh the old/new focus to remove/add it
+ RefreshLine(oldCurrent);
+ RefreshLine(newCurrent);
+
+ // Given a selection [anchor, old], to change/extend it to new (i.e. the
+ // selection becomes [anchor, new]) we discriminate three possible cases:
+ //
+ // Case 1) new < old <= anchor || anchor <= old < new
+ // i.e. oldCurrent between anchor and newCurrent, in which case we:
+ // - Highlight everything between anchor and newCurrent (inclusive).
+ //
+ // Case 2) old < new <= anchor || anchor <= new < old
+ // i.e. newCurrent between anchor and oldCurrent, in which case we:
+ // - Unhighlight everything between oldCurrent and newCurrent (exclusive).
+ //
+ // Case 3) old < anchor < new || new < anchor < old
+ // i.e. anchor between oldCurrent and newCurrent, in which case we
+ // - Highlight everything between anchor and newCurrent (inclusive).
+ // - Unhighlight everything between anchor (exclusive) and oldCurrent.
+
+ size_t lineFrom, lineTo;
+
+ if ( (newCurrent < oldCurrent && oldCurrent <= m_anchor) ||
+ (newCurrent > oldCurrent && oldCurrent >= m_anchor) )
+ {
+ lineFrom = m_anchor;
+ lineTo = newCurrent;
+
+ HighlightLines(lineFrom, lineTo);
+ }
+ else if ( (oldCurrent < newCurrent && newCurrent <= m_anchor) ||
+ (oldCurrent > newCurrent && newCurrent >= m_anchor) )
+ {
+ lineFrom = oldCurrent;
+ lineTo = newCurrent;
+
+ // Exclude newCurrent from being deselected
+ (lineTo < lineFrom) ? ++lineTo : --lineTo;
+
+ HighlightLines(lineFrom, lineTo, false);
+
+ // For virtual listctrl (in multi-selection mode), wxMSW sends only
+ // a notification to indicate that something has been deselected.
+ if ( IsVirtual() )
+ SendNotify((size_t)-1, wxEVT_LIST_ITEM_DESELECTED);
+ }
+ else if ( (oldCurrent < m_anchor && m_anchor < newCurrent) ||
+ (newCurrent < m_anchor && m_anchor < oldCurrent) )
+ {
+ lineFrom = m_anchor;
+ lineTo = oldCurrent;
+
+ // Exclude anchor from being deselected
+ (lineTo < lineFrom) ? --lineFrom : ++lineFrom;
+
+ HighlightLines(lineFrom, lineTo, false);
+
+ // See above.
+ if ( IsVirtual() )
+ SendNotify((size_t)-1, wxEVT_LIST_ITEM_DESELECTED);
+
+ lineFrom = m_anchor;
+ lineTo = newCurrent;
+
+ HighlightLines(lineFrom, lineTo);
+ }
+}
+
void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
{
wxCHECK_RET( newCurrent < (size_t)GetItemCount(),
@@ -2746,43 +2898,34 @@ void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
size_t oldCurrent = m_current;
+ ChangeCurrent(newCurrent);
+
// in single selection we just ignore Shift as we can't select several
// items anyhow
if ( event.ShiftDown() && !IsSingleSel() )
{
- ChangeCurrent(newCurrent);
-
- // refresh the old focus to remove it
- RefreshLine( oldCurrent );
-
- // select all the items between the old and the new one
- if ( oldCurrent > newCurrent )
- {
- newCurrent = oldCurrent;
- oldCurrent = m_current;
- }
-
- HighlightLines(oldCurrent, newCurrent);
+ ExtendSelection(oldCurrent, newCurrent);
}
else // !shift
{
- // all previously selected items are unselected unless ctrl is held
- // in a multiselection control
+ // all previously selected items are unselected unless ctrl is held in
+ // a multi-selection control. in single selection mode we must always
+ // have a selected item.
if ( !event.ControlDown() || IsSingleSel() )
- HighlightAll(false);
+ {
+ HighlightOnly(m_current, oldCurrent);
- ChangeCurrent(newCurrent);
-
- // refresh the old focus to remove it
- RefreshLine( oldCurrent );
-
- // in single selection mode we must always have a selected item
- if ( !event.ControlDown() || IsSingleSel() )
- HighlightLine( m_current, true );
+ // Update anchor
+ m_anchor = m_current;
+ }
+ else
+ {
+ // refresh the old/new focus to remove/add it
+ RefreshLine(oldCurrent);
+ RefreshLine(m_current);
+ }
}
- RefreshLine( m_current );
-
MoveToFocus();
}
@@ -2799,10 +2942,11 @@ void wxListMainWindow::OnKeyDown( wxKeyEvent &event )
// send a list event
wxListEvent le( wxEVT_LIST_KEY_DOWN, parent->GetId() );
+ const size_t current = ShouldSendEventForCurrent() ? m_current : (size_t)-1;
le.m_item.m_itemId =
- le.m_itemIndex = m_current;
- if (HasCurrent())
- GetLine(m_current)->GetItem( 0, le.m_item );
+ le.m_itemIndex = current;
+ if ( current != (size_t)-1 )
+ GetLine(current)->GetItem( 0, le.m_item );
le.m_code = event.GetKeyCode();
le.SetEventObject( parent );
if (parent->GetEventHandler()->ProcessEvent( le ))
@@ -2956,7 +3100,7 @@ void wxListMainWindow::OnChar( wxKeyEvent &event )
{
ReverseHighlight(m_current);
}
- else // normal space press
+ else if ( ShouldSendEventForCurrent() ) // normal space press
{
SendNotify( m_current, wxEVT_LIST_ITEM_ACTIVATED );
}
@@ -2969,7 +3113,7 @@ void wxListMainWindow::OnChar( wxKeyEvent &event )
case WXK_RETURN:
case WXK_EXECUTE:
- if ( event.HasModifiers() )
+ if ( event.HasModifiers() || !ShouldSendEventForCurrent() )
{
event.Skip();
break;
@@ -3078,6 +3222,7 @@ void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
{
m_hasFocus = true;
+ UpdateCurrent();
RefreshSelected();
}
}
@@ -3621,17 +3766,7 @@ int wxListMainWindow::GetSelectedItemCount() const
if ( IsVirtual() )
return m_selStore.GetSelectedCount();
- // TODO: we probably should maintain the number of items selected even for
- // non virtual controls as enumerating all lines is really slow...
- size_t countSel = 0;
- size_t count = GetItemCount();
- for ( size_t line = 0; line < count; line++ )
- {
- if ( GetLine(line)->IsHighlighted() )
- countSel++;
- }
-
- return countSel;
+ return m_selCount;
}
// ----------------------------------------------------------------------------
@@ -4036,9 +4171,6 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh)
if ( !noRefresh )
{
- // FIXME: why should we call it from here?
- UpdateCurrent();
-
RefreshAll();
}
}
@@ -4059,7 +4191,13 @@ void wxListMainWindow::RefreshAll()
void wxListMainWindow::UpdateCurrent()
{
if ( !HasCurrent() && !IsEmpty() )
- ChangeCurrent(0);
+ {
+ // Initialise m_current to the first item without sending any
+ // wxEVT_LIST_ITEM_FOCUSED event (typicaly when the control gains focus)
+ // and this is to allow changing the focused item using the arrow keys.
+ // which is the behaviour found in the wxMSW port.
+ ChangeCurrentWithoutEvent(0);
+ }
}
long wxListMainWindow::GetNextItem( long item,
@@ -4248,6 +4386,10 @@ void wxListMainWindow::DoDeleteAllItems()
m_countVirt = 0;
m_selStore.Clear();
}
+ else
+ {
+ m_selCount = 0;
+ }
if ( InReportView() )
ResetVisibleLinesRange();
diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp
index 4e4cf7a5b5..977954ca35 100644
--- a/src/gtk/textctrl.cpp
+++ b/src/gtk/textctrl.cpp
@@ -684,8 +684,9 @@ void wxTextCtrl::Init()
m_text = NULL;
m_buffer = NULL;
- m_showPositionOnThaw = NULL;
+ m_showPositionDefer = NULL;
m_anonymousMarkList = NULL;
+ m_afterLayoutId = 0;
}
wxTextCtrl::~wxTextCtrl()
@@ -702,6 +703,8 @@ wxTextCtrl::~wxTextCtrl()
if (m_anonymousMarkList)
g_slist_free(m_anonymousMarkList);
+ if (m_afterLayoutId)
+ g_source_remove(m_afterLayoutId);
}
wxTextCtrl::wxTextCtrl( wxWindow *parent,
@@ -1102,6 +1105,25 @@ bool wxTextCtrl::IsEmpty() const
return wxTextEntry::IsEmpty();
}
+void wxTextCtrl::GTKAfterLayout()
+{
+ m_afterLayoutId = 0;
+ if (m_showPositionDefer && !IsFrozen())
+ {
+ gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), m_showPositionDefer);
+ m_showPositionDefer = NULL;
+ }
+}
+
+extern "C" {
+static gboolean afterLayout(void* data)
+{
+ wxTextCtrl* win = static_cast(data);
+ win->GTKAfterLayout();
+ return false;
+}
+}
+
void wxTextCtrl::WriteText( const wxString &text )
{
wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
@@ -1163,15 +1185,16 @@ void wxTextCtrl::WriteText( const wxString &text )
gtk_text_buffer_delete_selection(m_buffer, false, true);
// Insert the text
+ GtkTextMark* insertMark = gtk_text_buffer_get_insert(m_buffer);
GtkTextIter iter;
- gtk_text_buffer_get_iter_at_mark( m_buffer, &iter,
- gtk_text_buffer_get_insert (m_buffer) );
+ gtk_text_buffer_get_iter_at_mark(m_buffer, &iter, insertMark);
+
+ const bool insertIsEnd = gtk_text_iter_is_end(&iter) != 0;
gtk_text_buffer_insert( m_buffer, &iter, buffer, buffer.length() );
- // Scroll to cursor, but only if scrollbar thumb is at the very bottom
- // won't work when frozen, text view is not using m_buffer then
- if (!IsFrozen())
+ // Scroll to cursor, if it is at the end and scrollbar thumb is at the bottom
+ if (insertIsEnd)
{
GtkAdjustment* adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(m_widget));
const double value = gtk_adjustment_get_value(adj);
@@ -1179,10 +1202,19 @@ void wxTextCtrl::WriteText( const wxString &text )
const double page_size = gtk_adjustment_get_page_size(adj);
if (wxIsSameDouble(value, upper - page_size))
{
- gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(m_text),
- gtk_text_buffer_get_insert(m_buffer), 0, false, 0, 1);
+ if (!IsFrozen())
+ gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), insertMark);
+
+ // GtkTextView's incremental background layout makes scrolling
+ // to end unreliable until the layout has been completed
+ m_showPositionDefer = insertMark;
}
}
+ if (m_afterLayoutId == 0)
+ {
+ m_afterLayoutId =
+ g_idle_add_full(GTK_TEXT_VIEW_PRIORITY_VALIDATE + 1, afterLayout, this, NULL);
+ }
}
wxString wxTextCtrl::GetLineText( long lineNo ) const
@@ -1363,7 +1395,7 @@ void wxTextCtrl::SetInsertionPoint( long pos )
GtkTextMark* mark = gtk_text_buffer_get_insert(m_buffer);
if (IsFrozen())
// defer until Thaw, text view is not using m_buffer now
- m_showPositionOnThaw = mark;
+ m_showPositionDefer = mark;
else
gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), mark);
}
@@ -1480,7 +1512,7 @@ void wxTextCtrl::ShowPosition( long pos )
gtk_text_buffer_move_mark(m_buffer, mark, &iter);
if (IsFrozen())
// defer until Thaw, text view is not using m_buffer now
- m_showPositionOnThaw = mark;
+ m_showPositionDefer = mark;
else
gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), mark);
}
@@ -2136,11 +2168,11 @@ void wxTextCtrl::DoThaw()
g_object_unref(m_buffer);
g_signal_handler_disconnect(m_buffer, sig_id);
- if (m_showPositionOnThaw != NULL)
+ if (m_showPositionDefer)
{
- gtk_text_view_scroll_mark_onscreen(
- GTK_TEXT_VIEW(m_text), m_showPositionOnThaw);
- m_showPositionOnThaw = NULL;
+ gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), m_showPositionDefer);
+ if (m_afterLayoutId == 0)
+ m_showPositionDefer = NULL;
}
}
diff --git a/src/gtk/webview_webkit2.cpp b/src/gtk/webview_webkit2.cpp
index 69583a546a..c507d4b64a 100644
--- a/src/gtk/webview_webkit2.cpp
+++ b/src/gtk/webview_webkit2.cpp
@@ -14,6 +14,7 @@
#include "wx/dir.h"
#include "wx/dynlib.h"
#include "wx/filename.h"
+#include "wx/stdpaths.h"
#include "wx/stockitem.h"
#include "wx/gtk/webview_webkit.h"
#include "wx/gtk/control.h"
@@ -369,7 +370,7 @@ wxgtk_webview_webkit_counted_matches(WebKitFindController *,
}
// This function checks if the specified directory contains our web extension.
-static bool CheckDirectoryForWebExt(const char* dirname)
+static bool CheckDirectoryForWebExt(const wxString& dirname)
{
wxDir dir;
if ( !wxDir::Exists(dirname) || !dir.Open(dirname) )
@@ -399,6 +400,23 @@ static bool CheckDirectoryForWebExt(const char* dirname)
return false;
}
+static bool TrySetWebExtensionsDirectory(WebKitWebContext *context, const wxString& dir)
+{
+ if (dir.empty() || !CheckDirectoryForWebExt(dir))
+ return false;
+
+ webkit_web_context_set_web_extensions_directory(context, dir.utf8_str());
+ return true;
+}
+
+static wxString GetStandardWebExtensionsDir()
+{
+ wxString dir = wxDynamicLibrary::GetPluginsDirectory();
+ if ( !dir.empty() )
+ dir += "/web-extensions";
+ return dir;
+}
+
static void
wxgtk_initialize_web_extensions(WebKitWebContext *context,
GDBusServer *dbusServer)
@@ -406,36 +424,28 @@ wxgtk_initialize_web_extensions(WebKitWebContext *context,
const char *address = g_dbus_server_get_client_address(dbusServer);
GVariant *user_data = g_variant_new("(s)", address);
- // The first value is the location in which the extension is supposed to be
- // normally installed, while the other three are used as fallbacks to allow
- // running the tests and sample using wxWebView before installing it.
- const char* const directories[] =
+ // Try to setup extension loading from the location it is supposed to be
+ // normally installed in.
+ if ( !TrySetWebExtensionsDirectory(context, GetStandardWebExtensionsDir()) )
{
- WX_WEB_EXTENSIONS_DIRECTORY,
- "..",
- "../..",
- "lib",
- };
-
- const char* dir = NULL;
- for ( size_t n = 0; n < WXSIZEOF(directories); ++n )
- {
- if ( CheckDirectoryForWebExt(directories[n]) )
+ // These relative locations are used as fallbacks to allow running
+ // the tests and sample using wxWebView before installing it.
+ wxString exepath = wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath();
+ if ( !exepath.empty() )
{
- dir = directories[n];
- break;
- }
- }
+ wxString const directories[] =
+ {
+ exepath + "/..",
+ exepath + "/../..",
+ exepath + "/lib",
+ };
- if ( dir )
- {
- webkit_web_context_set_web_extensions_directory(context, dir);
- }
- else
- {
- wxLogWarning(_("Web extension not found in \"%s\", "
- "some wxWebView functionality will be not available"),
- WX_WEB_EXTENSIONS_DIRECTORY);
+ for ( size_t n = 0; n < WXSIZEOF(directories); ++n )
+ {
+ if ( !TrySetWebExtensionsDirectory(context, directories[n]) )
+ break;
+ }
+ }
}
webkit_web_context_set_web_extensions_initialization_user_data(context,
@@ -1020,10 +1030,11 @@ bool wxWebViewWebKit::IsEditable() const
void wxWebViewWebKit::DeleteSelection()
{
- if (m_extension)
+ GDBusProxy *extension = GetExtensionProxy();
+ if (extension)
{
guint64 page_id = webkit_web_view_get_page_id(m_web_view);
- GVariant *retval = g_dbus_proxy_call_sync(m_extension,
+ GVariant *retval = g_dbus_proxy_call_sync(extension,
"DeleteSelection",
g_variant_new("(t)", page_id),
G_DBUS_CALL_FLAGS_NONE, -1,
@@ -1037,10 +1048,11 @@ void wxWebViewWebKit::DeleteSelection()
bool wxWebViewWebKit::HasSelection() const
{
- if (m_extension)
+ GDBusProxy *extension = GetExtensionProxy();
+ if (extension)
{
guint64 page_id = webkit_web_view_get_page_id(m_web_view);
- GVariant *retval = g_dbus_proxy_call_sync(m_extension,
+ GVariant *retval = g_dbus_proxy_call_sync(extension,
"HasSelection",
g_variant_new("(t)", page_id),
G_DBUS_CALL_FLAGS_NONE, -1,
@@ -1064,10 +1076,11 @@ void wxWebViewWebKit::SelectAll()
wxString wxWebViewWebKit::GetSelectedText() const
{
- if (m_extension)
+ GDBusProxy *extension = GetExtensionProxy();
+ if (extension)
{
guint64 page_id = webkit_web_view_get_page_id(m_web_view);
- GVariant *retval = g_dbus_proxy_call_sync(m_extension,
+ GVariant *retval = g_dbus_proxy_call_sync(extension,
"GetSelectedText",
g_variant_new("(t)", page_id),
G_DBUS_CALL_FLAGS_NONE, -1,
@@ -1085,10 +1098,11 @@ wxString wxWebViewWebKit::GetSelectedText() const
wxString wxWebViewWebKit::GetSelectedSource() const
{
- if (m_extension)
+ GDBusProxy *extension = GetExtensionProxy();
+ if (extension)
{
guint64 page_id = webkit_web_view_get_page_id(m_web_view);
- GVariant *retval = g_dbus_proxy_call_sync(m_extension,
+ GVariant *retval = g_dbus_proxy_call_sync(extension,
"GetSelectedSource",
g_variant_new("(t)", page_id),
G_DBUS_CALL_FLAGS_NONE, -1,
@@ -1106,10 +1120,11 @@ wxString wxWebViewWebKit::GetSelectedSource() const
void wxWebViewWebKit::ClearSelection()
{
- if (m_extension)
+ GDBusProxy *extension = GetExtensionProxy();
+ if (extension)
{
guint64 page_id = webkit_web_view_get_page_id(m_web_view);
- GVariant *retval = g_dbus_proxy_call_sync(m_extension,
+ GVariant *retval = g_dbus_proxy_call_sync(extension,
"ClearSelection",
g_variant_new("(t)", page_id),
G_DBUS_CALL_FLAGS_NONE, -1,
@@ -1123,10 +1138,11 @@ void wxWebViewWebKit::ClearSelection()
wxString wxWebViewWebKit::GetPageText() const
{
- if (m_extension)
+ GDBusProxy *extension = GetExtensionProxy();
+ if (extension)
{
guint64 page_id = webkit_web_view_get_page_id(m_web_view);
- GVariant *retval = g_dbus_proxy_call_sync(m_extension,
+ GVariant *retval = g_dbus_proxy_call_sync(extension,
"GetPageText",
g_variant_new("(t)", page_id),
G_DBUS_CALL_FLAGS_NONE, -1,
@@ -1410,4 +1426,15 @@ void wxWebViewWebKit::SetupWebExtensionServer()
g_object_unref(observer);
}
+GDBusProxy *wxWebViewWebKit::GetExtensionProxy() const
+{
+ if (!m_extension)
+ {
+ g_warning("Web extension not found in \"%s\", "
+ "some wxWebView functionality will be not available",
+ (const char*)GetStandardWebExtensionsDir().utf8_str());
+ }
+ return m_extension;
+}
+
#endif // wxUSE_WEBVIEW && wxUSE_WEBVIEW_WEBKIT2
diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp
index 6ebc77b68e..fe7fcd7737 100644
--- a/src/msw/dc.cpp
+++ b/src/msw/dc.cpp
@@ -2118,6 +2118,28 @@ wxPoint wxMSWDCImpl::LogicalToDevice(wxCoord x, wxCoord y) const
return wxPoint(p[0].x, p[0].y);
}
+wxSize wxMSWDCImpl::DeviceToLogicalRel(int x, int y) const
+{
+ POINT p[2];
+ p[0].x = 0;
+ p[0].y = 0;
+ p[1].x = x;
+ p[1].y = y;
+ ::DPtoLP(GetHdc(), p, WXSIZEOF(p));
+ return wxSize(p[1].x-p[0].x, p[1].y-p[0].y);
+}
+
+wxSize wxMSWDCImpl::LogicalToDeviceRel(int x, int y) const
+{
+ POINT p[2];
+ p[0].x = 0;
+ p[0].y = 0;
+ p[1].x = x;
+ p[1].y = y;
+ ::LPtoDP(GetHdc(), p, WXSIZEOF(p));
+ return wxSize(p[1].x-p[0].x, p[1].y-p[0].y);
+}
+
// ----------------------------------------------------------------------------
// Transform matrix
// ----------------------------------------------------------------------------
diff --git a/src/msw/graphicsd2d.cpp b/src/msw/graphicsd2d.cpp
index a436dd6243..cc6bdb08d4 100644
--- a/src/msw/graphicsd2d.cpp
+++ b/src/msw/graphicsd2d.cpp
@@ -4494,11 +4494,11 @@ void wxD2DContext::DrawBitmap(const wxGraphicsBitmap& bmp, wxDouble x, wxDouble
wxD2DBitmapData* bitmapData = wxGetD2DBitmapData(bmp);
bitmapData->Bind(this);
- D2D1_SIZE_F imgSize = bitmapData->GetD2DBitmap()->GetSize();
+ wxBitmap const& bitmap = static_cast(bitmapData->GetNativeBitmap())->GetSourceBitmap();
m_renderTargetHolder->DrawBitmap(
bitmapData->GetD2DBitmap(),
- D2D1::RectF(0, 0, imgSize.width, imgSize.height),
+ D2D1::RectF(0, 0, bitmap.GetWidth(), bitmap.GetHeight()),
D2D1::RectF(x, y, x + w, y + h),
GetInterpolationQuality(),
GetCompositionMode());
diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp
index b5d912a764..33031f3d70 100644
--- a/src/msw/listctrl.cpp
+++ b/src/msw/listctrl.cpp
@@ -788,7 +788,15 @@ bool wxListCtrl::SetColumnWidth(int col, int width)
else if ( width == wxLIST_AUTOSIZE_USEHEADER)
width = LVSCW_AUTOSIZE_USEHEADER;
- return ListView_SetColumnWidth(GetHwnd(), col, width) != 0;
+ if ( !ListView_SetColumnWidth(GetHwnd(), col, width) )
+ return false;
+
+ // Failure to explicitly refresh the control with horizontal rules results
+ // in corrupted rules display.
+ if ( HasFlag(wxLC_HRULES) )
+ Refresh();
+
+ return true;
}
// ----------------------------------------------------------------------------
@@ -3261,12 +3269,7 @@ void wxListCtrl::OnPaint(wxPaintEvent& event)
dc.SetPen(pen);
dc.SetBrush(* wxTRANSPARENT_BRUSH);
- // Find the coordinate of the right most visible point: this is not the
- // same as GetClientSize().x because the window might not be fully visible,
- // it could be clipped by its parent.
- const int availableWidth = GetParent()->GetClientSize().x - GetPosition().x;
- int visibleWidth = wxMin(GetClientSize().x,
- availableWidth - GetWindowBorderSize().x);
+ wxSize clientSize = GetClientSize();
const int countPerPage = GetCountPerPage();
if (countPerPage < 0)
@@ -3278,9 +3281,6 @@ void wxListCtrl::OnPaint(wxPaintEvent& event)
const long top = GetTopItem();
const long bottom = wxMin(top + countPerPage, itemCount - 1);
- wxRect clipRect;
- dc.GetClippingBox(clipRect);
-
if (drawHRules)
{
wxRect itemRect;
@@ -3289,23 +3289,9 @@ void wxListCtrl::OnPaint(wxPaintEvent& event)
if (GetItemRect(i, itemRect))
{
const int cy = itemRect.GetBottom();
- dc.DrawLine(clipRect.x, cy, clipRect.GetRight() + 1, cy);
+ dc.DrawLine(0, cy, clientSize.x, cy);
}
}
-
- /*
- The drawing can be clipped horizontally to the rightmost column.
- This happens when an item is added (and visible) and results in a
- horizontal rule being clipped instead of drawn across the entire
- list control. In that case we request for the part to the right of
- the rightmost column to be drawn as well.
- */
- if ( clipRect.GetRight() < visibleWidth - 1 && clipRect.width )
- {
- RefreshRect(wxRect(clipRect.GetRight(), clipRect.y,
- visibleWidth - clipRect.width, clipRect.height),
- false /* don't erase background */);
- }
}
if (drawVRules)
@@ -3347,7 +3333,7 @@ void wxListCtrl::OnPaint(wxPaintEvent& event)
wxDCBrushChanger changeBrush(dc, GetBackgroundColour());
dc.DrawRectangle(0, topItemRect.GetY() - gap,
- visibleWidth, gap);
+ clientSize.GetWidth(), gap);
}
const int numCols = GetColumnCount();
diff --git a/src/msw/slider.cpp b/src/msw/slider.cpp
index d859ea5d55..3cb247965d 100644
--- a/src/msw/slider.cpp
+++ b/src/msw/slider.cpp
@@ -313,15 +313,28 @@ bool wxSlider::MSWOnScroll(int WXUNUSED(orientation),
SetValue(newPos);
wxScrollEvent event(scrollEvent, m_windowId);
+ bool processed = false;
+
event.SetPosition(newPos);
event.SetEventObject( this );
- HandleWindowEvent(event);
+ processed = HandleWindowEvent(event);
- wxCommandEvent cevent( wxEVT_SLIDER, GetId() );
- cevent.SetInt( newPos );
- cevent.SetEventObject( this );
+ // Do not generate wxEVT_SLIDER when the native scroll message
+ // parameter is SB_ENDSCROLL, which always follows only after
+ // another scroll message which already changed the slider value.
+ // Therefore, sending wxEVT_SLIDER after SB_ENDSCROLL
+ // would result in two wxEVT_SLIDER events with the same value.
+ if ( wParam != SB_ENDSCROLL )
+ {
+ wxCommandEvent cevent( wxEVT_SLIDER, GetId() );
- return HandleWindowEvent( cevent );
+ cevent.SetInt( newPos );
+ cevent.SetEventObject( this );
+
+ processed = HandleWindowEvent( cevent );
+ }
+
+ return processed;
}
void wxSlider::Command (wxCommandEvent & event)
diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm
index 813bb1face..7f26b8585e 100644
--- a/src/osx/cocoa/window.mm
+++ b/src/osx/cocoa/window.mm
@@ -518,7 +518,7 @@ void wxWidgetCocoaImpl::SetupKeyEvent(wxKeyEvent &wxevent , NSEvent * nsEvent, N
}
}
- if ( !keyval )
+ if ( !keyval && aunichar < 256 ) // only for ASCII characters
{
if ( wxevent.GetEventType() == wxEVT_KEY_UP || wxevent.GetEventType() == wxEVT_KEY_DOWN )
keyval = wxToupper( aunichar ) ;
diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp
index 03921a9ce9..96405ffba6 100644
--- a/src/propgrid/propgrid.cpp
+++ b/src/propgrid/propgrid.cpp
@@ -355,7 +355,6 @@ void wxPropertyGrid::Init1()
m_inOnValidationFailure = false;
m_permanentValidationFailureBehavior = wxPG_VFB_DEFAULT;
m_dragStatus = 0;
- m_mouseSide = 16;
m_editorFocused = false;
// Set up default unspecified value 'colour'
@@ -5002,8 +5001,11 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y,
int splitterHit;
int splitterHitOffset;
int columnHit = state->HitTestH( x, &splitterHit, &splitterHitOffset );
- int splitterX = x - splitterHitOffset;
+ #if wxUSE_TOOLTIPS
+ wxPGProperty* prevHover = m_propHover;
+ int prevCol = m_colHover;
+ #endif
m_colHover = columnHit;
if ( m_dragStatus > 0 )
@@ -5012,6 +5014,7 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y,
x < (m_pState->GetVirtualWidth() - wxPG_DRAG_MARGIN) )
{
+ int splitterX = x - splitterHitOffset;
int newSplitterX = x - m_dragOffset;
// Splitter redraw required?
@@ -5042,10 +5045,6 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y,
int ih = m_lineHeight;
int sy = y;
- #if wxUSE_TOOLTIPS
- wxPGProperty* prevHover = m_propHover;
- unsigned char prevSide = m_mouseSide;
- #endif
int curPropHoverY = y - (y % ih);
// On which item it hovers
@@ -5064,20 +5063,13 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y,
}
#if wxUSE_TOOLTIPS
- // Store which side we are on
- m_mouseSide = 0;
- if ( columnHit == 1 )
- m_mouseSide = 2;
- else if ( columnHit == 0 )
- m_mouseSide = 1;
-
//
// If tooltips are enabled, show label or value as a tip
// in case it doesn't otherwise show in full length.
//
if ( m_windowStyle & wxPG_TOOLTIPS )
{
- if ( m_propHover != prevHover || prevSide != m_mouseSide )
+ if ( m_propHover != prevHover || prevCol != m_colHover )
{
if ( m_propHover && !m_propHover->IsCategory() )
{
@@ -5089,40 +5081,59 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y,
SetToolTip(tipString);
}
- else
+ else if ( m_colHover >= 0 && m_colHover < (int)m_pState->GetColumnCount())
{
// Show cropped value string as a tooltip
wxString tipString;
- int space = 0;
+ wxPGCell cell;
+ int item = ( m_colHover == 1 ? m_propHover->GetChoiceSelection() : -1 );
+ m_propHover->GetDisplayInfo(m_colHover, item, 0, &tipString, &cell);
+ int space = m_pState->GetColumnWidth(m_colHover);
- if ( m_mouseSide == 1 )
+ int imageWidth = 0;
+ const wxBitmap& bmp = cell.GetBitmap();
+ if ( bmp.IsOk() )
{
- tipString = m_propHover->GetLabel();
- space = splitterX-m_marginWidth-3;
- }
- else if ( m_mouseSide == 2 )
- {
- tipString = m_propHover->GetDisplayedString();
-
- space = m_width - splitterX;
- if ( m_propHover->HasFlag(wxPG_PROP_CUSTOMIMAGE) )
- space -= wxPG_CUSTOM_IMAGE_WIDTH +
- wxCC_CUSTOM_IMAGE_MARGIN1 +
- wxCC_CUSTOM_IMAGE_MARGIN2;
+ imageWidth = bmp.GetWidth();
+ int hMax = m_lineHeight - wxPG_CUSTOM_IMAGE_SPACINGY - 1;
+ if ( bmp.GetHeight() > hMax )
+ imageWidth *= (double)hMax / bmp.GetHeight();
}
- if ( space )
+ if ( m_colHover == 0 )
{
- int tw, th;
- GetTextExtent( tipString, &tw, &th, 0, 0 );
- if ( tw > space )
- SetToolTip( tipString );
+ if ( !(m_windowStyle & wxPG_HIDE_CATEGORIES) || m_propHover->GetParent() != m_pState->DoGetRoot() )
+ space -= (m_propHover->GetDepth()-1)*m_subgroup_extramargin;
}
- else
+ else if ( m_colHover == 1 && !m_propHover->IsValueUnspecified())
{
- SetToolTip(wxEmptyString);
+ wxSize imageSize = GetImageSize(m_propHover, -1);
+ if ( imageSize.x > 0 )
+ imageWidth = imageSize.x;
+ tipString = m_propHover->GetValueAsString();
+ if ( GetColumnCount() <= 2 )
+ {
+ wxString unitsString = m_propHover->GetAttribute(wxPG_ATTR_UNITS, wxEmptyString);
+ if ( !unitsString.empty() )
+ tipString = wxString::Format(wxS("%s %s"), tipString, unitsString );
+ }
}
+ space -= m_propHover->GetImageOffset(imageWidth);
+ space -= (wxPG_XBEFORETEXT + 1);
+ int tw, th;
+ const wxFont* font = NULL;
+ if ( (m_windowStyle & wxPG_BOLD_MODIFIED) && m_propHover->HasFlag(wxPG_PROP_MODIFIED) )
+ font = &m_captionFont;
+ if ( cell.GetFont().IsOk() )
+ font = &cell.GetFont();
+ GetTextExtent( tipString, &tw, &th, 0, 0, font );
+ if ( tw > space )
+ SetToolTip( tipString );
+ }
+ else
+ {
+ SetToolTip(wxEmptyString);
}
}
else
diff --git a/src/unix/snglinst.cpp b/src/unix/snglinst.cpp
index 0c8d4275ef..9c64ffbf6f 100644
--- a/src/unix/snglinst.cpp
+++ b/src/unix/snglinst.cpp
@@ -298,7 +298,7 @@ bool wxSingleInstanceCheckerImpl::Create(const wxString& name)
// message is that the previous instance of the program
// crashed), don't show it by default, i.e. unless the
// program is running with --verbose command line option.
- wxLogInfo(_("Deleted stale lock file '%s'."),
+ wxLogVerbose(_("Deleted stale lock file '%s'."),
name.c_str());
// retry now
diff --git a/tests/Makefile.in b/tests/Makefile.in
index 5cd6cc7bda..f99b4761e1 100644
--- a/tests/Makefile.in
+++ b/tests/Makefile.in
@@ -185,6 +185,7 @@ TEST_GUI_OBJECTS = \
test_gui_affinematrix.o \
test_gui_boundingbox.o \
test_gui_clippingbox.o \
+ test_gui_coords.o \
test_gui_graphmatrix.o \
test_gui_graphpath.o \
test_gui_config.o \
@@ -547,7 +548,7 @@ data:
data-images:
@mkdir -p image
- @for f in horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png; do \
+ @for f in horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png; do \
if test ! -f image/$$f -a ! -d image/$$f ; \
then x=yep ; \
else x=`find $(srcdir)/image/$$f -newer image/$$f -print` ; \
@@ -899,6 +900,9 @@ test_gui_boundingbox.o: $(srcdir)/graphics/boundingbox.cpp $(TEST_GUI_ODEP)
test_gui_clippingbox.o: $(srcdir)/graphics/clippingbox.cpp $(TEST_GUI_ODEP)
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/graphics/clippingbox.cpp
+test_gui_coords.o: $(srcdir)/graphics/coords.cpp $(TEST_GUI_ODEP)
+ $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/graphics/coords.cpp
+
test_gui_graphmatrix.o: $(srcdir)/graphics/graphmatrix.cpp $(TEST_GUI_ODEP)
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/graphics/graphmatrix.cpp
diff --git a/tests/controls/bitmapcomboboxtest.cpp b/tests/controls/bitmapcomboboxtest.cpp
index 2a011b3869..904eb6079f 100644
--- a/tests/controls/bitmapcomboboxtest.cpp
+++ b/tests/controls/bitmapcomboboxtest.cpp
@@ -24,9 +24,6 @@
#include "itemcontainertest.h"
#include "asserthelper.h"
-//Test only if we are based off of wxComboBox
-#ifndef wxGENERIC_BITMAPCOMBOBOX
-
class BitmapComboBoxTestCase : public TextEntryTestCase,
public ItemContainerTestCase,
public CppUnit::TestCase
@@ -82,9 +79,9 @@ void BitmapComboBoxTestCase::Bitmap()
wxArrayString items;
items.push_back("item 0");
items.push_back("item 1");
-
- //We need this otherwise MSVC complains as it cannot find a suitable append
- static_cast(m_combo)->Append(items);
+ // TODO: Add wxBitmapComboBoxBase::Append(wxArrayString )
+ for( unsigned int i = 0; i < items.size(); ++i )
+ m_combo->Append(items[i]);
CPPUNIT_ASSERT(!m_combo->GetItemBitmap(0).IsOk());
@@ -104,8 +101,10 @@ void BitmapComboBoxTestCase::Bitmap()
CPPUNIT_ASSERT(m_combo->GetItemBitmap(0).IsOk());
CPPUNIT_ASSERT_EQUAL(wxSize(16, 16), m_combo->GetBitmapSize());
+
+ m_combo->SetSelection( 1 );
+
+ CPPUNIT_ASSERT_EQUAL( m_combo->GetStringSelection(), "item with bitmap" );
}
-#endif //wxGENERIC_BITMAPCOMBOBOX
-
#endif //wxUSE_BITMAPCOMBOBOX
diff --git a/tests/controls/listbasetest.cpp b/tests/controls/listbasetest.cpp
index 2bee21811d..5673676e74 100644
--- a/tests/controls/listbasetest.cpp
+++ b/tests/controls/listbasetest.cpp
@@ -26,6 +26,7 @@
#include "wx/uiaction.h"
#include "wx/imaglist.h"
#include "wx/artprov.h"
+#include "wx/stopwatch.h"
void ListBaseTestCase::ColumnsOrder()
{
@@ -177,6 +178,123 @@ void ListBaseTestCase::ChangeMode()
CPPUNIT_ASSERT_EQUAL( "First", list->GetItemText(0) );
}
+#ifdef __WXGTK__
+ #define wxGTK_TIMED_YIELD(t) \
+ if ( !IsRunningUnderXVFB() ) \
+ for ( wxStopWatch sw; sw.Time() < t; ) wxYield()
+#else // !__WXGTK__
+ #define wxGTK_TIMED_YIELD(t)
+#endif // __WXGTK__
+
+void ListBaseTestCase::MultiSelect()
+{
+#if wxUSE_UIACTIONSIMULATOR
+
+#ifndef __WXMSW__
+ // FIXME: This test fails on Travis CI although works fine on
+ // development machine, no idea why though!
+ if ( IsAutomaticTest() )
+ return;
+#endif // !__WXMSW__
+
+ wxListCtrl* const list = GetList();
+
+ EventCounter focused(list, wxEVT_LIST_ITEM_FOCUSED);
+ EventCounter selected(list, wxEVT_LIST_ITEM_SELECTED);
+ EventCounter deselected(list, wxEVT_LIST_ITEM_DESELECTED);
+
+ list->InsertColumn(0, "Header");
+
+ for ( int i = 0; i < 10; ++i )
+ list->InsertItem(i, wxString::Format("Item %d", i));
+
+ wxUIActionSimulator sim;
+
+ wxRect pos;
+ list->GetItemRect(2, pos); // Choose the third item as anchor
+
+ // We move in slightly so we are not on the edge
+ wxPoint point = list->ClientToScreen(pos.GetPosition()) + wxPoint(10, 10);
+
+ sim.MouseMove(point);
+ wxYield();
+
+ sim.MouseClick(); // select the anchor
+ wxYield();
+
+ wxGTK_TIMED_YIELD(50);
+
+ list->GetItemRect(5, pos);
+ point = list->ClientToScreen(pos.GetPosition()) + wxPoint(10, 10);
+
+ sim.MouseMove(point);
+ wxYield();
+
+ sim.KeyDown(WXK_SHIFT);
+ sim.MouseClick();
+ sim.KeyUp(WXK_SHIFT);
+ wxYield();
+
+ wxGTK_TIMED_YIELD(10);
+
+ // when the first item was selected the focus changes to it, but not
+ // on subsequent clicks
+ CPPUNIT_ASSERT_EQUAL(4, list->GetSelectedItemCount()); // item 2 to 5 (inclusive) are selected
+ CPPUNIT_ASSERT_EQUAL(2, focused.GetCount()); // count the focus which was on the anchor
+ CPPUNIT_ASSERT_EQUAL(4, selected.GetCount());
+ CPPUNIT_ASSERT_EQUAL(0, deselected.GetCount());
+
+ focused.Clear();
+ selected.Clear();
+ deselected.Clear();
+
+ sim.Char(WXK_END, wxMOD_SHIFT); // extend the selection to the last item
+ wxYield();
+
+ wxGTK_TIMED_YIELD(10);
+
+ CPPUNIT_ASSERT_EQUAL(8, list->GetSelectedItemCount()); // item 2 to 9 (inclusive) are selected
+ CPPUNIT_ASSERT_EQUAL(1, focused.GetCount()); // focus is on the last item
+ CPPUNIT_ASSERT_EQUAL(4, selected.GetCount()); // only newly selected items got the event
+ CPPUNIT_ASSERT_EQUAL(0, deselected.GetCount());
+
+ focused.Clear();
+ selected.Clear();
+ deselected.Clear();
+
+ sim.Char(WXK_HOME, wxMOD_SHIFT); // select from anchor to the first item
+ wxYield();
+
+ wxGTK_TIMED_YIELD(10);
+
+ CPPUNIT_ASSERT_EQUAL(3, list->GetSelectedItemCount()); // item 0 to 2 (inclusive) are selected
+ CPPUNIT_ASSERT_EQUAL(1, focused.GetCount()); // focus is on item 0
+ CPPUNIT_ASSERT_EQUAL(2, selected.GetCount()); // events are only generated for item 0 and 1
+ CPPUNIT_ASSERT_EQUAL(7, deselected.GetCount()); // item 2 (exclusive) to 9 are deselected
+
+ focused.Clear();
+ selected.Clear();
+ deselected.Clear();
+
+ list->EnsureVisible(0);
+ wxYield();
+
+ list->GetItemRect(2, pos);
+ point = list->ClientToScreen(pos.GetPosition()) + wxPoint(10, 10);
+
+ sim.MouseMove(point);
+ wxYield();
+
+ sim.MouseClick();
+ wxYield();
+
+ CPPUNIT_ASSERT_EQUAL(1, list->GetSelectedItemCount()); // anchor is the only selected item
+ CPPUNIT_ASSERT_EQUAL(1, focused.GetCount()); // because the focus changed from item 0 to anchor
+ CPPUNIT_ASSERT_EQUAL(0, selected.GetCount()); // anchor is already in selection state
+ CPPUNIT_ASSERT_EQUAL(2, deselected.GetCount()); // items 0 and 1 are deselected
+#endif // wxUSE_UIACTIONSIMULATOR
+}
+
void ListBaseTestCase::ItemClick()
{
#if wxUSE_UIACTIONSIMULATOR
@@ -236,16 +354,9 @@ void ListBaseTestCase::ItemClick()
// when the first item was selected the focus changes to it, but not
// on subsequent clicks
-
- // FIXME: This test fail under wxGTK & wxOSX because we get 3 FOCUSED events and
- // 2 SELECTED ones instead of the one of each we expect for some
- // reason, this needs to be debugged as it may indicate a bug in the
- // generic wxListCtrl implementation.
-#ifndef _WX_GENERIC_LISTCTRL_H_
CPPUNIT_ASSERT_EQUAL(1, focused.GetCount());
CPPUNIT_ASSERT_EQUAL(1, selected.GetCount());
CPPUNIT_ASSERT_EQUAL(1, deselected.GetCount());
-#endif
CPPUNIT_ASSERT_EQUAL(1, activated.GetCount());
CPPUNIT_ASSERT_EQUAL(1, rclick.GetCount());
#endif // wxUSE_UIACTIONSIMULATOR
diff --git a/tests/controls/listbasetest.h b/tests/controls/listbasetest.h
index d5840767c9..8b8df808b7 100644
--- a/tests/controls/listbasetest.h
+++ b/tests/controls/listbasetest.h
@@ -26,6 +26,7 @@ protected:
CPPUNIT_TEST( ChangeMode ); \
WXUISIM_TEST( ItemClick ); \
WXUISIM_TEST( KeyDown ); \
+ WXUISIM_TEST( MultiSelect ); \
CPPUNIT_TEST( DeleteItems ); \
CPPUNIT_TEST( InsertItem ); \
CPPUNIT_TEST( Find ); \
@@ -40,6 +41,7 @@ protected:
void ItemRect();
void ItemText();
void ChangeMode();
+ void MultiSelect();
void ItemClick();
void KeyDown();
void DeleteItems();
diff --git a/tests/controls/listviewtest.cpp b/tests/controls/listviewtest.cpp
index 94162d3eab..1ddd6c6f33 100644
--- a/tests/controls/listviewtest.cpp
+++ b/tests/controls/listviewtest.cpp
@@ -20,6 +20,7 @@
#include "wx/listctrl.h"
#include "listbasetest.h"
+#include "testableframe.h"
class ListViewTestCase : public ListBaseTestCase, public CppUnit::TestCase
{
@@ -61,7 +62,8 @@ void ListViewTestCase::setUp()
void ListViewTestCase::tearDown()
{
- wxDELETE(m_list);
+ DeleteTestWindow(m_list);
+ m_list = NULL;
}
void ListViewTestCase::Selection()
@@ -104,6 +106,8 @@ void ListViewTestCase::Selection()
void ListViewTestCase::Focus()
{
+ EventCounter focused(m_list, wxEVT_LIST_ITEM_FOCUSED);
+
m_list->InsertColumn(0, "Column 0");
m_list->InsertItem(0, "Item 0");
@@ -111,10 +115,12 @@ void ListViewTestCase::Focus()
m_list->InsertItem(2, "Item 2");
m_list->InsertItem(3, "Item 3");
+ CPPUNIT_ASSERT_EQUAL(0, focused.GetCount());
CPPUNIT_ASSERT_EQUAL(-1, m_list->GetFocusedItem());
m_list->Focus(0);
+ CPPUNIT_ASSERT_EQUAL(1, focused.GetCount());
CPPUNIT_ASSERT_EQUAL(0, m_list->GetFocusedItem());
}
diff --git a/tests/controls/radiobuttontest.cpp b/tests/controls/radiobuttontest.cpp
index a81d6aec61..cdcc144972 100644
--- a/tests/controls/radiobuttontest.cpp
+++ b/tests/controls/radiobuttontest.cpp
@@ -27,40 +27,19 @@
#include "testableframe.h"
#include "testwindow.h"
-class RadioButtonTestCase : public CppUnit::TestCase
+class RadioButtonTestCase
{
public:
- RadioButtonTestCase() { }
-
- void setUp() wxOVERRIDE;
- void tearDown() wxOVERRIDE;
-
-private:
- CPPUNIT_TEST_SUITE( RadioButtonTestCase );
- WXUISIM_TEST( Click );
- CPPUNIT_TEST( Value );
- CPPUNIT_TEST( Group );
- CPPUNIT_TEST( Single );
- CPPUNIT_TEST_SUITE_END();
-
- void Click();
- void Value();
- void Group();
- void Single();
+ RadioButtonTestCase();
+ ~RadioButtonTestCase();
+protected:
wxRadioButton* m_radio;
wxDECLARE_NO_COPY_CLASS(RadioButtonTestCase);
};
-// register in the unnamed registry so that these tests are run by default
-CPPUNIT_TEST_SUITE_REGISTRATION( RadioButtonTestCase );
-
-// also include in its own registry so that these tests can be run alone
-CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( RadioButtonTestCase,
- "RadioButtonTestCase" );
-
-void RadioButtonTestCase::setUp()
+RadioButtonTestCase::RadioButtonTestCase()
{
m_radio = new wxRadioButton(wxTheApp->GetTopWindow(), wxID_ANY,
"wxRadioButton");
@@ -68,12 +47,12 @@ void RadioButtonTestCase::setUp()
m_radio->Refresh();
}
-void RadioButtonTestCase::tearDown()
+RadioButtonTestCase::~RadioButtonTestCase()
{
- wxDELETE(m_radio);
+ delete m_radio;
}
-void RadioButtonTestCase::Click()
+TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Click", "[radiobutton]")
{
// OS X doesn't support selecting a single radio button
#if wxUSE_UIACTIONSIMULATOR && !defined(__WXOSX__)
@@ -87,87 +66,115 @@ void RadioButtonTestCase::Click()
wxYield();
- CPPUNIT_ASSERT_EQUAL( 1, selected.GetCount() );
+ CHECK(selected.GetCount() == 1);
#endif
}
-void RadioButtonTestCase::Value()
+TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Value", "[radiobutton]")
{
#ifndef __WXGTK__
EventCounter selected(m_radio, wxEVT_RADIOBUTTON);
m_radio->SetValue(true);
- CPPUNIT_ASSERT(m_radio->GetValue());
+ CHECK(m_radio->GetValue());
m_radio->SetValue(false);
- CPPUNIT_ASSERT(!m_radio->GetValue());
+ CHECK(!m_radio->GetValue());
- CPPUNIT_ASSERT_EQUAL(0, selected.GetCount());
+ CHECK(selected.GetCount() == 0);
#endif
}
-void RadioButtonTestCase::Group()
+TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Group", "[radiobutton]")
{
wxWindow* const parent = wxTheApp->GetTopWindow();
// Create two different radio groups.
- wxRadioButton* g1radio0 = new wxRadioButton(parent, wxID_ANY, "radio 1.0",
+ wxScopedPtr g1radio0(new wxRadioButton(parent, wxID_ANY, "radio 1.0",
wxDefaultPosition, wxDefaultSize,
- wxRB_GROUP);
+ wxRB_GROUP));
- wxRadioButton* g1radio1 = new wxRadioButton(parent, wxID_ANY, "radio 1.1");
+ wxScopedPtr g1radio1(new wxRadioButton(parent, wxID_ANY, "radio 1.1"));
- wxRadioButton* g2radio0 = new wxRadioButton(parent, wxID_ANY, "radio 2.0",
+ wxScopedPtr g2radio0(new wxRadioButton(parent, wxID_ANY, "radio 2.0",
wxDefaultPosition, wxDefaultSize,
- wxRB_GROUP);
+ wxRB_GROUP));
- wxRadioButton* g2radio1 = new wxRadioButton(parent, wxID_ANY, "radio 2.1");
+ wxScopedPtr g2radio1(new wxRadioButton(parent, wxID_ANY, "radio 2.1"));
// Check that having another control between radio buttons doesn't break
// grouping.
- wxStaticText* text = new wxStaticText(parent, wxID_ANY, "Label");
- wxRadioButton* g2radio2 = new wxRadioButton(parent, wxID_ANY, "radio 2.1");
+ wxScopedPtr text(new wxStaticText(parent, wxID_ANY, "Label"));
+ wxScopedPtr g2radio2(new wxRadioButton(parent, wxID_ANY, "radio 2.2"));
g1radio0->SetValue(true);
g2radio0->SetValue(true);
- CPPUNIT_ASSERT(g1radio0->GetValue());
- CPPUNIT_ASSERT(!g1radio1->GetValue());
- CPPUNIT_ASSERT(g2radio0->GetValue());
- CPPUNIT_ASSERT(!g2radio1->GetValue());
+ CHECK(g1radio0->GetValue());
+ CHECK(!g1radio1->GetValue());
+ CHECK(g2radio0->GetValue());
+ CHECK(!g2radio1->GetValue());
g1radio1->SetValue(true);
g2radio1->SetValue(true);
- CPPUNIT_ASSERT(!g1radio0->GetValue());
- CPPUNIT_ASSERT(g1radio1->GetValue());
- CPPUNIT_ASSERT(!g2radio0->GetValue());
- CPPUNIT_ASSERT(g2radio1->GetValue());
+ CHECK(!g1radio0->GetValue());
+ CHECK(g1radio1->GetValue());
+ CHECK(!g2radio0->GetValue());
+ CHECK(g2radio1->GetValue());
g2radio2->SetValue(true);
- CPPUNIT_ASSERT(!g2radio0->GetValue());
- CPPUNIT_ASSERT(!g2radio1->GetValue());
- CPPUNIT_ASSERT(g2radio2->GetValue());
+ CHECK(!g2radio0->GetValue());
+ CHECK(!g2radio1->GetValue());
+ CHECK(g2radio2->GetValue());
g1radio0->SetValue(true);
g2radio0->SetValue(true);
- CPPUNIT_ASSERT(g1radio0->GetValue());
- CPPUNIT_ASSERT(!g1radio1->GetValue());
- CPPUNIT_ASSERT(g2radio0->GetValue());
- CPPUNIT_ASSERT(!g2radio1->GetValue());
+ CHECK(g1radio0->GetValue());
+ CHECK(!g1radio1->GetValue());
+ CHECK(g2radio0->GetValue());
+ CHECK(!g2radio1->GetValue());
- wxDELETE(g1radio0);
- wxDELETE(g1radio1);
- wxDELETE(g2radio0);
- wxDELETE(g2radio1);
- wxDELETE(g2radio2);
- wxDELETE(text);
+
+ // Check that group navigation functions behave as expected.
+
+ // GetFirstInGroup()
+ CHECK_SAME_WINDOW(g1radio0->GetFirstInGroup(), g1radio0);
+ CHECK_SAME_WINDOW(g1radio1->GetFirstInGroup(), g1radio0);
+
+ CHECK_SAME_WINDOW(g2radio0->GetFirstInGroup(), g2radio0);
+ CHECK_SAME_WINDOW(g2radio1->GetFirstInGroup(), g2radio0);
+ CHECK_SAME_WINDOW(g2radio2->GetFirstInGroup(), g2radio0);
+
+ // GetLastInGroup()
+ CHECK_SAME_WINDOW(g1radio0->GetLastInGroup(), g1radio1);
+ CHECK_SAME_WINDOW(g1radio1->GetLastInGroup(), g1radio1);
+
+ CHECK_SAME_WINDOW(g2radio0->GetLastInGroup(), g2radio2);
+ CHECK_SAME_WINDOW(g2radio1->GetLastInGroup(), g2radio2);
+ CHECK_SAME_WINDOW(g2radio2->GetLastInGroup(), g2radio2);
+
+ // GetNextInGroup()
+ CHECK_SAME_WINDOW(g1radio0->GetNextInGroup(), g1radio1);
+ CHECK_SAME_WINDOW(g1radio1->GetNextInGroup(), NULL);
+
+ CHECK_SAME_WINDOW(g2radio0->GetNextInGroup(), g2radio1);
+ CHECK_SAME_WINDOW(g2radio1->GetNextInGroup(), g2radio2);
+ CHECK_SAME_WINDOW(g2radio2->GetNextInGroup(), NULL);
+
+ // GetPreviousInGroup()
+ CHECK_SAME_WINDOW(g1radio0->GetPreviousInGroup(), NULL);
+ CHECK_SAME_WINDOW(g1radio1->GetPreviousInGroup(), g1radio0);
+
+ CHECK_SAME_WINDOW(g2radio0->GetPreviousInGroup(), NULL);
+ CHECK_SAME_WINDOW(g2radio1->GetPreviousInGroup(), g2radio0);
+ CHECK_SAME_WINDOW(g2radio2->GetPreviousInGroup(), g2radio1);
}
-void RadioButtonTestCase::Single()
+TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Single", "[radiobutton]")
{
//Create a group of 2 buttons, having second button selected
wxScopedPtr gradio0(new wxRadioButton(wxTheApp->GetTopWindow(),
@@ -197,9 +204,15 @@ void RadioButtonTestCase::Single()
CHECK(gradio1->GetValue());
CHECK(ngradio->GetValue());
+
+ // Also check that navigation works as expected with "single" buttons.
+ CHECK_SAME_WINDOW(sradio->GetFirstInGroup(), sradio);
+ CHECK_SAME_WINDOW(sradio->GetLastInGroup(), sradio);
+ CHECK_SAME_WINDOW(sradio->GetPreviousInGroup(), NULL);
+ CHECK_SAME_WINDOW(sradio->GetNextInGroup(), NULL);
}
-TEST_CASE("wxRadioButton::Focus", "[radiobutton][focus]")
+TEST_CASE("RadioButton::Focus", "[radiobutton][focus]")
{
// Create a container panel just to be able to destroy all the windows
// created here at once by simply destroying it.
diff --git a/tests/controls/slidertest.cpp b/tests/controls/slidertest.cpp
index 9ecc97327c..aac59a2bca 100644
--- a/tests/controls/slidertest.cpp
+++ b/tests/controls/slidertest.cpp
@@ -35,6 +35,7 @@ private:
#ifndef __WXOSX__
WXUISIM_TEST( PageUpDown );
WXUISIM_TEST( LineUpDown );
+ WXUISIM_TEST( EvtSlider );
WXUISIM_TEST( LinePageSize );
#endif
CPPUNIT_TEST( Value );
@@ -47,6 +48,7 @@ private:
void PageUpDown();
void LineUpDown();
+ void EvtSlider();
void LinePageSize();
void Value();
void Range();
@@ -125,6 +127,24 @@ void SliderTestCase::LineUpDown()
#endif
}
+void SliderTestCase::EvtSlider()
+{
+#if wxUSE_UIACTIONSIMULATOR
+ EventCounter slider(m_slider, wxEVT_SLIDER);
+
+ wxUIActionSimulator sim;
+ wxYield();
+ m_slider->SetFocus();
+
+ sim.Char(WXK_UP);
+ sim.Char(WXK_DOWN);
+
+ wxYield();
+
+ CPPUNIT_ASSERT_EQUAL(2, slider.GetCount());
+#endif
+}
+
void SliderTestCase::LinePageSize()
{
#if wxUSE_UIACTIONSIMULATOR
diff --git a/tests/controls/windowtest.cpp b/tests/controls/windowtest.cpp
index 372317e67b..cfcc4a0f6d 100644
--- a/tests/controls/windowtest.cpp
+++ b/tests/controls/windowtest.cpp
@@ -136,10 +136,22 @@ TEST_CASE_METHOD(WindowTestCase, "Window::Mouse", "[window]")
CHECK(m_window->GetCursor().IsOk());
#if wxUSE_CARET
- //A plain window doesn't have a caret
CHECK(!m_window->GetCaret());
- wxCaret* caret = new wxCaret(m_window, 16, 16);
+ wxCaret* caret;
+
+ // Try creating the caret in two different, but normally equivalent, ways.
+ SECTION("Caret 1-step")
+ {
+ caret = new wxCaret(m_window, 16, 16);
+ }
+
+ SECTION("Caret 2-step")
+ {
+ caret = new wxCaret();
+ caret->Create(m_window, 16, 16);
+ }
+
m_window->SetCaret(caret);
CHECK(m_window->GetCaret()->IsOk());
diff --git a/tests/graphics/coords.cpp b/tests/graphics/coords.cpp
new file mode 100644
index 0000000000..061900cf99
--- /dev/null
+++ b/tests/graphics/coords.cpp
@@ -0,0 +1,1430 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name: tests/graphics/coords.cpp
+// Purpose: Coordinates conversion unit tests
+// Author: Artur Wieczorek
+// Created: 2020-09-25
+// Copyright: (c) 2020 wxWidgets development team
+///////////////////////////////////////////////////////////////////////////////
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include "testprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#include "wx/bitmap.h"
+#include "wx/dcgraph.h"
+#include "wx/dcmemory.h"
+
+
+// ----------------------------------------------------------------------------
+// test class
+// ----------------------------------------------------------------------------
+
+static const wxSize s_dcSize(100, 100);
+static const wxPoint s_posDev(24, 57);
+static const wxSize s_dimDev(40, 15);
+
+// ====================
+// wxDC / wxGCDC tests
+// ====================
+
+class CoordinatesDCTestCaseBase
+{
+public:
+ CoordinatesDCTestCaseBase()
+ {
+ m_bmp.Create(s_dcSize);
+ m_dc = NULL;
+ }
+
+ virtual ~CoordinatesDCTestCaseBase()
+ {
+ m_bmp = wxNullBitmap;
+ }
+
+protected:
+ wxBitmap m_bmp;
+ wxDC* m_dc;
+};
+
+// ===========
+// wxDC tests
+// ===========
+
+class CoordinatesDCTestCase : public CoordinatesDCTestCaseBase
+{
+public:
+ CoordinatesDCTestCase()
+ {
+ m_mdc.SelectObject(m_bmp);
+ m_dc = &m_mdc;
+ }
+
+ virtual ~CoordinatesDCTestCase()
+ {
+ m_mdc.SelectObject(wxNullBitmap);
+ }
+
+protected:
+ wxMemoryDC m_mdc;
+};
+
+#if wxUSE_GRAPHICS_CONTEXT
+// =============
+// wxGCDC tests
+// =============
+
+class CoordinatesGCDCTestCase : public CoordinatesDCTestCase
+{
+public:
+ CoordinatesGCDCTestCase()
+ {
+ m_gcdc = new wxGCDC(m_mdc);
+
+ wxGraphicsContext* ctx = m_gcdc->GetGraphicsContext();
+ ctx->SetAntialiasMode(wxANTIALIAS_NONE);
+ ctx->DisableOffset();
+
+ m_dc = m_gcdc;
+ }
+
+ virtual ~CoordinatesGCDCTestCase()
+ {
+ delete m_gcdc;
+ }
+
+protected:
+ wxGCDC* m_gcdc;
+};
+#endif // wxUSE_GRAPHICS_CONTEXT
+
+// ===== Implementation =====
+
+static void InitialState(wxDC* dc)
+{
+ // Check initial state
+
+ wxPoint origin = dc->GetDeviceOrigin();
+ CHECK(origin.x == 0);
+ CHECK(origin.y == 0);
+
+ origin = dc->GetLogicalOrigin();
+ CHECK(origin.x == 0);
+ CHECK(origin.y == 0);
+
+ double sx, sy;
+ dc->GetUserScale(&sx, &sy);
+ CHECK(sx == 1.0);
+ CHECK(sy == 1.0);
+
+ dc->GetLogicalScale(&sx, &sy);
+ CHECK(sx == 1.0);
+ CHECK(sy == 1.0);
+
+#if wxUSE_DC_TRANSFORM_MATRIX
+ if ( dc->CanUseTransformMatrix() )
+ {
+ wxAffineMatrix2D m = dc->GetTransformMatrix();
+ CHECK(m.IsIdentity() == true);
+ }
+#endif // wxUSE_DC_TRANSFORM_MATRIX
+}
+
+static void NoTransform(wxDC *dc)
+{
+ // No transformations
+
+ // First convert from device to logical coordinates
+ wxPoint posLog;
+ posLog.x = dc->DeviceToLogicalX(s_posDev.x);
+ posLog.y = dc->DeviceToLogicalY(s_posDev.y);
+ CHECK(posLog.x == s_posDev.x);
+ CHECK(posLog.y == s_posDev.y);
+
+ wxSize dimLog;
+ dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x);
+ dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y);
+ CHECK(dimLog.x == s_dimDev.x);
+ CHECK(dimLog.y == s_dimDev.y);
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev.x = dc->LogicalToDeviceX(posLog.x);
+ posDev.y = dc->LogicalToDeviceY(posLog.y);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev.x = dc->LogicalToDeviceXRel(dimLog.x);
+ dimDev.y = dc->LogicalToDeviceYRel(dimLog.y);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+}
+
+static void NoTransformEx(wxDC * dc)
+{
+ // No transformations
+
+ // First convert from device to logical coordinates
+ wxPoint posLog;
+ posLog = dc->DeviceToLogical(s_posDev);
+ CHECK(posLog.x == s_posDev.x);
+ CHECK(posLog.y == s_posDev.y);
+
+ wxSize dimLog;
+ dimLog = dc->DeviceToLogicalRel(s_dimDev);
+ CHECK(dimLog.x == s_dimDev.x);
+ CHECK(dimLog.y == s_dimDev.y);
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev = dc->LogicalToDevice(posLog);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev = dc->LogicalToDeviceRel(dimLog);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+}
+
+static void DeviceOriginChanged(wxDC* dc)
+{
+ // Only device origin is changed
+ const wxCoord dx = 10;
+ const wxCoord dy = 15;
+ dc->SetDeviceOrigin(dx, dy);
+
+ // First convert from device to logical coordinates
+ wxPoint posLog;
+ posLog.x = dc->DeviceToLogicalX(s_posDev.x);
+ posLog.y = dc->DeviceToLogicalY(s_posDev.y);
+ CHECK(posLog.x == s_posDev.x - dx);
+ CHECK(posLog.y == s_posDev.y - dy);
+
+ wxSize dimLog;
+ dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x);
+ dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y);
+ CHECK(dimLog.x == s_dimDev.x);
+ CHECK(dimLog.y == s_dimDev.y);
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev.x = dc->LogicalToDeviceX(posLog.x);
+ posDev.y = dc->LogicalToDeviceY(posLog.y);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev.x = dc->LogicalToDeviceXRel(dimLog.x);
+ dimDev.y = dc->LogicalToDeviceYRel(dimLog.y);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+}
+
+static void DeviceOriginChangedEx(wxDC * dc)
+{
+ // Only device origin is changed
+ const wxCoord dx = 10;
+ const wxCoord dy = 15;
+ dc->SetDeviceOrigin(dx, dy);
+
+ // First convert from device to logical coordinates
+ wxPoint posLog;
+ posLog = dc->DeviceToLogical(s_posDev);
+ CHECK(posLog.x == s_posDev.x - dx);
+ CHECK(posLog.y == s_posDev.y - dy);
+
+ wxSize dimLog;
+ dimLog = dc->DeviceToLogicalRel(s_dimDev);
+ CHECK(dimLog.x == s_dimDev.x);
+ CHECK(dimLog.y == s_dimDev.y);
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev = dc->LogicalToDevice(posLog);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev = dc->LogicalToDeviceRel(dimLog);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+}
+
+static void LogicalOriginChanged(wxDC* dc)
+{
+ // Only logical origin is changed
+ const wxCoord dx = -15;
+ const wxCoord dy = -20;
+ dc->SetLogicalOrigin(dx, dy);
+
+ // First convert from device to logical coordinates
+ wxPoint posLog;
+ posLog.x = dc->DeviceToLogicalX(s_posDev.x);
+ posLog.y = dc->DeviceToLogicalY(s_posDev.y);
+ CHECK(posLog.x == s_posDev.x + dx);
+ CHECK(posLog.y == s_posDev.y + dy);
+
+ wxSize dimLog;
+ dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x);
+ dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y);
+ CHECK(dimLog.x == s_dimDev.x);
+ CHECK(dimLog.y == s_dimDev.y);
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev.x = dc->LogicalToDeviceX(posLog.x);
+ posDev.y = dc->LogicalToDeviceY(posLog.y);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev.x = dc->LogicalToDeviceXRel(dimLog.x);
+ dimDev.y = dc->LogicalToDeviceYRel(dimLog.y);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+}
+
+static void LogicalOriginChangedEx(wxDC * dc)
+{
+ // Only logical origin is changed
+ const wxCoord dx = -15;
+ const wxCoord dy = -20;
+ dc->SetLogicalOrigin(dx, dy);
+
+ // First convert from device to logical coordinates
+ wxPoint posLog;
+ posLog = dc->DeviceToLogical(s_posDev);
+ CHECK(posLog.x == s_posDev.x + dx);
+ CHECK(posLog.y == s_posDev.y + dy);
+
+ wxSize dimLog;
+ dimLog = dc->DeviceToLogicalRel(s_dimDev);
+ CHECK(dimLog.x == s_dimDev.x);
+ CHECK(dimLog.y == s_dimDev.y);
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev = dc->LogicalToDevice(posLog);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev = dc->LogicalToDeviceRel(dimLog);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+}
+
+static void UserScaleChanged(wxDC* dc)
+{
+ // Only user scale is changed
+ const double sx = 2.0;
+ const double sy = 3.0;
+ dc->SetUserScale(sx, sy);
+
+ // First convert from device to logical coordinates
+ wxPoint posLog;
+ posLog.x = dc->DeviceToLogicalX(s_posDev.x);
+ posLog.y = dc->DeviceToLogicalY(s_posDev.y);
+ CHECK(posLog.x == wxRound(s_posDev.x / sx));
+ CHECK(posLog.y == wxRound(s_posDev.y / sy));
+
+ wxSize dimLog;
+ dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x);
+ dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y);
+ CHECK(dimLog.x == wxRound(s_dimDev.x / sx));
+ CHECK(dimLog.y == wxRound(s_dimDev.y / sy));
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev.x = dc->LogicalToDeviceX(posLog.x);
+ posDev.y = dc->LogicalToDeviceY(posLog.y);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev.x = dc->LogicalToDeviceXRel(dimLog.x);
+ dimDev.y = dc->LogicalToDeviceYRel(dimLog.y);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+}
+
+static void UserScaleChangedEx(wxDC * dc)
+{
+ // Only user scale is changed
+ const double sx = 2.0;
+ const double sy = 3.0;
+ dc->SetUserScale(sx, sy);
+
+ // First convert from device to logical coordinates
+ wxPoint posLog;
+ posLog = dc->DeviceToLogical(s_posDev);
+ CHECK(posLog.x == wxRound(s_posDev.x / sx));
+ CHECK(posLog.y == wxRound(s_posDev.y / sy));
+
+ wxSize dimLog;
+ dimLog = dc->DeviceToLogicalRel(s_dimDev);
+ CHECK(dimLog.x == wxRound(s_dimDev.x / sx));
+ CHECK(dimLog.y == wxRound(s_dimDev.y / sy));
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev = dc->LogicalToDevice(posLog);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev = dc->LogicalToDeviceRel(dimLog);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+}
+
+static void LogicalScaleChanged(wxDC* dc)
+{
+ // Only logical scale is changed
+ const double sx = 2.0;
+ const double sy = 3.0;
+ dc->SetLogicalScale(sx, sy);
+
+ // First convert from device to logical coordinates
+ wxPoint posLog;
+ posLog.x = dc->DeviceToLogicalX(s_posDev.x);
+ posLog.y = dc->DeviceToLogicalY(s_posDev.y);
+ CHECK(posLog.x == wxRound(s_posDev.x / sx));
+ CHECK(posLog.y == wxRound(s_posDev.y / sy));
+
+ wxSize dimLog;
+ dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x);
+ dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y);
+ CHECK(dimLog.x == wxRound(s_dimDev.x / sx));
+ CHECK(dimLog.y == wxRound(s_dimDev.y / sy));
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev.x = dc->LogicalToDeviceX(posLog.x);
+ posDev.y = dc->LogicalToDeviceY(posLog.y);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev.x = dc->LogicalToDeviceXRel(dimLog.x);
+ dimDev.y = dc->LogicalToDeviceYRel(dimLog.y);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+}
+
+static void LogicalScaleChangedEx(wxDC * dc)
+{
+ // Only logical scale is changed
+ const double sx = 2.0;
+ const double sy = 3.0;
+ dc->SetLogicalScale(sx, sy);
+
+ // First convert from device to logical coordinates
+ wxPoint posLog;
+ posLog = dc->DeviceToLogical(s_posDev);
+ CHECK(posLog.x == wxRound(s_posDev.x / sx));
+ CHECK(posLog.y == wxRound(s_posDev.y / sy));
+
+ wxSize dimLog;
+ dimLog = dc->DeviceToLogicalRel(s_dimDev);
+ CHECK(dimLog.x == wxRound(s_dimDev.x / sx));
+ CHECK(dimLog.y == wxRound(s_dimDev.y / sy));
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev = dc->LogicalToDevice(posLog);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev = dc->LogicalToDeviceRel(dimLog);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+}
+
+static void TransformedStd(wxDC* dc)
+{
+ // Apply all standardd transformations
+ dc->SetDeviceOrigin(10, 15);
+ dc->SetUserScale(0.5, 2.0);
+ dc->SetLogicalScale(4.0, 1.5);
+ dc->SetLogicalOrigin(-15, -20);
+
+ // First convert from device to logical coordinates
+ wxPoint posLog;
+ posLog.x = dc->DeviceToLogicalX(s_posDev.x);
+ posLog.y = dc->DeviceToLogicalY(s_posDev.y);
+ CHECK(posLog.x == -8);
+ CHECK(posLog.y == -6);
+
+ wxSize dimLog;
+ dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x);
+ dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y);
+ CHECK(dimLog.x == 20);
+ CHECK(dimLog.y == 5);
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev.x = dc->LogicalToDeviceX(posLog.x);
+ posDev.y = dc->LogicalToDeviceY(posLog.y);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev.x = dc->LogicalToDeviceXRel(dimLog.x);
+ dimDev.y = dc->LogicalToDeviceYRel(dimLog.y);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+}
+
+static void TransformedStdEx(wxDC * dc)
+{
+ // Apply all standardd transformations
+ dc->SetDeviceOrigin(10, 15);
+ dc->SetUserScale(0.5, 2.0);
+ dc->SetLogicalScale(4.0, 1.5);
+ dc->SetLogicalOrigin(-15, -20);
+
+ // First convert from device to logical coordinates
+ wxPoint posLog;
+ posLog = dc->DeviceToLogical(s_posDev);
+ CHECK(posLog.x == -8);
+ CHECK(posLog.y == -6);
+
+ wxSize dimLog;
+ dimLog = dc->DeviceToLogicalRel(s_dimDev);
+ CHECK(dimLog.x == 20);
+ CHECK(dimLog.y == 5);
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev = dc->LogicalToDevice(posLog);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev = dc->LogicalToDeviceRel(dimLog);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+}
+
+static void TransformedWithMatrix(wxDC* dc)
+{
+ // Apply transformation matrix only
+#if wxUSE_DC_TRANSFORM_MATRIX
+ if ( dc->CanUseTransformMatrix() )
+ {
+ // Apply translation and scaling only
+ wxAffineMatrix2D m = dc->GetTransformMatrix();
+ m.Translate(10, 15);
+ m.Scale(2.0, 3.0);
+ dc->SetTransformMatrix(m);
+
+ // First convert from device to logical coordinates
+ // Results should be nagative because legacy functions
+ // don't take affine transformation into account.
+ m.Invert();
+ wxPoint2DDouble posLogRef = m.TransformPoint(wxPoint2DDouble(s_posDev));
+ wxPoint posLog;
+ posLog.x = dc->DeviceToLogicalX(s_posDev.x);
+ posLog.y = dc->DeviceToLogicalY(s_posDev.y);
+ CHECK_FALSE(posLog.x == wxRound(posLogRef.m_x));
+ CHECK_FALSE(posLog.y == wxRound(posLogRef.m_y));
+ CHECK(posLog.x == s_posDev.x);
+ CHECK(posLog.y == s_posDev.y);
+
+ wxPoint2DDouble dimLogRef = m.TransformDistance(wxPoint2DDouble(s_dimDev.x, s_dimDev.y));
+ wxSize dimLog;
+ dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x);
+ dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y);
+ CHECK_FALSE(dimLog.x == wxRound(dimLogRef.m_x));
+ CHECK_FALSE(dimLog.y == wxRound(dimLogRef.m_y));
+ CHECK(dimLog.x == s_dimDev.x);
+ CHECK(dimLog.y == s_dimDev.y);
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev.x = dc->LogicalToDeviceX(posLog.x);
+ posDev.y = dc->LogicalToDeviceY(posLog.y);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev.x = dc->LogicalToDeviceXRel(dimLog.x);
+ dimDev.y = dc->LogicalToDeviceYRel(dimLog.y);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+ }
+#endif // wxUSE_DC_TRANSFORM_MATRIX
+}
+
+static void TransformedWithMatrixEx(wxDC * dc)
+{
+ // Apply transformation matrix only
+#if wxUSE_DC_TRANSFORM_MATRIX
+ if ( dc->CanUseTransformMatrix() )
+ {
+ // Apply translation and scaling only
+ wxAffineMatrix2D m = dc->GetTransformMatrix();
+ m.Translate(10, 15);
+ m.Scale(2.0, 3.0);
+ dc->SetTransformMatrix(m);
+
+ // First convert from device to logical coordinates
+ m.Invert();
+ wxPoint2DDouble posLogRef = m.TransformPoint(wxPoint2DDouble(s_posDev));
+ wxPoint posLog;
+ posLog = dc->DeviceToLogical(s_posDev);
+ CHECK(posLog.x == wxRound(posLogRef.m_x));
+ CHECK(posLog.y == wxRound(posLogRef.m_y));
+
+ wxPoint2DDouble dimLogRef = m.TransformDistance(wxPoint2DDouble(s_dimDev.x, s_dimDev.y));
+ wxSize dimLog;
+ dimLog = dc->DeviceToLogicalRel(s_dimDev);
+ CHECK(dimLog.x == wxRound(dimLogRef.m_x));
+ CHECK(dimLog.y == wxRound(dimLogRef.m_y));
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev = dc->LogicalToDevice(posLog);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev = dc->LogicalToDeviceRel(dimLog);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+ }
+#endif // wxUSE_DC_TRANSFORM_MATRIX
+}
+
+static void TransformedWithMatrixAndStd(wxDC* dc)
+{
+ // Apply combination of standard and matrix transformations
+#if wxUSE_DC_TRANSFORM_MATRIX
+ if ( dc->CanUseTransformMatrix() )
+ {
+ dc->SetDeviceOrigin(10, 15);
+
+ dc->SetUserScale(0.5, 1.5);
+ dc->SetLogicalScale(4.0, 2.0);
+ dc->SetLogicalOrigin(-15, -20);
+
+ wxAffineMatrix2D m = dc->GetTransformMatrix();
+ m.Translate(10, 18);
+ m.Scale(2.0, 0.5);
+ dc->SetTransformMatrix(m);
+
+ // First convert from device to logical coordinates
+ // Results should be nagative because legacy functions
+ // don't take affine transformation into account.
+ wxAffineMatrix2D m1;
+ m1.Translate(10 - (-15) * (0.5 * 4.0), 15 - (-20) * (1.5 * 2.0));
+ m1.Scale(0.5 * 4.0, 1.5 * 2.0);
+ m1.Concat(m);
+ m1.Invert();
+
+ wxPoint2DDouble posLogRef = m1.TransformPoint(wxPoint2DDouble(s_posDev));
+ wxPoint posLog;
+ posLog.x = dc->DeviceToLogicalX(s_posDev.x);
+ posLog.y = dc->DeviceToLogicalY(s_posDev.y);
+ CHECK_FALSE(posLog.x == wxRound(posLogRef.m_x));
+ CHECK_FALSE(posLog.y == wxRound(posLogRef.m_y));
+
+ wxPoint2DDouble dimLogRef = m1.TransformDistance(wxPoint2DDouble(s_dimDev.x, s_dimDev.y));
+ wxSize dimLog;
+ dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x);
+ dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y);
+ CHECK_FALSE(dimLog.x == wxRound(dimLogRef.m_x));
+ CHECK_FALSE(dimLog.y == wxRound(dimLogRef.m_y));
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev.x = dc->LogicalToDeviceX(posLog.x);
+ posDev.y = dc->LogicalToDeviceY(posLog.y);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev.x = dc->LogicalToDeviceXRel(dimLog.x);
+ dimDev.y = dc->LogicalToDeviceYRel(dimLog.y);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+ }
+#endif // wxUSE_DC_TRANSFORM_MATRIX
+}
+
+static void TransformedWithMatrixAndStdEx(wxDC * dc)
+{
+ // Apply combination of standard and matrix transformations
+#if wxUSE_DC_TRANSFORM_MATRIX
+ if ( dc->CanUseTransformMatrix() )
+ {
+ dc->SetDeviceOrigin(10, 15);
+
+ dc->SetUserScale(0.5, 1.5);
+ dc->SetLogicalScale(4.0, 2.0);
+ dc->SetLogicalOrigin(-15, -20);
+
+ wxAffineMatrix2D m = dc->GetTransformMatrix();
+ m.Translate(10, 18);
+ m.Scale(2.0, 0.5);
+ dc->SetTransformMatrix(m);
+
+ // First convert from device to logical coordinates
+ wxAffineMatrix2D m1;
+ m1.Translate(10 - (-15) * (0.5 * 4.0), 15 - (-20) * (1.5 * 2.0));
+ m1.Scale(0.5 * 4.0, 1.5 * 2.0);
+ m1.Concat(m);
+ m1.Invert();
+
+ wxPoint2DDouble posLogRef = m1.TransformPoint(wxPoint2DDouble(s_posDev));
+ wxPoint posLog;
+ posLog = dc->DeviceToLogical(s_posDev);
+ CHECK(posLog.x == wxRound(posLogRef.m_x));
+ CHECK(posLog.y == wxRound(posLogRef.m_y));
+
+ wxPoint2DDouble dimLogRef = m1.TransformDistance(wxPoint2DDouble(s_dimDev.x, s_dimDev.y));
+ wxSize dimLog;
+ dimLog = dc->DeviceToLogicalRel(s_dimDev);
+ CHECK(dimLog.x == wxRound(dimLogRef.m_x));
+ CHECK(dimLog.y == wxRound(dimLogRef.m_y));
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev = dc->LogicalToDevice(posLog);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev = dc->LogicalToDeviceRel(dimLog);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+ }
+#endif // wxUSE_DC_TRANSFORM_MATRIX
+}
+
+static void RotatedWithMatrix(wxDC* dc)
+{
+ // Apply matrix transformations with rotation component
+#if wxUSE_DC_TRANSFORM_MATRIX
+ if ( dc->CanUseTransformMatrix() )
+ {
+ wxAffineMatrix2D m = dc->GetTransformMatrix();
+ m.Rotate(6 * M_PI / 180.0);
+ m.Translate(10, 15);
+ m.Scale(2.0, 3.0);
+ dc->SetTransformMatrix(m);
+
+ // First convert from device to logical coordinates
+ // Results should be nagative because legacy functions
+ // don't take affine transformation into account.
+ m.Invert();
+ wxPoint2DDouble posLogRef = m.TransformPoint(wxPoint2DDouble(s_posDev));
+ wxPoint posLog;
+ posLog.x = dc->DeviceToLogicalX(s_posDev.x);
+ posLog.y = dc->DeviceToLogicalY(s_posDev.y);
+ CHECK_FALSE(posLog.x == wxRound(posLogRef.m_x));
+ CHECK_FALSE(posLog.y == wxRound(posLogRef.m_y));
+ CHECK(posLog.x == s_posDev.x);
+ CHECK(posLog.y == s_posDev.y);
+
+ wxPoint2DDouble dimLogRef = m.TransformDistance(wxPoint2DDouble(s_dimDev.x, s_dimDev.y));
+ wxSize dimLog;
+ dimLog.x = dc->DeviceToLogicalXRel(s_dimDev.x);
+ dimLog.y = dc->DeviceToLogicalYRel(s_dimDev.y);
+ CHECK_FALSE(dimLog.x == wxRound(dimLogRef.m_x));
+ CHECK_FALSE(dimLog.y == wxRound(dimLogRef.m_y));
+ CHECK(dimLog.x == s_dimDev.x);
+ CHECK(dimLog.y == s_dimDev.y);
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev.x = dc->LogicalToDeviceX(posLog.x);
+ posDev.y = dc->LogicalToDeviceY(posLog.y);
+ CHECK(posDev.x == s_posDev.x);
+ CHECK(posDev.y == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev.x = dc->LogicalToDeviceXRel(dimLog.x);
+ dimDev.y = dc->LogicalToDeviceYRel(dimLog.y);
+ CHECK(dimDev.x == s_dimDev.x);
+ CHECK(dimDev.y == s_dimDev.y);
+ }
+#endif // wxUSE_DC_TRANSFORM_MATRIX
+}
+
+static void RotatedWithMatrixEx(wxDC * dc)
+{
+ // Apply matrix transformations with rotation component
+#if wxUSE_DC_TRANSFORM_MATRIX
+ if ( dc->CanUseTransformMatrix() )
+ {
+ wxAffineMatrix2D m = dc->GetTransformMatrix();
+ m.Rotate(6 * M_PI / 180.0);
+ m.Translate(10, 15);
+ m.Scale(2.0, 3.0);
+ dc->SetTransformMatrix(m);
+
+ // First convert from device to logical coordinates
+ m.Invert();
+ wxPoint2DDouble posLogRef = m.TransformPoint(wxPoint2DDouble(s_posDev));
+ wxPoint posLog;
+ posLog = dc->DeviceToLogical(s_posDev);
+ CHECK(posLog.x == wxRound(posLogRef.m_x));
+ CHECK(posLog.y == wxRound(posLogRef.m_y));
+
+ wxPoint2DDouble dimLogRef = m.TransformDistance(wxPoint2DDouble(s_dimDev.x, s_dimDev.y));
+ wxSize dimLog;
+ dimLog = dc->DeviceToLogicalRel(s_dimDev);
+ CHECK(dimLog.x == wxRound(dimLogRef.m_x));
+ CHECK(dimLog.y == wxRound(dimLogRef.m_y));
+
+ // And next back from logical to device coordinates
+ wxPoint posDev;
+ posDev = dc->LogicalToDevice(posLog);
+ CHECK(Approx(posDev.x).margin(1) == s_posDev.x);
+ CHECK(Approx(posDev.y).margin(1) == s_posDev.y);
+
+ wxSize dimDev;
+ dimDev = dc->LogicalToDeviceRel(dimLog);
+ CHECK(Approx(dimDev.x).margin(1) == s_dimDev.x);
+ CHECK(Approx(dimDev.y).margin(1) == s_dimDev.y);
+ }
+#endif // wxUSE_DC_TRANSFORM_MATRIX
+}
+
+// For GTK+ 3 and OSX wxDC is equivalent to wxGCDC
+// so it doesn't need to be tested individually.
+#if !defined(__WXGTK3__) && !defined(__WXOSX__)
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::InitialState", "[coordinates]")
+{
+ // Check initial state
+ InitialState(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::NoTransform", "[coordinates]")
+{
+ // No transformations
+ NoTransform(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::NoTransformEx", "[coordinates]")
+{
+ // No transformations
+ NoTransformEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::DeviceOriginChanged", "[coordinates]")
+{
+ // Only device origin is changed
+ DeviceOriginChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::DeviceOriginChangedEx", "[coordinates]")
+{
+ // Only device origin is changed
+ DeviceOriginChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::LogicalOriginChanged", "[coordinates]")
+{
+ // Only logical origin is changed
+ LogicalOriginChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::LogicalOriginChangedEx", "[coordinates]")
+{
+ // Only logical origin is changed
+ LogicalOriginChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::UserScaleChanged", "[coordinates]")
+{
+ // Only user scale is changed
+ UserScaleChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::UserScaleChangedEx", "[coordinates]")
+{
+ // Only user scale is changed
+ UserScaleChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::LogicalScaleChanged", "[coordinates]")
+{
+ // Only logical scale is changed
+ LogicalScaleChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::LogicalScaleChangedEx", "[coordinates]")
+{
+ // Only logical scale is changed
+ LogicalScaleChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedStd", "[coordinates]")
+{
+ // Apply all standardd transformations
+ TransformedStd(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedStdEx", "[coordinates]")
+{
+ // Apply all standardd transformations
+ TransformedStdEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedWithMatrix", "[coordinates]")
+{
+ // Apply transformation matrix only
+ TransformedWithMatrix(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedWithMatrixEx", "[coordinates]")
+{
+ // Apply transformation matrix only
+ TransformedWithMatrixEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedWithMatrixAndStd", "[coordinates]")
+{
+ // Apply combination of standard and matrix transformations
+ TransformedWithMatrixAndStd(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::TransformedWithMatrixAndStdEx", "[coordinates]")
+{
+ // Apply combination of standard and matrix transformations
+ TransformedWithMatrixAndStdEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::RotatedWithMatrix", "[coordinates]")
+{
+ // Apply matrix transformations with rotation component
+ RotatedWithMatrix(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesDCTestCase, "CoordinatesDC::RotatedWithMatrixEx", "[coordinates]")
+{
+ // Apply matrix transformations with rotation component
+ RotatedWithMatrixEx(m_dc);
+}
+#endif // !__WXGTK3__ && !_WXOSX__
+
+#if wxUSE_GRAPHICS_CONTEXT
+// For MSW we have individual test cases for each graphics renderer
+// so we don't need to test wxGCDC with default renderer.
+#ifndef __WXMSW__
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::InitialState", "[coordinates]")
+{
+ // Check initial state
+ InitialState(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::NoTransform", "[coordinates]")
+{
+ // No transformations
+ NoTransform(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::NoTransformEx", "[coordinates]")
+{
+ // No transformations
+ NoTransformEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::DeviceOriginChanged", "[coordinates]")
+{
+ // Only device origin is changed
+ DeviceOriginChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::DeviceOriginChangedEx", "[coordinates]")
+{
+ // Only device origin is changed
+ DeviceOriginChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::LogicalOriginChanged", "[coordinates]")
+{
+ // Only logical origin is changed
+ LogicalOriginChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::LogicalOriginChangedEx", "[coordinates]")
+{
+ // Only logical origin is changed
+ LogicalOriginChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::UserScaleChanged", "[coordinates]")
+{
+ // Only user scale is changed
+ UserScaleChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::UserScaleChangedEx", "[coordinates]")
+{
+ // Only user scale is changed
+ UserScaleChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::LogicalScaleChanged", "[coordinates]")
+{
+ // Only logical scale is changed
+ LogicalScaleChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::LogicalScaleChangedEx", "[coordinates]")
+{
+ // Only logical scale is changed
+ LogicalScaleChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedStd", "[coordinates]")
+{
+ // Apply all standardd transformations
+ TransformedStd(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedStdEx", "[coordinates]")
+{
+ // Apply all standardd transformations
+ TransformedStdEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedWithMatrix", "[coordinates]")
+{
+ // Apply transformation matrix only
+ TransformedWithMatrix(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedWithMatrixEx", "[coordinates]")
+{
+ // Apply transformation matrix only
+ TransformedWithMatrixEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedWithMatrixAndStd", "[coordinates]")
+{
+ // Apply combination of standard and matrix transformations
+ TransformedWithMatrixAndStd(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::TransformedWithMatrixAndStdEx", "[coordinates]")
+{
+ // Apply combination of standard and matrix transformations
+ TransformedWithMatrixAndStdEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::RotatedWithMatrix", "[coordinates]")
+{
+ // Apply matrix transformations with rotation component
+ RotatedWithMatrix(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCTestCase, "CoordinatesGCDC::RotatedWithMatrixEx", "[coordinates]")
+{
+ // Apply matrix transformations with rotation component
+ RotatedWithMatrixEx(m_dc);
+}
+#else// GDI+ and Direct2D are available only under MSW.
+#if wxUSE_GRAPHICS_GDIPLUS
+class CoordinatesGCDCGDIPlusTestCase : public CoordinatesGCDCTestCase
+{
+public:
+ CoordinatesGCDCGDIPlusTestCase()
+ {
+ wxGraphicsRenderer* rend = wxGraphicsRenderer::GetGDIPlusRenderer();
+ wxGraphicsContext* ctx = rend->CreateContext(m_mdc);
+ REQUIRE(ctx != NULL);
+ m_gcdc->SetGraphicsContext(ctx);
+ }
+
+ virtual ~CoordinatesGCDCGDIPlusTestCase() {}
+};
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::InitialState", "[coordinates]")
+{
+ // Check initial state
+ InitialState(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::NoTransform", "[coordinates]")
+{
+ // No transformations
+ NoTransform(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::NoTransformEx", "[coordinates]")
+{
+ // No transformations
+ NoTransformEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::DeviceOriginChanged", "[coordinates]")
+{
+ // Only device origin is changed
+ DeviceOriginChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::DeviceOriginChangedEx", "[coordinates]")
+{
+ // Only device origin is changed
+ DeviceOriginChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::LogicalOriginChanged", "[coordinates]")
+{
+ // Only logical origin is changed
+ LogicalOriginChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::LogicalOriginChangedEx", "[coordinates]")
+{
+ // Only logical origin is changed
+ LogicalOriginChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::UserScaleChanged", "[coordinates]")
+{
+ // Only user scale is changed
+ UserScaleChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::UserScaleChangedEx", "[coordinates]")
+{
+ // Only user scale is changed
+ UserScaleChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::LogicalScaleChanged", "[coordinates]")
+{
+ // Only logical scale is changed
+ LogicalScaleChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::LogicalScaleChangedex", "[coordinates]")
+{
+ // Only logical scale is changed
+ LogicalScaleChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedStd", "[coordinates]")
+{
+ // Apply all standardd transformations
+ TransformedStd(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedStdEx", "[coordinates]")
+{
+ // Apply all standardd transformations
+ TransformedStdEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedWithMatrix", "[coordinates]")
+{
+ // Apply transformation matrix only
+ TransformedWithMatrix(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedWithMatrixEx", "[coordinates]")
+{
+ // Apply transformation matrix only
+ TransformedWithMatrixEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedWithMatrixAndStd", "[coordinates]")
+{
+ // Apply combination of standard and matrix transformations
+ TransformedWithMatrixAndStd(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::TransformedWithMatrixAndStdEx", "[coordinates]")
+{
+ // Apply combination of standard and matrix transformations
+ TransformedWithMatrixAndStdEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::RotatedWithMatrix", "[coordinates]")
+{
+ // Apply matrix transformations with rotation component
+ RotatedWithMatrix(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCGDIPlusTestCase, "CoordinatesGCDCGDIPlus::RotatedWithMatrixEx", "[coordinates]")
+{
+ // Apply matrix transformations with rotation component
+ RotatedWithMatrixEx(m_dc);
+}
+#endif // wxUSE_GRAPHICS_GDIPLUS
+
+#if wxUSE_GRAPHICS_DIRECT2D
+class CoordinatesGCDCDirect2DTestCase : public CoordinatesGCDCTestCase
+{
+public:
+ CoordinatesGCDCDirect2DTestCase()
+ {
+ wxGraphicsRenderer* rend = wxGraphicsRenderer::GetDirect2DRenderer();
+ wxGraphicsContext* ctx = rend->CreateContext(m_mdc);
+ REQUIRE(ctx != NULL);
+ m_gcdc->SetGraphicsContext(ctx);
+ }
+
+ virtual ~CoordinatesGCDCDirect2DTestCase() {}
+};
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::InitialState", "[coordinates]")
+{
+ // Check initial state
+ InitialState(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::NoTransform", "[coordinates]")
+{
+ // No transformations
+ NoTransform(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::NoTransformEx", "[coordinates]")
+{
+ // No transformations
+ NoTransformEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::DeviceOriginChanged", "[coordinates]")
+{
+ // Only device origin is changed
+ DeviceOriginChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::DeviceOriginChangedEx", "[coordinates]")
+{
+ // Only device origin is changed
+ DeviceOriginChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::LogicalOriginChanged", "[coordinates]")
+{
+ // Only logical origin is changed
+ LogicalOriginChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::LogicalOriginChangedEx", "[coordinates]")
+{
+ // Only logical origin is changed
+ LogicalOriginChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::UserScaleChanged", "[coordinates]")
+{
+ // Only user scale is changed
+ UserScaleChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::UserScaleChangedEx", "[coordinates]")
+{
+ // Only user scale is changed
+ UserScaleChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::LogicalScaleChanged", "[coordinates]")
+{
+ // Only logical scale is changed
+ LogicalScaleChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::LogicalScaleChangedEx", "[coordinates]")
+{
+ // Only logical scale is changed
+ LogicalScaleChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedStd", "[coordinates]")
+{
+ // Apply all standardd transformations
+ TransformedStd(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedStdEx", "[coordinates]")
+{
+ // Apply all standardd transformations
+ TransformedStdEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedWithMatrix", "[coordinates]")
+{
+ // Apply transformation matrix only
+ TransformedWithMatrix(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedWithMatrixEx", "[coordinates]")
+{
+ // Apply transformation matrix only
+ TransformedWithMatrixEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedWithMatrixAndStd", "[coordinates]")
+{
+ // Apply combination of standard and matrix transformations
+ TransformedWithMatrixAndStd(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::TransformedWithMatrixAndStdEx", "[coordinates]")
+{
+ // Apply combination of standard and matrix transformations
+ TransformedWithMatrixAndStdEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::RotatedWithMatrix", "[coordinates]")
+{
+ // Apply matrix transformations with rotation component
+ RotatedWithMatrix(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCDirect2DTestCase, "CoordinatesGCDCDirect2D::RotatedWithMatrixEx", "[coordinates]")
+{
+ // Apply matrix transformations with rotation component
+ RotatedWithMatrixEx(m_dc);
+}
+#endif // wxUSE_GRAPHICS_DIRECT2D
+#endif // __WXMSW__/!__WXMSW__
+
+#if wxUSE_CAIRO
+class CoordinatesGCDCCairoTestCase : public CoordinatesGCDCTestCase
+{
+public:
+ CoordinatesGCDCCairoTestCase()
+ {
+ wxGraphicsRenderer* rend = wxGraphicsRenderer::GetCairoRenderer();
+ wxGraphicsContext* ctx = rend->CreateContext(m_mdc);
+ REQUIRE(ctx != NULL);
+ m_gcdc->SetGraphicsContext(ctx);
+ }
+
+ virtual ~CoordinatesGCDCCairoTestCase() {}
+};
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::InitialState", "[coordinates]")
+{
+ // Check initial state
+ InitialState(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::NoTransform", "[coordinates]")
+{
+ // No transformations
+ NoTransform(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::NoTransformEx", "[coordinates]")
+{
+ // No transformations
+ NoTransformEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::DeviceOriginChanged", "[coordinates]")
+{
+ // Only device origin is changed
+ DeviceOriginChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::DeviceOriginChangedEx", "[coordinates]")
+{
+ // Only device origin is changed
+ DeviceOriginChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::LogicalOriginChanged", "[coordinates]")
+{
+ // Only logical origin is changed
+ LogicalOriginChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::LogicalOriginChangedEx", "[coordinates]")
+{
+ // Only logical origin is changed
+ LogicalOriginChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::UserScaleChanged", "[coordinates]")
+{
+ // Only user scale is changed
+ UserScaleChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::UserScaleChangedEx", "[coordinates]")
+{
+ // Only user scale is changed
+ UserScaleChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::LogicalScaleChanged", "[coordinates]")
+{
+ // Only logical scale is changed
+ LogicalScaleChanged(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::LogicalScaleChangedEx", "[coordinates]")
+{
+ // Only logical scale is changed
+ LogicalScaleChangedEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedStd", "[coordinates]")
+{
+ // Apply all standardd transformations
+ TransformedStd(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedStdEx", "[coordinates]")
+{
+ // Apply all standardd transformations
+ TransformedStdEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedWithMatrix", "[coordinates]")
+{
+ // Apply transformation matrix only
+ TransformedWithMatrix(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedWithMatrixEx", "[coordinates]")
+{
+ // Apply transformation matrix only
+ TransformedWithMatrixEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedWithMatrixAndStd", "[coordinates]")
+{
+ // Apply combination of standard and matrix transformations
+ TransformedWithMatrixAndStd(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::TransformedWithMatrixAndStdEx", "[coordinates]")
+{
+ // Apply combination of standard and matrix transformations
+ TransformedWithMatrixAndStdEx(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::RotatedWithMatrix", "[coordinates]")
+{
+ // Apply matrix transformations with rotation component
+ RotatedWithMatrix(m_dc);
+}
+
+TEST_CASE_METHOD(CoordinatesGCDCCairoTestCase, "CoordinatesGCDCCairo::RotatedWithMatrixEx", "[coordinates]")
+{
+ // Apply matrix transformations with rotation component
+ RotatedWithMatrixEx(m_dc);
+}
+#endif // wxUSE_CAIRO
+#endif // wxUSE_GRAPHICS_CONTEXT
diff --git a/tests/image/image.cpp b/tests/image/image.cpp
index f76e79162c..c825a445a4 100644
--- a/tests/image/image.cpp
+++ b/tests/image/image.cpp
@@ -1454,6 +1454,438 @@ void ImageTestCase::ScaleCompare()
#endif //wxUSE_IMAGE
+TEST_CASE("wxImage::Paste", "[image][paste]")
+{
+ const static char* squares_xpm[] =
+ {
+ "9 9 7 1",
+ " c None",
+ "y c #FFFF00",
+ "r c #FF0000",
+ "g c #00FF00",
+ "b c #0000FF",
+ "o c #FF6600",
+ "w c #FFFFFF",
+ "rrrrwgggg",
+ "rrrrwgggg",
+ "rrrrwgggg",
+ "rrrrwgggg",
+ "wwwwwwwww",
+ "bbbbwoooo",
+ "bbbbwoooo",
+ "bbbbwoooo",
+ "bbbbwoooo"
+ };
+
+ const static char* toggle_equal_size_xpm[] =
+ {
+ "9 9 2 1",
+ " c None",
+ "y c #FFFF00",
+ "y y y y y",
+ " y y y y ",
+ "y y y y y",
+ " y y y y ",
+ "y y y y y",
+ " y y y y ",
+ "y y y y y",
+ " y y y y ",
+ "y y y y y",
+ };
+
+ const static char* transparent_image_xpm[] =
+ {
+ "5 5 2 1",
+ " c None", // Mask
+ "y c #FFFF00",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ };
+
+ const static char* light_image_xpm[] =
+ {
+ "5 5 2 1",
+ " c None",
+ "y c #FFFF00",
+ "yyyyy",
+ "yyyyy",
+ "yyyyy",
+ "yyyyy",
+ "yyyyy",
+ };
+
+ const static char* black_image_xpm[] =
+ {
+ "5 5 2 1",
+ " c #000000",
+ "y c None", // Mask
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ };
+
+ // Execute AddHandler() just once.
+ static const bool
+ registeredHandler = (wxImage::AddHandler(new wxPNGHandler()), true);
+
+ SECTION("Paste same size image")
+ {
+ wxImage actual(squares_xpm);
+ wxImage paste(toggle_equal_size_xpm);
+ wxImage expected(toggle_equal_size_xpm);
+ actual.Paste(paste, 0, 0);
+ CHECK_THAT(actual, RGBSameAs(expected));
+
+ // Without alpha using "compose" doesn't change anything.
+ actual.Paste(paste, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ CHECK_THAT(actual, RGBSameAs(expected));
+ }
+
+ SECTION("Paste larger image")
+ {
+ const static char* toggle_larger_size_xpm[] =
+ {
+ "13 13 2 1",
+ " c None",
+ "y c #FFFF00",
+ "y y y y y y y",
+ " y y y y y y ",
+ "y y y y y y y",
+ " y y y y y y ",
+ "y y y y y y y",
+ " y y y y y y ",
+ "y y y y y y y",
+ " y y y y y y ",
+ "y y y y y y y",
+ " y y y y y y ",
+ "y y y y y y y",
+ " y y y y y y ",
+ "y y y y y y y",
+ };
+
+ wxImage actual(squares_xpm);
+ wxImage paste(toggle_larger_size_xpm);
+ wxImage expected(toggle_equal_size_xpm);
+ actual.Paste(paste, -2, -2);
+ CHECK_THAT(actual, RGBSameAs(expected));
+ }
+
+ SECTION("Paste smaller image")
+ {
+ const static char* toggle_smaller_size_xpm[] =
+ {
+ "5 5 2 1",
+ " c None",
+ "y c #FFFF00",
+ "y y y",
+ " y y ",
+ "y y y",
+ " y y ",
+ "y y y",
+ };
+
+ const static char* expected_xpm[] =
+ {
+ "9 9 7 1",
+ " c None",
+ "y c #FFFF00",
+ "r c #FF0000",
+ "g c #00FF00",
+ "b c #0000FF",
+ "o c #FF6600",
+ "w c #FFFFFF",
+ "rrrrwgggg",
+ "rrrrwgggg",
+ "rry y ygg",
+ "rr y y gg",
+ "wwy y yww",
+ "bb y y oo",
+ "bby y yoo",
+ "bbbbwoooo",
+ "bbbbwoooo"
+ };
+
+ wxImage actual(squares_xpm);
+ wxImage paste(toggle_smaller_size_xpm);
+ wxImage expected(expected_xpm);
+ actual.Paste(paste, 2, 2);
+ CHECK_THAT(actual, RGBSameAs(expected));
+ }
+
+ SECTION("Paste beyond top left corner")
+ {
+ const static char* expected_xpm[] =
+ {
+ "9 9 7 1",
+ " c None",
+ "y c #FFFF00",
+ "r c #FF0000",
+ "g c #00FF00",
+ "b c #0000FF",
+ "o c #FF6600",
+ "w c #FFFFFF",
+ "oooowgggg",
+ "oooowgggg",
+ "oooowgggg",
+ "oooowgggg",
+ "wwwwwwwww",
+ "bbbbwoooo",
+ "bbbbwoooo",
+ "bbbbwoooo",
+ "bbbbwoooo"
+ };
+
+ wxImage actual(squares_xpm);
+ wxImage paste(squares_xpm);
+ wxImage expected(expected_xpm);
+ actual.Paste(paste, -5, -5);
+ CHECK_THAT(actual, RGBSameAs(expected));
+ }
+
+ SECTION("Paste beyond top right corner")
+ {
+ const static char* expected_xpm[] =
+ {
+ "9 9 7 1",
+ " c None",
+ "y c #FFFF00",
+ "r c #FF0000",
+ "g c #00FF00",
+ "b c #0000FF",
+ "o c #FF6600",
+ "w c #FFFFFF",
+ "rrrrwbbbb",
+ "rrrrwbbbb",
+ "rrrrwbbbb",
+ "rrrrwbbbb",
+ "wwwwwwwww",
+ "bbbbwoooo",
+ "bbbbwoooo",
+ "bbbbwoooo",
+ "bbbbwoooo"
+ };
+ wxImage actual(squares_xpm);
+ wxImage paste(squares_xpm);
+ wxImage expected(expected_xpm);
+ actual.Paste(paste, 5, -5);
+ CHECK_THAT(actual, RGBSameAs(expected));
+ }
+
+ SECTION("Paste beyond bottom right corner")
+ {
+ const static char* expected_xpm[] =
+ {
+ "9 9 7 1",
+ " c None",
+ "y c #FF0000",
+ "r c #FF0000",
+ "g c #00FF00",
+ "b c #0000FF",
+ "o c #FF6600",
+ "w c #FFFFFF",
+ "rrrrwgggg",
+ "rrrrwgggg",
+ "rrrrwgggg",
+ "rrrrwgggg",
+ "wwwwwwwww",
+ "bbbbwrrrr",
+ "bbbbwrrrr",
+ "bbbbwrrrr",
+ "bbbbwrrrr"
+ };
+ wxImage actual(squares_xpm);
+ wxImage paste(squares_xpm);
+ wxImage expected(expected_xpm);
+ actual.Paste(paste, 5, 5);
+ CHECK_THAT(actual, RGBSameAs(expected));
+ }
+
+ SECTION("Paste beyond bottom left corner")
+ {
+ const static char* expected_xpm[] =
+ {
+ "9 9 7 1",
+ " c None",
+ "y c #FFFF00",
+ "r c #FF0000",
+ "g c #00FF00",
+ "b c #0000FF",
+ "o c #FF6600",
+ "w c #FFFFFF",
+ "rrrrwgggg",
+ "rrrrwgggg",
+ "rrrrwgggg",
+ "rrrrwgggg",
+ "wwwwwwwww",
+ "ggggwoooo",
+ "ggggwoooo",
+ "ggggwoooo",
+ "ggggwoooo"
+ };
+ wxImage actual(squares_xpm);
+ wxImage paste(squares_xpm);
+ wxImage expected(expected_xpm);
+ actual.Paste(paste, -5, 5);
+ CHECK_THAT(actual, RGBSameAs(expected));
+ }
+
+ SECTION("Paste fully opaque image onto blank image without alpha")
+ {
+ const wxImage background("image/paste_input_background.png");
+ REQUIRE(background.IsOk());
+
+ wxImage actual(background.GetSize());
+ actual.Paste(background, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ CHECK_THAT(actual, RGBSameAs(background));
+ CHECK(!actual.HasAlpha());
+ }
+ SECTION("Paste fully opaque image onto blank image with alpha")
+ {
+ const wxImage background("image/paste_input_background.png");
+ REQUIRE(background.IsOk());
+
+ wxImage actual(background.GetSize());
+ actual.InitAlpha();
+ actual.Paste(background, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ CHECK_THAT(actual, RGBSameAs(background));
+ CHECK_THAT(actual, CenterAlphaPixelEquals(wxALPHA_OPAQUE));
+ }
+ SECTION("Paste fully transparent image")
+ {
+ const wxImage background("image/paste_input_background.png");
+ REQUIRE(background.IsOk());
+
+ wxImage actual = background.Copy();
+ wxImage transparent(actual.GetSize());
+ transparent.InitAlpha();
+ memset(transparent.GetAlpha(), 0, transparent.GetWidth() * transparent.GetHeight());
+ actual.Paste(transparent, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ CHECK_THAT(actual, RGBSameAs(background));
+ CHECK_THAT(actual, CenterAlphaPixelEquals(wxALPHA_OPAQUE));
+ }
+ SECTION("Paste image with transparent region")
+ {
+ wxImage actual("image/paste_input_background.png");
+ REQUIRE(actual.IsOk());
+
+ const wxImage opaque_square("image/paste_input_overlay_transparent_border_opaque_square.png");
+ REQUIRE(opaque_square.IsOk());
+
+ actual.Paste(opaque_square, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ CHECK_THAT(actual, RGBSameAs(wxImage("image/paste_result_background_plus_overlay_transparent_border_opaque_square.png")));
+ CHECK_THAT(actual, CenterAlphaPixelEquals(wxALPHA_OPAQUE));
+ }
+ SECTION("Paste image with semi transparent region")
+ {
+ wxImage actual("image/paste_input_background.png");
+ REQUIRE(actual.IsOk());
+
+ const wxImage transparent_square("image/paste_input_overlay_transparent_border_semitransparent_square.png");
+ REQUIRE(transparent_square.IsOk());
+
+ actual.Paste(transparent_square, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ CHECK_THAT(actual, RGBSameAs(wxImage("image/paste_result_background_plus_overlay_transparent_border_semitransparent_square.png")));
+ CHECK_THAT(actual, CenterAlphaPixelEquals(wxALPHA_OPAQUE));
+ }
+ SECTION("Paste two semi transparent images on top of background")
+ {
+ wxImage actual("image/paste_input_background.png");
+ REQUIRE(actual.IsOk());
+
+ const wxImage transparent_square("image/paste_input_overlay_transparent_border_semitransparent_square.png");
+ REQUIRE(transparent_square.IsOk());
+
+ const wxImage transparent_circle("image/paste_input_overlay_transparent_border_semitransparent_circle.png");
+ REQUIRE(transparent_circle.IsOk());
+
+ actual.Paste(transparent_circle, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ actual.Paste(transparent_square, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ CHECK_THAT(actual, RGBSimilarTo(wxImage("image/paste_result_background_plus_circle_plus_square.png"), 1));
+ CHECK_THAT(actual, CenterAlphaPixelEquals(wxALPHA_OPAQUE));
+ }
+ SECTION("Paste two semi transparent images together first, then on top of background")
+ {
+ wxImage actual("image/paste_input_background.png");
+ REQUIRE(actual.IsOk());
+
+ const wxImage transparent_square("image/paste_input_overlay_transparent_border_semitransparent_square.png");
+ REQUIRE(transparent_square.IsOk());
+
+ const wxImage transparent_circle("image/paste_input_overlay_transparent_border_semitransparent_circle.png");
+ REQUIRE(transparent_circle.IsOk());
+
+ wxImage circle = transparent_circle.Copy();
+ circle.Paste(transparent_square, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ actual.Paste(circle, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ // When applied in this order, two times a rounding difference is triggered.
+ CHECK_THAT(actual, RGBSimilarTo(wxImage("image/paste_result_background_plus_circle_plus_square.png"), 2));
+ CHECK_THAT(actual, CenterAlphaPixelEquals(wxALPHA_OPAQUE));
+ }
+ SECTION("Paste semitransparent image over transparent image")
+ {
+ const wxImage transparent_square("image/paste_input_overlay_transparent_border_semitransparent_square.png");
+ REQUIRE(transparent_square.IsOk());
+
+ const wxImage transparent_circle("image/paste_input_overlay_transparent_border_semitransparent_circle.png");
+ REQUIRE(transparent_circle.IsOk());
+
+ wxImage actual(transparent_circle.GetSize());
+ actual.InitAlpha();
+ memset(actual.GetAlpha(), 0, actual.GetWidth() * actual.GetHeight());
+ actual.Paste(transparent_circle, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ CHECK_THAT(actual, CenterAlphaPixelEquals(192));
+ actual.Paste(transparent_square, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ CHECK_THAT(actual, RGBSimilarTo(wxImage("image/paste_result_no_background_square_over_circle.png"), 1));
+ CHECK_THAT(actual, CenterAlphaPixelEquals(224));
+ }
+ SECTION("Paste fully transparent (masked) image over light image") // todo make test case for 'blend with mask'
+ {
+ wxImage actual(light_image_xpm);
+ actual.InitAlpha();
+ wxImage paste(transparent_image_xpm);
+ wxImage expected(light_image_xpm);
+ actual.Paste(paste, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ CHECK_THAT(actual, RGBSameAs(expected));
+ }
+ SECTION("Paste fully black (masked) image over light image") // todo make test case for 'blend with mask'
+ {
+ wxImage actual(light_image_xpm);
+ actual.InitAlpha();
+ wxImage paste(black_image_xpm);
+ wxImage expected(black_image_xpm);
+ actual.Paste(paste, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ CHECK_THAT(actual, RGBSameAs(expected));
+ }
+ SECTION("Paste dark image over light image")
+ {
+ wxImage black("image/paste_input_black.png");
+ wxImage actual("image/paste_input_background.png");
+ actual.InitAlpha();
+ actual.Paste(black, 0, 0, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ CHECK_THAT(actual, CenterAlphaPixelEquals(255));
+ CHECK_THAT(actual, RGBSameAs(black));
+ }
+ SECTION("Paste large image with negative vertical offset")
+ {
+ wxImage target(442, 249);
+ wxImage to_be_pasted(345, 24900);
+ target.InitAlpha();
+ target.Paste(to_be_pasted, 48, -12325, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ }
+ SECTION("Paste large image with negative horizontal offset")
+ {
+ wxImage target(249, 442);
+ wxImage to_be_pasted(24900, 345);
+ target.InitAlpha();
+ target.Paste(to_be_pasted, -12325, 48, wxIMAGE_ALPHA_BLEND_COMPOSE);
+ }
+
+}
/*
TODO: add lots of more tests to wxImage functions
diff --git a/tests/image/paste_input_background.png b/tests/image/paste_input_background.png
new file mode 100644
index 0000000000..fd93b550ce
Binary files /dev/null and b/tests/image/paste_input_background.png differ
diff --git a/tests/image/paste_input_black.png b/tests/image/paste_input_black.png
new file mode 100644
index 0000000000..43f4668bba
Binary files /dev/null and b/tests/image/paste_input_black.png differ
diff --git a/tests/image/paste_input_overlay_transparent_border_opaque_square.png b/tests/image/paste_input_overlay_transparent_border_opaque_square.png
new file mode 100644
index 0000000000..fa32073e5c
Binary files /dev/null and b/tests/image/paste_input_overlay_transparent_border_opaque_square.png differ
diff --git a/tests/image/paste_input_overlay_transparent_border_semitransparent_circle.png b/tests/image/paste_input_overlay_transparent_border_semitransparent_circle.png
new file mode 100644
index 0000000000..af6d42ffbd
Binary files /dev/null and b/tests/image/paste_input_overlay_transparent_border_semitransparent_circle.png differ
diff --git a/tests/image/paste_input_overlay_transparent_border_semitransparent_square.png b/tests/image/paste_input_overlay_transparent_border_semitransparent_square.png
new file mode 100644
index 0000000000..d609cd5a45
Binary files /dev/null and b/tests/image/paste_input_overlay_transparent_border_semitransparent_square.png differ
diff --git a/tests/image/paste_result_background_plus_circle_plus_square.png b/tests/image/paste_result_background_plus_circle_plus_square.png
new file mode 100644
index 0000000000..20af553c7d
Binary files /dev/null and b/tests/image/paste_result_background_plus_circle_plus_square.png differ
diff --git a/tests/image/paste_result_background_plus_overlay_transparent_border_opaque_square.png b/tests/image/paste_result_background_plus_overlay_transparent_border_opaque_square.png
new file mode 100644
index 0000000000..60da07730d
Binary files /dev/null and b/tests/image/paste_result_background_plus_overlay_transparent_border_opaque_square.png differ
diff --git a/tests/image/paste_result_background_plus_overlay_transparent_border_semitransparent_square.png b/tests/image/paste_result_background_plus_overlay_transparent_border_semitransparent_square.png
new file mode 100644
index 0000000000..a6e6fef28e
Binary files /dev/null and b/tests/image/paste_result_background_plus_overlay_transparent_border_semitransparent_square.png differ
diff --git a/tests/image/paste_result_no_background_square_over_circle.png b/tests/image/paste_result_no_background_square_over_circle.png
new file mode 100644
index 0000000000..d27564a130
Binary files /dev/null and b/tests/image/paste_result_no_background_square_over_circle.png differ
diff --git a/tests/makefile.bcc b/tests/makefile.bcc
index 6be3ae8a33..b505662946 100644
--- a/tests/makefile.bcc
+++ b/tests/makefile.bcc
@@ -168,6 +168,7 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_affinematrix.obj \
$(OBJS)\test_gui_boundingbox.obj \
$(OBJS)\test_gui_clippingbox.obj \
+ $(OBJS)\test_gui_coords.obj \
$(OBJS)\test_gui_graphmatrix.obj \
$(OBJS)\test_gui_graphpath.obj \
$(OBJS)\test_gui_config.obj \
@@ -570,7 +571,7 @@ data:
data-images:
if not exist image mkdir image
- for %f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png) do if not exist image\%f copy .\image\%f image
+ for %f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png) do if not exist image\%f copy .\image\%f image
fr:
if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr
@@ -907,6 +908,9 @@ $(OBJS)\test_gui_boundingbox.obj: .\graphics\boundingbox.cpp
$(OBJS)\test_gui_clippingbox.obj: .\graphics\clippingbox.cpp
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\graphics\clippingbox.cpp
+$(OBJS)\test_gui_coords.obj: .\graphics\coords.cpp
+ $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\graphics\coords.cpp
+
$(OBJS)\test_gui_graphmatrix.obj: .\graphics\graphmatrix.cpp
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\graphics\graphmatrix.cpp
diff --git a/tests/makefile.gcc b/tests/makefile.gcc
index 88cb64af69..c074804243 100644
--- a/tests/makefile.gcc
+++ b/tests/makefile.gcc
@@ -163,6 +163,7 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_affinematrix.o \
$(OBJS)\test_gui_boundingbox.o \
$(OBJS)\test_gui_clippingbox.o \
+ $(OBJS)\test_gui_coords.o \
$(OBJS)\test_gui_graphmatrix.o \
$(OBJS)\test_gui_graphpath.o \
$(OBJS)\test_gui_config.o \
@@ -555,7 +556,7 @@ data:
data-images:
if not exist image mkdir image
- for %%f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png) do if not exist image\%%f copy .\image\%%f image
+ for %%f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png) do if not exist image\%%f copy .\image\%%f image
fr:
if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr
@@ -892,6 +893,9 @@ $(OBJS)\test_gui_boundingbox.o: ./graphics/boundingbox.cpp
$(OBJS)\test_gui_clippingbox.o: ./graphics/clippingbox.cpp
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
+$(OBJS)\test_gui_coords.o: ./graphics/coords.cpp
+ $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
+
$(OBJS)\test_gui_graphmatrix.o: ./graphics/graphmatrix.cpp
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
diff --git a/tests/makefile.vc b/tests/makefile.vc
index 990d47e105..c5652c9a21 100644
--- a/tests/makefile.vc
+++ b/tests/makefile.vc
@@ -177,6 +177,7 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_affinematrix.obj \
$(OBJS)\test_gui_boundingbox.obj \
$(OBJS)\test_gui_clippingbox.obj \
+ $(OBJS)\test_gui_coords.obj \
$(OBJS)\test_gui_graphmatrix.obj \
$(OBJS)\test_gui_graphpath.obj \
$(OBJS)\test_gui_config.obj \
@@ -983,7 +984,7 @@ data:
data-images:
if not exist image mkdir image
- for %f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png) do if not exist image\%f copy .\image\%f image
+ for %f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png) do if not exist image\%f copy .\image\%f image
fr:
if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr
@@ -1320,6 +1321,9 @@ $(OBJS)\test_gui_boundingbox.obj: .\graphics\boundingbox.cpp
$(OBJS)\test_gui_clippingbox.obj: .\graphics\clippingbox.cpp
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\graphics\clippingbox.cpp
+$(OBJS)\test_gui_coords.obj: .\graphics\coords.cpp
+ $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\graphics\coords.cpp
+
$(OBJS)\test_gui_graphmatrix.obj: .\graphics\graphmatrix.cpp
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\graphics\graphmatrix.cpp
diff --git a/tests/mbconv/convautotest.cpp b/tests/mbconv/convautotest.cpp
index 6a5d5791d1..12e19c21ed 100644
--- a/tests/mbconv/convautotest.cpp
+++ b/tests/mbconv/convautotest.cpp
@@ -34,7 +34,9 @@ public:
private:
CPPUNIT_TEST_SUITE( ConvAutoTestCase );
+ CPPUNIT_TEST( Init );
CPPUNIT_TEST( Empty );
+ CPPUNIT_TEST( Encode );
CPPUNIT_TEST( Short );
CPPUNIT_TEST( None );
CPPUNIT_TEST( UTF32LE );
@@ -42,22 +44,53 @@ private:
CPPUNIT_TEST( UTF16LE );
CPPUNIT_TEST( UTF16BE );
CPPUNIT_TEST( UTF8 );
+ CPPUNIT_TEST( UTF8NoBom );
+ CPPUNIT_TEST( Fallback );
+ CPPUNIT_TEST( FallbackMultibyte );
+ CPPUNIT_TEST( FallbackShort );
CPPUNIT_TEST( StreamUTF8NoBOM );
CPPUNIT_TEST( StreamUTF8 );
CPPUNIT_TEST( StreamUTF16LE );
CPPUNIT_TEST( StreamUTF16BE );
CPPUNIT_TEST( StreamUTF32LE );
CPPUNIT_TEST( StreamUTF32BE );
+ CPPUNIT_TEST( StreamFallback );
+ CPPUNIT_TEST( StreamFallbackMultibyte );
CPPUNIT_TEST_SUITE_END();
+ // expected converter state, UTF-8 without BOM by default
+ struct ConvState
+ {
+ ConvState( wxBOM bom = wxBOM_None,
+ wxFontEncoding enc = wxFONTENCODING_UTF8,
+ bool fallback = false )
+ : m_bom(bom), m_enc(enc), m_fallback(fallback) {}
+
+ void Check(const wxConvAuto& conv) const
+ {
+ CPPUNIT_ASSERT( conv.GetBOM() == m_bom );
+ CPPUNIT_ASSERT( conv.GetEncoding() == m_enc );
+ CPPUNIT_ASSERT( conv.IsUsingFallbackEncoding() == m_fallback );
+ CPPUNIT_ASSERT( conv.IsUTF8() == (m_enc == wxFONTENCODING_UTF8) );
+ }
+
+ wxBOM m_bom;
+ wxFontEncoding m_enc;
+ bool m_fallback;
+ };
+
// real test function: check that converting the src multibyte string to
// wide char using wxConvAuto yields wch as the first result
//
// the length of the string may need to be passed explicitly if it has
// embedded NULs, otherwise it's not necessary
- void TestFirstChar(const char *src, wchar_t wch, size_t len = wxNO_LEN);
+ void TestFirstChar(const char *src, wchar_t wch, size_t len = wxNO_LEN,
+ ConvState st = ConvState(),
+ wxFontEncoding fe = wxFONTENCODING_DEFAULT);
+ void Init();
void Empty();
+ void Encode();
void Short();
void None();
void UTF32LE();
@@ -65,12 +98,17 @@ private:
void UTF16LE();
void UTF16BE();
void UTF8();
+ void UTF8NoBom();
+ void Fallback();
+ void FallbackMultibyte();
+ void FallbackShort();
// test whether two lines of text are converted properly from a stream
void TestTextStream(const char *src,
size_t srclength,
const wxString& line1,
- const wxString& line2);
+ const wxString& line2,
+ wxFontEncoding fe = wxFONTENCODING_DEFAULT);
void StreamUTF8NoBOM();
void StreamUTF8();
@@ -78,6 +116,8 @@ private:
void StreamUTF16BE();
void StreamUTF32LE();
void StreamUTF32BE();
+ void StreamFallback();
+ void StreamFallbackMultibyte();
};
// register in the unnamed registry so that these tests are run by default
@@ -90,16 +130,36 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ConvAutoTestCase, "ConvAutoTestCase");
// tests
// ----------------------------------------------------------------------------
-void ConvAutoTestCase::TestFirstChar(const char *src, wchar_t wch, size_t len)
+void ConvAutoTestCase::TestFirstChar(const char *src, wchar_t wch, size_t len,
+ ConvState st, wxFontEncoding fe)
{
- wxWCharBuffer wbuf = wxConvAuto().cMB2WC(src, len, NULL);
+ wxConvAuto conv(fe);
+ wxWCharBuffer wbuf = conv.cMB2WC(src, len, NULL);
CPPUNIT_ASSERT( wbuf );
CPPUNIT_ASSERT_EQUAL( wch, *wbuf );
+ st.Check(conv);
+}
+
+void ConvAutoTestCase::Init()
+{
+ ConvState(wxBOM_Unknown, wxFONTENCODING_MAX).Check(wxConvAuto());
}
void ConvAutoTestCase::Empty()
{
- CPPUNIT_ASSERT( !wxConvAuto().cMB2WC("") );
+ wxConvAuto conv;
+ CPPUNIT_ASSERT( !conv.cMB2WC("") );
+ ConvState(wxBOM_Unknown, wxFONTENCODING_MAX).Check(conv);
+}
+
+void ConvAutoTestCase::Encode()
+{
+ wxConvAuto conv;
+ wxString str = wxString::FromUTF8("\xd0\x9f\xe3\x81\x82");
+ wxCharBuffer buf = conv.cWC2MB(str.wc_str());
+ CPPUNIT_ASSERT( buf );
+ CPPUNIT_ASSERT_EQUAL( str, wxString::FromUTF8(buf) );
+ ConvState(wxBOM_Unknown, wxFONTENCODING_UTF8).Check(conv);
}
void ConvAutoTestCase::Short()
@@ -114,38 +174,71 @@ void ConvAutoTestCase::None()
void ConvAutoTestCase::UTF32LE()
{
- TestFirstChar("\xff\xfe\0\0A\0\0\0", wxT('A'), 8);
+ TestFirstChar("\xff\xfe\0\0A\0\0\0", wxT('A'), 8, ConvState(wxBOM_UTF32LE, wxFONTENCODING_UTF32LE));
}
void ConvAutoTestCase::UTF32BE()
{
- TestFirstChar("\0\0\xfe\xff\0\0\0B", wxT('B'), 8);
+ TestFirstChar("\0\0\xfe\xff\0\0\0B", wxT('B'), 8, ConvState(wxBOM_UTF32BE, wxFONTENCODING_UTF32BE));
}
void ConvAutoTestCase::UTF16LE()
{
- TestFirstChar("\xff\xfeZ\0", wxT('Z'), 4);
+ TestFirstChar("\xff\xfeZ\0", wxT('Z'), 4, ConvState(wxBOM_UTF16LE, wxFONTENCODING_UTF16LE));
}
void ConvAutoTestCase::UTF16BE()
{
- TestFirstChar("\xfe\xff\0Y", wxT('Y'), 4);
+ TestFirstChar("\xfe\xff\0Y", wxT('Y'), 4, ConvState(wxBOM_UTF16BE, wxFONTENCODING_UTF16BE));
}
void ConvAutoTestCase::UTF8()
{
#ifdef wxHAVE_U_ESCAPE
- TestFirstChar("\xef\xbb\xbf\xd0\x9f", L'\u041f');
+ TestFirstChar("\xef\xbb\xbf\xd0\x9f", L'\u041f', wxNO_LEN, ConvState(wxBOM_UTF8, wxFONTENCODING_UTF8));
#endif
}
+void ConvAutoTestCase::UTF8NoBom()
+{
+#ifdef wxHAVE_U_ESCAPE
+ TestFirstChar("\xd0\x9f\xe3\x81\x82", L'\u041f', wxNO_LEN, ConvState(wxBOM_None, wxFONTENCODING_UTF8));
+#endif
+}
+
+void ConvAutoTestCase::Fallback()
+{
+#ifdef wxHAVE_U_ESCAPE
+ TestFirstChar("\xbf", L'\u041f', wxNO_LEN,
+ ConvState(wxBOM_None, wxFONTENCODING_ISO8859_5, true),
+ wxFONTENCODING_ISO8859_5);
+#endif
+}
+
+void ConvAutoTestCase::FallbackMultibyte()
+{
+#ifdef wxHAVE_U_ESCAPE
+ TestFirstChar("\x84\x50", L'\u041f', wxNO_LEN,
+ ConvState(wxBOM_None, wxFONTENCODING_CP932, true),
+ wxFONTENCODING_CP932);
+#endif
+}
+
+void ConvAutoTestCase::FallbackShort()
+{
+ TestFirstChar("\x61\xc4", 'a', 2,
+ ConvState(wxBOM_None, wxFONTENCODING_ISO8859_5, true),
+ wxFONTENCODING_ISO8859_5);
+}
+
void ConvAutoTestCase::TestTextStream(const char *src,
size_t srclength,
const wxString& line1,
- const wxString& line2)
+ const wxString& line2,
+ wxFontEncoding fe)
{
wxMemoryInputStream instream(src, srclength);
- wxTextInputStream text(instream);
+ wxTextInputStream text(instream, wxT(" \t"), wxConvAuto(fe));
CPPUNIT_ASSERT_EQUAL( line1, text.ReadLine() );
CPPUNIT_ASSERT_EQUAL( line2, text.ReadLine() );
@@ -166,16 +259,8 @@ const wxString line2 = wxString::FromUTF8("\xce\xb2");
void ConvAutoTestCase::StreamUTF8NoBOM()
{
- // currently this test doesn't work because without the BOM wxConvAuto
- // decides that the string is in Latin-1 after finding the first (but not
- // the two subsequent ones which are part of the same UTF-8 sequence!)
- // 8-bit character
- //
- // FIXME: we need to fix this at wxTextInputStream level, see #11570
-#if 0
TestTextStream("\x61\xE3\x81\x82\x0A\xCE\xB2",
7, line1, line2);
-#endif
}
void ConvAutoTestCase::StreamUTF8()
@@ -210,4 +295,17 @@ void ConvAutoTestCase::StreamUTF32BE()
20, line1, line2);
}
+void ConvAutoTestCase::StreamFallback()
+{
+ TestTextStream("\x61\xbf\x0A\xe0",
+ 4, wxString::FromUTF8("a\xd0\x9f"), wxString::FromUTF8("\xd1\x80"),
+ wxFONTENCODING_ISO8859_5);
+}
+
+void ConvAutoTestCase::StreamFallbackMultibyte()
+{
+ TestTextStream("\x61\x82\xa0\x0A\x83\xc0",
+ 6, line1, line2, wxFONTENCODING_CP932);
+}
+
#endif // wxUSE_UNICODE
diff --git a/tests/streams/textstreamtest.cpp b/tests/streams/textstreamtest.cpp
index edb6eaa8a2..c6497b23f2 100644
--- a/tests/streams/textstreamtest.cpp
+++ b/tests/streams/textstreamtest.cpp
@@ -324,6 +324,46 @@ TEST_CASE("wxTextInputStream::GetChar", "[text][input][stream][char]")
REQUIRE( tis.GetChar() == 0x00 );
CHECK( tis.GetInputStream().Eof() );
}
+
+ // Two null bytes that look like the start of UTF-32BE BOM,
+ // followed by 4 byte UTF-8 sequence.
+ // Needs wxConvAuto to not switch to fallback on <6 bytes.
+ SECTION("UTF8-with-nulls")
+ {
+ const wxUint8 buf[] = { 0x00, 0x00, 0xf0, 0x90, 0x8c, 0x98 };
+ wxMemoryInputStream mis(buf, sizeof(buf));
+ wxTextInputStream tis(mis);
+
+ wxCharTypeBuffer e = wxString::FromUTF8((char*)buf, sizeof(buf))
+ .tchar_str();
+ for ( size_t i = 0; i < e.length(); ++i )
+ {
+ INFO("i = " << i);
+ REQUIRE( tis.GetChar() == e[i] );
+ }
+ REQUIRE( tis.GetChar() == 0x00 );
+ CHECK( tis.GetInputStream().Eof() );
+ }
+
+ // Two null bytes that look like the start of UTF-32BE BOM,
+ // then 3 bytes that look like the start of UTF-8 sequence.
+ // Needs 6 character output buffer in GetChar().
+ SECTION("almost-UTF8-with-nulls")
+ {
+ const wxUint8 buf[] = { 0x00, 0x00, 0xf0, 0x90, 0x8c, 0xe0 };
+ wxMemoryInputStream mis(buf, sizeof(buf));
+ wxTextInputStream tis(mis);
+
+ wxCharTypeBuffer e = wxString((char*)buf, wxCSConv(wxFONTENCODING_ISO8859_1),
+ sizeof(buf)).tchar_str();
+ for ( size_t i = 0; i < e.length(); ++i )
+ {
+ INFO("i = " << i);
+ REQUIRE( tis.GetChar() == e[i] );
+ }
+ REQUIRE( tis.GetChar() == 0x00 );
+ CHECK( tis.GetInputStream().Eof() );
+ }
}
#endif // wxUSE_UNICODE
diff --git a/tests/test.bkl b/tests/test.bkl
index 2588593b05..0aa49e95cd 100644
--- a/tests/test.bkl
+++ b/tests/test.bkl
@@ -181,6 +181,7 @@
graphics/affinematrix.cpp
graphics/boundingbox.cpp
graphics/clippingbox.cpp
+ graphics/coords.cpp
graphics/graphmatrix.cpp
graphics/graphpath.cpp
config/config.cpp
@@ -359,6 +360,16 @@
cross_bilinear_256x256.png
cross_box_average_256x256.png
cross_nearest_neighb_256x256.png
+
+ paste_input_background.png
+ paste_input_black.png
+ paste_input_overlay_transparent_border_opaque_square.png
+ paste_input_overlay_transparent_border_semitransparent_circle.png
+ paste_input_overlay_transparent_border_semitransparent_square.png
+ paste_result_background_plus_circle_plus_square.png
+ paste_result_background_plus_overlay_transparent_border_opaque_square.png
+ paste_result_background_plus_overlay_transparent_border_semitransparent_square.png
+ paste_result_no_background_square_over_circle.png
diff --git a/tests/test_gui.vcxproj b/tests/test_gui.vcxproj
index 754fdb8d44..7032b4ce33 100644
--- a/tests/test_gui.vcxproj
+++ b/tests/test_gui.vcxproj
@@ -547,6 +547,7 @@
+
diff --git a/tests/test_gui.vcxproj.filters b/tests/test_gui.vcxproj.filters
index e61c1bf4fd..0eede89fd6 100644
--- a/tests/test_gui.vcxproj.filters
+++ b/tests/test_gui.vcxproj.filters
@@ -293,6 +293,9 @@
Source Files
+
+ Source Files
+
Source Files
diff --git a/tests/test_vc7_test_gui.vcproj b/tests/test_vc7_test_gui.vcproj
index f18a1a38ce..ec237145b5 100644
--- a/tests/test_vc7_test_gui.vcproj
+++ b/tests/test_vc7_test_gui.vcproj
@@ -358,6 +358,9 @@
+
+
diff --git a/tests/test_vc8_test_gui.vcproj b/tests/test_vc8_test_gui.vcproj
index ccc8576f4a..dd1700c187 100644
--- a/tests/test_vc8_test_gui.vcproj
+++ b/tests/test_vc8_test_gui.vcproj
@@ -914,6 +914,10 @@
RelativePath=".\config\config.cpp"
>
+
+
diff --git a/tests/test_vc9_test_gui.vcproj b/tests/test_vc9_test_gui.vcproj
index c9c6d5a4e8..ff01099d23 100644
--- a/tests/test_vc9_test_gui.vcproj
+++ b/tests/test_vc9_test_gui.vcproj
@@ -886,6 +886,10 @@
RelativePath=".\config\config.cpp"
>
+
+
diff --git a/tests/testimage.h b/tests/testimage.h
index e922e36d63..f4f20d8ddc 100644
--- a/tests/testimage.h
+++ b/tests/testimage.h
@@ -30,8 +30,9 @@ namespace Catch
class ImageRGBMatcher : public Catch::MatcherBase
{
public:
- ImageRGBMatcher(const wxImage& image)
+ ImageRGBMatcher(const wxImage& image, int tolerance)
: m_image(image)
+ , m_tolerance(tolerance)
{
}
@@ -53,7 +54,8 @@ public:
{
for ( int y = 0; y < m_image.GetHeight(); ++y )
{
- if ( *d1 != *d2 )
+ const unsigned char diff = *d1 > * d2 ? *d1 - *d2 : *d2 - *d1;
+ if (diff > m_tolerance)
{
m_diffDesc.Printf
(
@@ -72,11 +74,11 @@ public:
}
}
- // We should never get here as we know that the images are different
- // and so should have returned from inside the loop above.
- wxFAIL_MSG("unreachable");
+ // We can only get here when the images are different AND we've not exited the
+ // method from the loop. That implies the tolerance must have caused this.
+ wxASSERT_MSG(m_tolerance > 0, "Unreachable without tolerance");
- return false;
+ return true;
}
std::string describe() const wxOVERRIDE
@@ -92,12 +94,67 @@ public:
private:
const wxImage m_image;
+ const int m_tolerance;
mutable wxString m_diffDesc;
};
inline ImageRGBMatcher RGBSameAs(const wxImage& image)
{
- return ImageRGBMatcher(image);
+ return ImageRGBMatcher(image, 0);
+}
+
+// Allows small differences (within given tolerance) for r, g, and b values.
+inline ImageRGBMatcher RGBSimilarTo(const wxImage& image, int tolerance)
+{
+ return ImageRGBMatcher(image, tolerance);
+}
+
+class ImageAlphaMatcher : public Catch::MatcherBase
+{
+public:
+ ImageAlphaMatcher(unsigned char alpha)
+ : m_alpha(alpha)
+ {
+ }
+
+ bool match(const wxImage& other) const wxOVERRIDE
+ {
+ if (!other.HasAlpha())
+ {
+ m_diffDesc = "no alpha data";
+ return false;
+ }
+
+ unsigned char center_alpha =
+ *(other.GetAlpha() + (other.GetWidth() / 2) + (other.GetHeight() / 2 * other.GetWidth()));
+
+ if (m_alpha != center_alpha)
+ {
+ m_diffDesc.Printf("got alpha %u", center_alpha);
+ return false;
+ }
+
+ return true;
+ }
+
+ std::string describe() const wxOVERRIDE
+ {
+ std::string desc;
+
+ if (!m_diffDesc.empty())
+ desc = m_diffDesc.ToStdString(wxConvUTF8);
+
+ return desc;
+ }
+
+private:
+ const unsigned char m_alpha;
+ mutable wxString m_diffDesc;
+};
+
+inline ImageAlphaMatcher CenterAlphaPixelEquals(unsigned char alpha)
+{
+ return ImageAlphaMatcher(alpha);
}
#endif // _WX_TESTS_TESTIMAGE_H_
diff --git a/tests/testwindow.h b/tests/testwindow.h
index 64b455b261..00f8003ec5 100644
--- a/tests/testwindow.h
+++ b/tests/testwindow.h
@@ -9,6 +9,7 @@
#ifndef _WX_TESTS_TESTWINDOW_H_
#define _WX_TESTS_TESTWINDOW_H_
+#include "wx/scopedptr.h"
#include "wx/window.h"
// We need to wrap wxWindow* in a class as specializing StringMaker for
@@ -17,6 +18,8 @@ class wxWindowPtr
{
public:
explicit wxWindowPtr(wxWindow* win) : m_win(win) {}
+ template
+ explicit wxWindowPtr(const wxScopedPtr& win) : m_win(win.get()) {}
wxString Dump() const
{
@@ -44,7 +47,9 @@ private:
// Macro providing more information about the current focus if comparison
// fails.
-#define CHECK_FOCUS_IS(w) CHECK(wxWindowPtr(wxWindow::FindFocus()) == wxWindowPtr(w))
+#define CHECK_SAME_WINDOW(w1, w2) CHECK(wxWindowPtr(w1) == wxWindowPtr(w2))
+
+#define CHECK_FOCUS_IS(w) CHECK_SAME_WINDOW(wxWindow::FindFocus(), w)
namespace Catch
{
diff --git a/wx-config.in b/wx-config.in
index 16013d35b9..441f88ce92 100755
--- a/wx-config.in
+++ b/wx-config.in
@@ -1311,12 +1311,12 @@ if [ -n "$output_option_libs" ]; then
_ldflags="-L$libdir"
if [ -n "$MAC_FRAMEWORK" ]; then
- wx_libs="-framework $MAC_FRAMEWORK"
- if [ -n "$MAC_FRAMEWORK_PREFIX" ]; then
- _ldflags="-F$MAC_FRAMEWORK_PREFIX"
- else
- _ldflags=""
- fi
+ wx_libs="-framework $MAC_FRAMEWORK"
+ if [ -n "$MAC_FRAMEWORK_PREFIX" ]; then
+ _ldflags="-F$MAC_FRAMEWORK_PREFIX"
+ else
+ _ldflags=""
+ fi
fi
is_installed || [ -n "$flag_option_no_rpath" ] || _rpath="@WXCONFIG_RPATH@"