From e6e1a42e1e84d7a24c79295d01aa8b1844d64c6b Mon Sep 17 00:00:00 2001 From: B Stack Date: Fri, 27 Dec 2019 08:28:17 -0500 Subject: add upstream 10.19 --- Changelog.txt | 13 + FreeFileSync/Build/Resources/Icons.zip | Bin 338102 -> 391482 bytes FreeFileSync/Build/Resources/Languages.zip | Bin 504688 -> 506524 bytes FreeFileSync/Source/RealTimeSync/application.cpp | 3 + FreeFileSync/Source/RealTimeSync/application.h | 1 + FreeFileSync/Source/RealTimeSync/gui_generated.cpp | 28 +- FreeFileSync/Source/RealTimeSync/gui_generated.h | 9 +- FreeFileSync/Source/RealTimeSync/main_dlg.cpp | 25 +- FreeFileSync/Source/afs/ftp.cpp | 68 +-- FreeFileSync/Source/afs/gdrive.cpp | 439 ++++++++-------- FreeFileSync/Source/afs/native.cpp | 2 +- FreeFileSync/Source/afs/sftp.cpp | 2 +- FreeFileSync/Source/base/application.cpp | 3 + FreeFileSync/Source/base/application.h | 2 +- FreeFileSync/Source/base/config.cpp | 103 +++- FreeFileSync/Source/base/config.h | 2 +- FreeFileSync/Source/base/db_file.cpp | 6 +- FreeFileSync/Source/base/dir_lock.cpp | 32 +- FreeFileSync/Source/base/icon_buffer.h | 4 +- FreeFileSync/Source/base/localization.cpp | 155 +++--- FreeFileSync/Source/base/localization.h | 7 +- FreeFileSync/Source/base/log_file.cpp | 14 +- FreeFileSync/Source/base/path_filter.h | 26 +- FreeFileSync/Source/base/structures.cpp | 6 +- FreeFileSync/Source/base/synchronization.cpp | 2 +- FreeFileSync/Source/ui/abstract_folder_picker.cpp | 2 +- FreeFileSync/Source/ui/cfg_grid.cpp | 36 +- FreeFileSync/Source/ui/command_box.cpp | 2 +- FreeFileSync/Source/ui/file_grid.cpp | 79 ++- FreeFileSync/Source/ui/file_view.cpp | 51 +- FreeFileSync/Source/ui/folder_history_box.cpp | 2 +- FreeFileSync/Source/ui/folder_pair.h | 25 +- FreeFileSync/Source/ui/gui_generated.cpp | 554 ++++++++++----------- FreeFileSync/Source/ui/gui_generated.h | 69 ++- FreeFileSync/Source/ui/log_panel.cpp | 10 +- FreeFileSync/Source/ui/main_dlg.cpp | 75 +-- FreeFileSync/Source/ui/progress_indicator.cpp | 12 +- FreeFileSync/Source/ui/small_dlgs.cpp | 143 +++--- FreeFileSync/Source/ui/sync_cfg.cpp | 22 +- FreeFileSync/Source/ui/tree_grid.cpp | 20 +- FreeFileSync/Source/version/version.h | 2 +- wx+/bitmap_button.h | 12 +- wx+/file_drop.h | 2 - wx+/graph.cpp | 8 +- wx+/grid.cpp | 55 +- wx+/grid.h | 4 +- wx+/image_resources.cpp | 127 +++-- wx+/image_resources.h | 2 +- wx+/image_tools.cpp | 24 +- wx+/image_tools.h | 50 +- wx+/popup_dlg_generated.cpp | 5 +- wx+/popup_dlg_generated.h | 6 +- wx+/rtl.h | 5 +- wx+/std_button_layout.h | 2 +- wx+/tooltip.cpp | 2 +- xBRZ/src/xbrz.cpp | 387 ++++++++------ xBRZ/src/xbrz.h | 1 - xBRZ/src/xbrz_tools.h | 10 +- zen/globals.h | 2 +- zen/legacy_compiler.h | 6 +- zen/serialize.h | 1 + zen/stl_tools.h | 6 +- zen/string_tools.h | 48 +- zen/sys_error.h | 2 +- 64 files changed, 1485 insertions(+), 1338 deletions(-) mode change 100755 => 100644 FreeFileSync/Build/Resources/Icons.zip mode change 100755 => 100644 FreeFileSync/Build/Resources/Languages.zip diff --git a/Changelog.txt b/Changelog.txt index 14301dab..c4b991e7 100755 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,16 @@ +FreeFileSync 10.19 [2019-12-27] +------------------------------- +Unified rendering of disabled grid layouts +Count moved file pair as one update in view filter buttons +Fix command button default sizes (Windows) +Added %item_name%, %item_name2% context menu macros +Support deleting references to shared Google Drive files +Trash Google Drive files only when having single parent +Fixed high DPI scaling issue on image borders +Preserve system date format for RTL languages +Fall back to folder path if resource archives are missing + + FreeFileSync 10.18 [2019-11-19] ------------------------------- Save/load database files in parallel diff --git a/FreeFileSync/Build/Resources/Icons.zip b/FreeFileSync/Build/Resources/Icons.zip old mode 100755 new mode 100644 index b010e86e..a02a0759 Binary files a/FreeFileSync/Build/Resources/Icons.zip and b/FreeFileSync/Build/Resources/Icons.zip differ diff --git a/FreeFileSync/Build/Resources/Languages.zip b/FreeFileSync/Build/Resources/Languages.zip old mode 100755 new mode 100644 index ba318dd8..a6c2362b Binary files a/FreeFileSync/Build/Resources/Languages.zip and b/FreeFileSync/Build/Resources/Languages.zip differ diff --git a/FreeFileSync/Source/RealTimeSync/application.cpp b/FreeFileSync/Source/RealTimeSync/application.cpp index 63b8ccbe..db28c580 100644 --- a/FreeFileSync/Source/RealTimeSync/application.cpp +++ b/FreeFileSync/Source/RealTimeSync/application.cpp @@ -113,6 +113,9 @@ int Application::OnExit() } +wxLayoutDirection Application::GetLayoutDirection() const { return fff::getLayoutDirection(); } + + void Application::onEnterEventLoop(wxEvent& event) { Disconnect(EVENT_ENTER_EVENT_LOOP, wxEventHandler(Application::onEnterEventLoop), nullptr, this); diff --git a/FreeFileSync/Source/RealTimeSync/application.h b/FreeFileSync/Source/RealTimeSync/application.h index 73747c6a..9c632686 100644 --- a/FreeFileSync/Source/RealTimeSync/application.h +++ b/FreeFileSync/Source/RealTimeSync/application.h @@ -20,6 +20,7 @@ private: int OnExit() override; bool OnExceptionInMainLoop() override { throw; } //just re-throw and avoid display of additional messagebox: it will be caught in OnRun() void OnUnhandledException () override { throw; } //just re-throw and avoid display of additional messagebox + wxLayoutDirection GetLayoutDirection() const override; void onEnterEventLoop(wxEvent& event); void onQueryEndSession(wxEvent& event); diff --git a/FreeFileSync/Source/RealTimeSync/gui_generated.cpp b/FreeFileSync/Source/RealTimeSync/gui_generated.cpp index e2cb067b..7709981d 100644 --- a/FreeFileSync/Source/RealTimeSync/gui_generated.cpp +++ b/FreeFileSync/Source/RealTimeSync/gui_generated.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version May 29 2018) +// C++ code generated with wxFormBuilder (version Oct 26 2018) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -32,9 +32,8 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr m_menuFile->AppendSeparator(); - wxMenuItem* m_menuItem4; - m_menuItem4 = new wxMenuItem( m_menuFile, wxID_EXIT, wxString( _("E&xit") ), wxEmptyString, wxITEM_NORMAL ); - m_menuFile->Append( m_menuItem4 ); + m_menuItemQuit = new wxMenuItem( m_menuFile, wxID_EXIT, wxString( _("E&xit") ), wxEmptyString, wxITEM_NORMAL ); + m_menuFile->Append( m_menuItemQuit ); m_menubar1->Append( m_menuFile, _("&File") ); @@ -174,12 +173,12 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr wxBoxSizer* bSizer20; bSizer20 = new wxBoxSizer( wxHORIZONTAL ); - m_bpButtonAddFolder = new wxBitmapButton( m_panelMainFolder, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonAddFolder = new wxBitmapButton( m_panelMainFolder, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonAddFolder->SetToolTip( _("Add folder") ); bSizer20->Add( m_bpButtonAddFolder, 0, wxEXPAND, 5 ); - m_bpButtonRemoveTopFolder = new wxBitmapButton( m_panelMainFolder, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonRemoveTopFolder = new wxBitmapButton( m_panelMainFolder, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonRemoveTopFolder->SetToolTip( _("Remove folder") ); bSizer20->Add( m_bpButtonRemoveTopFolder, 0, wxEXPAND, 5 ); @@ -283,6 +282,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr bSizerMain->Add( m_staticline5, 0, wxEXPAND, 5 ); m_buttonStart = new zen::BitmapTextButton( this, wxID_OK, _("Start"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonStart->SetDefault(); m_buttonStart->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); @@ -297,12 +297,12 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr // Connect Events this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDlgGenerated::OnClose ) ); - this->Connect( m_menuItem6->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnConfigNew ) ); - this->Connect( m_menuItem13->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnConfigLoad ) ); - this->Connect( m_menuItem14->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnConfigSave ) ); - this->Connect( m_menuItem4->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnMenuQuit ) ); - this->Connect( m_menuItemContent->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnShowHelp ) ); - this->Connect( m_menuItemAbout->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnMenuAbout ) ); + m_menuFile->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnConfigNew ), this, m_menuItem6->GetId()); + m_menuFile->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnConfigLoad ), this, m_menuItem13->GetId()); + m_menuFile->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnConfigSave ), this, m_menuItem14->GetId()); + m_menuFile->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnMenuQuit ), this, m_menuItemQuit->GetId()); + m_menuHelp->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnShowHelp ), this, m_menuItemContent->GetId()); + m_menuHelp->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnMenuAbout ), this, m_menuItemAbout->GetId()); m_bpButtonAddFolder->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDlgGenerated::OnAddFolder ), NULL, this ); m_bpButtonRemoveTopFolder->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDlgGenerated::OnRemoveTopFolder ), NULL, this ); m_buttonStart->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDlgGenerated::OnStart ), NULL, this ); @@ -312,14 +312,14 @@ MainDlgGenerated::~MainDlgGenerated() { } -FolderGenerated::FolderGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) +FolderGenerated::FolderGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : wxPanel( parent, id, pos, size, style, name ) { this->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); wxBoxSizer* bSizer114; bSizer114 = new wxBoxSizer( wxHORIZONTAL ); - m_bpButtonRemoveFolder = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonRemoveFolder = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonRemoveFolder->SetToolTip( _("Remove folder") ); bSizer114->Add( m_bpButtonRemoveFolder, 0, wxEXPAND, 5 ); diff --git a/FreeFileSync/Source/RealTimeSync/gui_generated.h b/FreeFileSync/Source/RealTimeSync/gui_generated.h index 323db79d..1fd190f0 100644 --- a/FreeFileSync/Source/RealTimeSync/gui_generated.h +++ b/FreeFileSync/Source/RealTimeSync/gui_generated.h @@ -1,12 +1,11 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version May 29 2018) +// C++ code generated with wxFormBuilder (version Oct 26 2018) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// -#ifndef __GUI_GENERATED_H__ -#define __GUI_GENERATED_H__ +#pragma once #include #include @@ -49,6 +48,7 @@ private: protected: wxMenuBar* m_menubar1; wxMenu* m_menuFile; + wxMenuItem* m_menuItemQuit; wxMenu* m_menuHelp; wxMenuItem* m_menuItemAbout; wxBoxSizer* bSizerMain; @@ -122,9 +122,8 @@ public: wxBitmapButton* m_bpButtonRemoveFolder; wxTextCtrl* m_txtCtrlDirectory; - FolderGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = 0 ); + FolderGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = 0, const wxString& name = wxEmptyString ); ~FolderGenerated(); }; -#endif //__GUI_GENERATED_H__ diff --git a/FreeFileSync/Source/RealTimeSync/main_dlg.cpp b/FreeFileSync/Source/RealTimeSync/main_dlg.cpp index 6ddbc215..57e188ea 100644 --- a/FreeFileSync/Source/RealTimeSync/main_dlg.cpp +++ b/FreeFileSync/Source/RealTimeSync/main_dlg.cpp @@ -77,8 +77,8 @@ MainDialog::MainDialog(const Zstring& cfgFileName) : setRelativeFontSize(*m_buttonStart, 1.5); - m_txtCtrlDirectoryMain->SetMinSize(wxSize(fastFromDIP(300), -1)); - m_spinCtrlDelay->SetMinSize(wxSize(fastFromDIP(70), -1)); //Hack: set size (why does wxWindow::Size() not work?) + m_txtCtrlDirectoryMain->SetMinSize({fastFromDIP(300), -1}); + m_spinCtrlDelay ->SetMinSize({fastFromDIP( 70), -1}); //Hack: set size (why does wxWindow::Size() not work?) m_checkBoxHideConsole->Hide(); //only relevant on Windows m_bpButtonRemoveTopFolder->Hide(); @@ -95,6 +95,7 @@ MainDialog::MainDialog(const Zstring& cfgFileName) : //register key event Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(MainDialog::OnKeyPressed), nullptr, this); + //prepare drag & drop firstFolderPanel_ = std::make_unique(this, *m_panelMainFolder, *m_buttonSelectFolderMain, *m_txtCtrlDirectoryMain, m_staticTextFinalPath); @@ -184,21 +185,27 @@ void MainDialog::OnShowHelp(wxCommandEvent& event) void MainDialog::OnMenuAbout(wxCommandEvent& event) { - std::wstring build = formatTime(FORMAT_DATE, getCompileTime()) + SPACED_DASH + L"Unicode"; + wxString build = utfTo(fff::ffsVersion); #ifndef wxUSE_UNICODE #error what is going on? #endif - build += + const wchar_t* const SPACED_BULLET = L" \u2022 "; + build += SPACED_BULLET; + + build += LTR_MARK; //fix Arabic #if ZEN_BUILD_ARCH == ZEN_ARCH_32BIT - L" x86"; + build += L"32 Bit"; #else - L" x64"; + build += L"64 Bit"; #endif + build += SPACED_BULLET; + build += formatTime(FORMAT_DATE, getCompileTime()); + showNotificationDialog(this, DialogInfoType::info, PopupDialogCfg(). setTitle(_("About")). - setMainInstructions(L"RealTimeSync" L"\n\n" + replaceCpy(_("Build: %x"), L"%x", build))); + setMainInstructions(L"RealTimeSync" L"\n\n" + replaceCpy(_("Version: %x"), L"%x", build))); } @@ -436,7 +443,7 @@ void MainDialog::insertAddFolder(const std::vector& newFolders, size_t const int folderHeight = additionalFolderPanels_.empty() ? 0 : additionalFolderPanels_[0]->GetSize().GetHeight(); const size_t visibleRows = std::min(additionalFolderPanels_.size(), MAX_ADD_FOLDERS); //up to MAX_ADD_FOLDERS additional folders shall be shown - m_scrolledWinFolders->SetMinSize(wxSize(-1, folderHeight * static_cast(visibleRows))); + m_scrolledWinFolders->SetMinSize({-1, folderHeight * static_cast(visibleRows)}); //adapt delete top folder pair button m_bpButtonRemoveTopFolder->Show(!additionalFolderPanels_.empty()); @@ -468,7 +475,7 @@ void MainDialog::removeAddFolder(size_t pos) const int folderHeight = additionalFolderPanels_.empty() ? 0 : additionalFolderPanels_[0]->GetSize().GetHeight(); const size_t visibleRows = std::min(additionalFolderPanels_.size(), MAX_ADD_FOLDERS); //up to MAX_ADD_FOLDERS additional folders shall be shown - m_scrolledWinFolders->SetMinSize(wxSize(-1, folderHeight * static_cast(visibleRows))); + m_scrolledWinFolders->SetMinSize({-1, folderHeight * static_cast(visibleRows)}); m_scrolledWinFolders->Layout(); //[!] needed when scrollbars are shown //adapt delete top folder pair button diff --git a/FreeFileSync/Source/afs/ftp.cpp b/FreeFileSync/Source/afs/ftp.cpp index 9ae1c89c..0380df48 100644 --- a/FreeFileSync/Source/afs/ftp.cpp +++ b/FreeFileSync/Source/afs/ftp.cpp @@ -245,39 +245,39 @@ std::wstring formatFtpStatusCode(int sc) { switch (sc) { - //*INDENT-OFF* - case 400: return L"The command was not accepted but the error condition is temporary."; - case 421: return L"Service not available, closing control connection."; - case 425: return L"Cannot open data connection."; - case 426: return L"Connection closed; transfer aborted."; - case 430: return L"Invalid username or password."; - case 431: return L"Need some unavailable resource to process security."; - case 434: return L"Requested host unavailable."; - case 450: return L"Requested file action not taken."; - case 451: return L"Local error in processing."; - case 452: return L"Insufficient storage space in system. File unavailable, e.g. file busy."; - - case 500: return L"Syntax error, command unrecognized or command line too long."; - case 501: return L"Syntax error in parameters or arguments."; - case 502: return L"Command not implemented."; - case 503: return L"Bad sequence of commands."; - case 504: return L"Command not implemented for that parameter."; - case 521: return L"Data connection cannot be opened with this PROT setting."; - case 522: return L"Server does not support the requested network protocol."; - case 530: return L"User not logged in."; - case 532: return L"Need account for storing files."; - case 533: return L"Command protection level denied for policy reasons."; - case 534: return L"Could not connect to server; issue regarding SSL."; - case 535: return L"Failed security check."; - case 536: return L"Requested PROT level not supported by mechanism."; - case 537: return L"Command protection level not supported by security mechanism."; - case 550: return L"File unavailable, e.g. file not found, no access."; - case 551: return L"Requested action aborted. Page type unknown."; - case 552: return L"Requested file action aborted. Exceeded storage allocation."; - case 553: return L"File name not allowed."; - - default: return L""; - //*INDENT-ON* + //*INDENT-OFF* + case 400: return L"The command was not accepted but the error condition is temporary."; + case 421: return L"Service not available, closing control connection."; + case 425: return L"Cannot open data connection."; + case 426: return L"Connection closed; transfer aborted."; + case 430: return L"Invalid username or password."; + case 431: return L"Need some unavailable resource to process security."; + case 434: return L"Requested host unavailable."; + case 450: return L"Requested file action not taken."; + case 451: return L"Local error in processing."; + case 452: return L"Insufficient storage space in system. File unavailable, e.g. file busy."; + + case 500: return L"Syntax error, command unrecognized or command line too long."; + case 501: return L"Syntax error in parameters or arguments."; + case 502: return L"Command not implemented."; + case 503: return L"Bad sequence of commands."; + case 504: return L"Command not implemented for that parameter."; + case 521: return L"Data connection cannot be opened with this PROT setting."; + case 522: return L"Server does not support the requested network protocol."; + case 530: return L"User not logged in."; + case 532: return L"Need account for storing files."; + case 533: return L"Command protection level denied for policy reasons."; + case 534: return L"Could not connect to server; issue regarding SSL."; + case 535: return L"Failed security check."; + case 536: return L"Requested PROT level not supported by mechanism."; + case 537: return L"Command protection level not supported by security mechanism."; + case 550: return L"File unavailable, e.g. file not found, no access."; + case 551: return L"Requested action aborted. Page type unknown."; + case 552: return L"Requested file action aborted. Exceeded storage allocation."; + case 553: return L"File name not allowed."; + + default: return L""; + //*INDENT-ON* } }(); @@ -2262,6 +2262,6 @@ bool fff::acceptsItemPathPhraseFtp(const Zstring& itemPathPhrase) //noexcept AbstractPath fff::createItemPathFtp(const Zstring& itemPathPhrase) //noexcept { - const FtpPathInfo pi = getResolvedFtpPath(itemPathPhrase); //noexcept + const FtpPathInfo& pi = getResolvedFtpPath(itemPathPhrase); //noexcept return AbstractPath(makeSharedRef(pi.login), pi.afsPath); } diff --git a/FreeFileSync/Source/afs/gdrive.cpp b/FreeFileSync/Source/afs/gdrive.cpp index fe4f932a..073e916c 100644 --- a/FreeFileSync/Source/afs/gdrive.cpp +++ b/FreeFileSync/Source/afs/gdrive.cpp @@ -68,7 +68,7 @@ const Zchar googleDrivePrefix[] = Zstr("gdrive:"); const char googleFolderMimeType[] = "application/vnd.google-apps.folder"; const char DB_FORMAT_DESCR[] = "FreeFileSync: Google Drive Database"; -const int DB_FORMAT_VER = 1; +const int DB_FORMAT_VER = 2; //2019-12-05 std::string getGoogleDriveClientId () { return ""; } // => replace with live credentials std::string getGoogleDriveClientSecret() { return ""; } // @@ -555,25 +555,25 @@ GoogleUserInfo getUserInfo(const std::string& accessToken) //throw SysError const char* htmlMessageTemplate = R""( - - TITLE_PLACEHOLDER - + + TITLE_PLACEHOLDER + -

TITLE_PLACEHOLDER

-
MESSAGE_PLACEHOLDER
+

TITLE_PLACEHOLDER

+
MESSAGE_PLACEHOLDER
)""; @@ -920,16 +920,18 @@ struct GoogleItemDetails { std::string itemName; bool isFolder = false; + bool isShared = false; uint64_t fileSize = 0; - time_t modTime = 0; + time_t modTime = 0; std::vector parentIds; }; bool operator==(const GoogleItemDetails& lhs, const GoogleItemDetails& rhs) { - return lhs.itemName == rhs.itemName && - lhs.isFolder == rhs.isFolder && - lhs.fileSize == rhs.fileSize && - lhs.modTime == rhs.modTime && + return lhs.itemName == rhs.itemName && + lhs.isFolder == rhs.isFolder && + lhs.isShared == rhs.isShared && + lhs.fileSize == rhs.fileSize && + lhs.modTime == rhs.modTime && lhs.parentIds == rhs.parentIds; } @@ -951,11 +953,10 @@ std::vector readFolderContent(const std::string& folderId, const std::string queryParams = xWwwFormUrlEncode( { { "spaces", "drive" }, // - { "corpora", "user" }, //"The 'user' corpus includes all files in "My Drive" and "Shared with me" https://developers.google.com/drive/api/v3/about-organization + { "corpora", "user" }, //"The 'user' corpus includes all files in "My Drive" and "Shared with me" https://developers.google.com/drive/api/v3/reference/files/list { "pageSize", "1000" }, //"[1, 1000] Default: 100" - { "fields", "nextPageToken,incompleteSearch,files(name,id,mimeType,size,modifiedTime,parents)" }, //https://developers.google.com/drive/api/v3/reference/files + { "fields", "nextPageToken,incompleteSearch,files(name,id,mimeType,shared,size,modifiedTime,parents)" }, //https://developers.google.com/drive/api/v3/reference/files { "q", "trashed=false and '" + folderId + "' in parents" }, - //{ "q", "sharedWithMe" }, }); if (nextPageToken) queryParams += '&' + xWwwFormUrlEncode({ { "pageToken", *nextPageToken } }); @@ -979,6 +980,7 @@ std::vector readFolderContent(const std::string& folderId, const const std::optional itemId = getPrimitiveFromJsonObject(*childVal, "id"); const std::optional itemName = getPrimitiveFromJsonObject(*childVal, "name"); const std::optional mimeType = getPrimitiveFromJsonObject(*childVal, "mimeType"); + const std::optional shared = getPrimitiveFromJsonObject(*childVal, "shared"); const std::optional size = getPrimitiveFromJsonObject(*childVal, "size"); const std::optional modifiedTime = getPrimitiveFromJsonObject(*childVal, "modifiedTime"); const JsonValue* parents = getChildFromJsonObject (*childVal, "parents"); @@ -987,22 +989,23 @@ std::vector readFolderContent(const std::string& folderId, const throw SysError(formatGoogleErrorRaw(response)); const bool isFolder = *mimeType == googleFolderMimeType; + const bool isShared = shared && *shared == "true"; //"Not populated for items in shared drives" const uint64_t fileSize = size ? stringTo(*size) : 0; //not available for folders //RFC 3339 date-time: e.g. "2018-09-29T08:39:12.053Z" const TimeComp tc = parseTime("%Y-%m-%dT%H:%M:%S", beforeLast(*modifiedTime, '.', IF_MISSING_RETURN_ALL)); if (tc == TimeComp() || !endsWith(*modifiedTime, 'Z')) //'Z' means "UTC" => it seems Google doesn't use the time-zone offset postfix - throw SysError(L"Modification time could not be parsed. (" + utfTo(*modifiedTime) + L")"); + throw SysError(L"Modification time could not be parsed. (" + utfTo(*modifiedTime) + L")"); time_t modTime = utcToTimeT(tc); //returns -1 on error if (modTime == -1) - { + { if (tc.year == 1600 || //zero-initialized FILETIME equals "December 31, 1600" or "January 1, 1601" tc.year == 1601) // => yes, possible even on Google Drive: https://freefilesync.org/forum/viewtopic.php?t=6602 modTime = 0; else - throw SysError(L"Modification time could not be parsed. (" + utfTo(*modifiedTime) + L")"); - } + throw SysError(L"Modification time could not be parsed. (" + utfTo(*modifiedTime) + L")"); + } std::vector parentIds; for (const auto& parentVal : parents->arrayVal) @@ -1013,7 +1016,7 @@ std::vector readFolderContent(const std::string& folderId, const } assert(std::find(parentIds.begin(), parentIds.end(), folderId) != parentIds.end()); - childItems.push_back({ *itemId, { *itemName, isFolder, fileSize, modTime, std::move(parentIds) } }); + childItems.push_back({ *itemId, { *itemName, isFolder, isShared, fileSize, modTime, std::move(parentIds) } }); } } while (nextPageToken); @@ -1045,7 +1048,7 @@ ChangesDelta getChangesDelta(const std::string& startPageToken, const std::strin { "pageSize", "1000" }, //"[1, 1000] Default: 100" { "restrictToMyDrive", "true" }, //important! otherwise we won't get "removed: true" (because file may still be accessible from other Corpora) { "spaces", "drive" }, - { "fields", "kind,nextPageToken,newStartPageToken,changes(kind,removed,fileId,file(name,mimeType,size,modifiedTime,parents,trashed))" }, + { "fields", "kind,nextPageToken,newStartPageToken,changes(kind,removed,fileId,file(name,mimeType,shared,size,modifiedTime,parents,trashed))" }, }); std::string response; @@ -1084,6 +1087,7 @@ ChangesDelta getChangesDelta(const std::string& startPageToken, const std::strin const std::optional itemName = getPrimitiveFromJsonObject(*file, "name"); const std::optional mimeType = getPrimitiveFromJsonObject(*file, "mimeType"); + const std::optional shared = getPrimitiveFromJsonObject(*file, "shared"); const std::optional size = getPrimitiveFromJsonObject(*file, "size"); const std::optional modifiedTime = getPrimitiveFromJsonObject(*file, "modifiedTime"); const std::optional trashed = getPrimitiveFromJsonObject(*file, "trashed"); @@ -1096,22 +1100,23 @@ ChangesDelta getChangesDelta(const std::string& startPageToken, const std::strin GoogleItemDetails itemDetails = {}; itemDetails.itemName = *itemName; itemDetails.isFolder = *mimeType == googleFolderMimeType; + itemDetails.isShared = shared && *shared == "true"; //"Not populated for items in shared drives" itemDetails.fileSize = size ? stringTo(*size) : 0; //not available for folders //RFC 3339 date-time: e.g. "2018-09-29T08:39:12.053Z" - const TimeComp tc = parseTime("%Y-%m-%dT%H:%M:%S", beforeLast(*modifiedTime, '.', IF_MISSING_RETURN_ALL)); - if (tc == TimeComp() || !endsWith(*modifiedTime, 'Z')) //'Z' means "UTC" => it seems Google doesn't use the time-zone offset postfix - throw SysError(L"Modification time could not be parsed. (" + utfTo(*modifiedTime) + L")"); - - itemDetails.modTime = utcToTimeT(tc); //returns -1 on error - if (itemDetails.modTime == -1) - { - if (tc.year == 1600 || //zero-initialized FILETIME equals "December 31, 1600" or "January 1, 1601" - tc.year == 1601) // => yes, possible even on Google Drive: https://freefilesync.org/forum/viewtopic.php?t=6602 - itemDetails.modTime = 0; - else - throw SysError(L"Modification time could not be parsed. (" + utfTo(*modifiedTime) + L")"); - } + const TimeComp tc = parseTime("%Y-%m-%dT%H:%M:%S", beforeLast(*modifiedTime, '.', IF_MISSING_RETURN_ALL)); + if (tc == TimeComp() || !endsWith(*modifiedTime, 'Z')) //'Z' means "UTC" => it seems Google doesn't use the time-zone offset postfix + throw SysError(L"Modification time could not be parsed. (" + utfTo(*modifiedTime) + L")"); + + itemDetails.modTime = utcToTimeT(tc); //returns -1 on error + if (itemDetails.modTime == -1) + { + if (tc.year == 1600 || //zero-initialized FILETIME equals "December 31, 1600" or "January 1, 1601" + tc.year == 1601) // => yes, possible even on Google Drive: https://freefilesync.org/forum/viewtopic.php?t=6602 + itemDetails.modTime = 0; + else + throw SysError(L"Modification time could not be parsed. (" + utfTo(*modifiedTime) + L")"); + } for (const auto& parentVal : parents->arrayVal) { @@ -1176,7 +1181,7 @@ void gdriveUnlinkParent(const std::string& itemId, const std::string& parentFold const std::string queryParams = xWwwFormUrlEncode( { { "removeParents", parentFolderId }, - { "fields", "id,parents"}, //for test if operation was successful + { "fields", "id,parents" }, //for test if operation was successful }); std::string response; googleHttpsRequest("/drive/v3/files/" + itemId + '?' + queryParams, //throw SysError @@ -1202,7 +1207,7 @@ void gdriveUnlinkParent(const std::string& itemId, const std::string& parentFold //- if item is a folder: trashes recursively!!! -//- a hardlink with multiple parents will be not be accessible anymore via any of its path aliases! +//- a hardlink with multiple parents will NOT be accessible anymore via any of its path aliases! void gdriveMoveToTrash(const std::string& itemId, const std::string& accessToken) //throw SysError { //https://developers.google.com/drive/api/v3/reference/files/update @@ -1228,11 +1233,11 @@ void gdriveMoveToTrash(const std::string& itemId, const std::string& accessToken std::string /*folderId*/ gdriveCreateFolderPlain(const Zstring& folderName, const std::string& parentFolderId, const std::string& accessToken) //throw SysError { //https://developers.google.com/drive/api/v3/folder#creating_a_folder - std::string postBuf = "{\n"; - postBuf += "\"mimeType\": \"" + std::string(googleFolderMimeType) + "\",\n"; - postBuf += "\"name\": \"" + utfTo(folderName) + "\",\n"; - postBuf += "\"parents\": [\"" + parentFolderId + "\"]\n"; //[!] no trailing comma! - postBuf += "}"; + const std::string& postBuf = std::string("{\n") + + "\"mimeType\": \"" + std::string(googleFolderMimeType) + "\",\n" + + "\"name\": \"" + utfTo(folderName) + "\",\n" + + "\"parents\": [\"" + parentFolderId + "\"]\n" + //[!] no trailing comma! + "}"; std::string response; googleHttpsRequest("/drive/v3/files?fields=id", { "Authorization: Bearer " + accessToken, "Content-Type: application/json; charset=UTF-8" }, @@ -1267,15 +1272,14 @@ void gdriveMoveAndRenameItem(const std::string& itemId, const std::string& paren //more Google Drive peculiarities: changing the file name changes modifiedTime!!! => workaround: //RFC 3339 date-time: e.g. "2018-09-29T08:39:12.053Z" - const std::string dateTime = formatTime("%Y-%m-%dT%H:%M:%S.000Z", getUtcTime(newModTime)); //returns empty string on failure - if (dateTime.empty()) + const std::string modTimeRfc = formatTime("%Y-%m-%dT%H:%M:%S.000Z", getUtcTime(newModTime)); //returns empty string on failure + if (modTimeRfc.empty()) throw SysError(L"Invalid modification time (time_t: " + numberTo(newModTime) + L")"); - std::string postBuf = "{\n"; - //postBuf += "\"name\": \"" + utfTo(newName) + "\"\n"; - postBuf += "\"name\": \"" + utfTo(newName) + "\",\n"; - postBuf += "\"modifiedTime\": \"" + dateTime + "\"\n"; //[!] no trailing comma! - postBuf += "}"; + const std::string& postBuf = std::string("{\n") + + "\"name\": \"" + utfTo(newName) + "\",\n" + + "\"modifiedTime\": \"" + modTimeRfc + "\"\n" + //[!] no trailing comma! + "}"; std::string response; googleHttpsRequest("/drive/v3/files/" + itemId + '?' + queryParams, //throw SysError @@ -1304,11 +1308,11 @@ void setModTime(const std::string& itemId, time_t modTime, const std::string& ac { //https://developers.google.com/drive/api/v3/reference/files/update //RFC 3339 date-time: e.g. "2018-09-29T08:39:12.053Z" - const std::string dateTime = formatTime("%Y-%m-%dT%H:%M:%S.000Z", getUtcTime(modTime)); //returns empty string on failure - if (dateTime.empty()) + const std::string& modTimeRfc = formatTime("%Y-%m-%dT%H:%M:%S.000Z", getUtcTime(modTime)); //returns empty string on failure + if (modTimeRfc.empty()) throw SysError(L"Invalid modification time (time_t: " + numberTo(modTime) + L")"); - const std::string postBuf = R"({ "modifiedTime": ")" + dateTime + "\" }"; + const std::string postBuf = R"({ "modifiedTime": ")" + modTimeRfc + "\" }"; std::string response; googleHttpsRequest("/drive/v3/files/" + itemId + "?fields=modifiedTime", //throw SysError @@ -1321,7 +1325,7 @@ void setModTime(const std::string& itemId, time_t modTime, const std::string& ac catch (const JsonParsingError&) {} const std::optional modifiedTime = getPrimitiveFromJsonObject(jresponse, "modifiedTime"); - if (!modifiedTime || *modifiedTime != dateTime) + if (!modifiedTime || *modifiedTime != modTimeRfc) throw SysError(formatGoogleErrorRaw(response)); } #endif @@ -1360,11 +1364,11 @@ std::string /*itemId*/ gdriveUploadSmallFile(const Zstring& fileName, const std: std::string metaDataBuf = "{\n"; if (modTime) //convert to RFC 3339 date-time: e.g. "2018-09-29T08:39:12.053Z" { - const std::string dateTime = formatTime("%Y-%m-%dT%H:%M:%S.000Z", getUtcTime(*modTime)); //returns empty string on failure - if (dateTime.empty()) + const std::string& modTimeRfc = formatTime("%Y-%m-%dT%H:%M:%S.000Z", getUtcTime(*modTime)); //returns empty string on failure + if (modTimeRfc.empty()) throw SysError(L"Invalid modification time (time_t: " + numberTo(*modTime) + L")"); - metaDataBuf += "\"modifiedTime\": \"" + dateTime + "\",\n"; + metaDataBuf += "\"modifiedTime\": \"" + modTimeRfc + "\",\n"; } metaDataBuf += "\"name\": \"" + utfTo(fileName) + "\",\n"; metaDataBuf += "\"parents\": [\"" + parentFolderId + "\"]\n"; //[!] no trailing comma! @@ -1454,79 +1458,79 @@ std::string /*itemId*/ gdriveUploadFile(const Zstring& fileName, const std::stri //https://developers.google.com/drive/api/v3/folder#inserting_a_file_in_a_folder //https://developers.google.com/drive/api/v3/resumable-upload - //step 1: initiate resumable upload session - std::string uploadUrlRelative; + //step 1: initiate resumable upload session + std::string uploadUrlRelative; + { + std::string postBuf = "{\n"; + if (modTime) //convert to RFC 3339 date-time: e.g. "2018-09-29T08:39:12.053Z" { - std::string postBuf = "{\n"; - if (modTime) //convert to RFC 3339 date-time: e.g. "2018-09-29T08:39:12.053Z" - { - const std::string dateTime = formatTime("%Y-%m-%dT%H:%M:%S.000Z", getUtcTime(*modTime)); //returns empty string on failure - if (dateTime.empty()) - throw SysError(L"Invalid modification time (time_t: " + numberTo(*modTime) + L")"); + const std::string& modTimeRfc = formatTime("%Y-%m-%dT%H:%M:%S.000Z", getUtcTime(*modTime)); //returns empty string on failure + if (modTimeRfc.empty()) + throw SysError(L"Invalid modification time (time_t: " + numberTo(*modTime) + L")"); - postBuf += "\"modifiedTime\": \"" + dateTime + "\",\n"; - } - postBuf += "\"name\": \"" + utfTo(fileName) + "\",\n"; - postBuf += "\"parents\": [\"" + parentFolderId + "\"]\n"; //[!] no trailing comma! - postBuf += "}"; + postBuf += "\"modifiedTime\": \"" + modTimeRfc + "\",\n"; + } + postBuf += "\"name\": \"" + utfTo(fileName) + "\",\n"; + postBuf += "\"parents\": [\"" + parentFolderId + "\"]\n"; //[!] no trailing comma! + postBuf += "}"; - std::string uploadUrl; + std::string uploadUrl; - auto onBytesReceived = [&](const char* buffer, size_t len) - { - //inside libcurl's C callstack => better not throw exceptions here!!! - //"The callback will be called once for each header and only complete header lines are passed on to the callback" (including \r\n at the end) - if (startsWithAsciiNoCase(std::string_view(buffer, len), "Location:")) - { - uploadUrl.assign(buffer, len); //not null-terminated! - uploadUrl = afterFirst(uploadUrl, ':', IF_MISSING_RETURN_NONE); - trim(uploadUrl); - } - return len; - }; - using ReadCbType = decltype(onBytesReceived); - using ReadCbWrapperType = size_t (*)(const char* buffer, size_t size, size_t nitems, ReadCbType* callbackData); //needed for cdecl function pointer cast - ReadCbWrapperType onBytesReceivedWrapper = [](const char* buffer, size_t size, size_t nitems, ReadCbType* callbackData) + auto onBytesReceived = [&](const char* buffer, size_t len) + { + //inside libcurl's C callstack => better not throw exceptions here!!! + //"The callback will be called once for each header and only complete header lines are passed on to the callback" (including \r\n at the end) + if (startsWithAsciiNoCase(std::string_view(buffer, len), "Location:")) { - return (*callbackData)(buffer, size * nitems); //free this poor little C-API from its shackles and redirect to a proper lambda - }; + uploadUrl.assign(buffer, len); //not null-terminated! + uploadUrl = afterFirst(uploadUrl, ':', IF_MISSING_RETURN_NONE); + trim(uploadUrl); + } + return len; + }; + using ReadCbType = decltype(onBytesReceived); + using ReadCbWrapperType = size_t (*)(const char* buffer, size_t size, size_t nitems, ReadCbType* callbackData); //needed for cdecl function pointer cast + ReadCbWrapperType onBytesReceivedWrapper = [](const char* buffer, size_t size, size_t nitems, ReadCbType* callbackData) + { + return (*callbackData)(buffer, size * nitems); //free this poor little C-API from its shackles and redirect to a proper lambda + }; - std::string response; - const HttpSession::HttpResult httpResult = googleHttpsRequest("/upload/drive/v3/files?uploadType=resumable", //throw SysError - { "Authorization: Bearer " + accessToken, "Content-Type: application/json; charset=UTF-8" }, - { { CURLOPT_POSTFIELDS, postBuf.c_str() }, { CURLOPT_HEADERDATA, &onBytesReceived }, { CURLOPT_HEADERFUNCTION, onBytesReceivedWrapper } }, - [&](const void* buffer, size_t bytesToWrite) { response.append(static_cast(buffer), bytesToWrite); }, nullptr /*readRequest*/); + std::string response; + const HttpSession::HttpResult httpResult = googleHttpsRequest("/upload/drive/v3/files?uploadType=resumable", //throw SysError + { "Authorization: Bearer " + accessToken, "Content-Type: application/json; charset=UTF-8" }, + { { CURLOPT_POSTFIELDS, postBuf.c_str() }, { CURLOPT_HEADERDATA, &onBytesReceived }, { CURLOPT_HEADERFUNCTION, onBytesReceivedWrapper } }, + [&](const void* buffer, size_t bytesToWrite) { response.append(static_cast(buffer), bytesToWrite); }, nullptr /*readRequest*/); - if (httpResult.statusCode != 200) - throw SysError(formatGoogleErrorRaw(response)); + if (httpResult.statusCode != 200) + throw SysError(formatGoogleErrorRaw(response)); - if (!startsWith(uploadUrl, "https://www.googleapis.com/")) - throw SysError(L"Invalid upload URL: " + utfTo(uploadUrl)); //user should never see this + if (!startsWith(uploadUrl, "https://www.googleapis.com/")) + throw SysError(L"Invalid upload URL: " + utfTo(uploadUrl)); //user should never see this - uploadUrlRelative = afterFirst(uploadUrl, "googleapis.com", IF_MISSING_RETURN_NONE); - } - //--------------------------------------------------- - //step 2: upload file content + uploadUrlRelative = afterFirst(uploadUrl, "googleapis.com", IF_MISSING_RETURN_NONE); + } + //--------------------------------------------------- + //step 2: upload file content - //not officially documented, but Google Drive supports compressed file upload when "Content-Encoding: gzip" is set! :))) - InputStreamAsGzip gzipStream(readBlock); //throw SysError + //not officially documented, but Google Drive supports compressed file upload when "Content-Encoding: gzip" is set! :))) + InputStreamAsGzip gzipStream(readBlock); //throw SysError - auto readBlockAsGzip = [&](void* buffer, size_t bytesToRead) { return gzipStream.read(buffer, bytesToRead); }; //throw SysError, X - //returns "bytesToRead" bytes unless end of stream! => fits into "0 signals EOF: Posix read() semantics" + auto readBlockAsGzip = [&](void* buffer, size_t bytesToRead) { return gzipStream.read(buffer, bytesToRead); }; //throw SysError, X + //returns "bytesToRead" bytes unless end of stream! => fits into "0 signals EOF: Posix read() semantics" - std::string response; - googleHttpsRequest(uploadUrlRelative, { "Content-Encoding: gzip" }, {} /*extraOptions*/, //throw SysError, X - [&](const void* buffer, size_t bytesToWrite) { response.append(static_cast(buffer), bytesToWrite); }, readBlockAsGzip); + std::string response; + googleHttpsRequest(uploadUrlRelative, { "Content-Encoding: gzip" }, {} /*extraOptions*/, //throw SysError, X + [&](const void* buffer, size_t bytesToWrite) { response.append(static_cast(buffer), bytesToWrite); }, readBlockAsGzip); - JsonValue jresponse; - try { jresponse = parseJson(response); } - catch (JsonParsingError&) {} + JsonValue jresponse; + try { jresponse = parseJson(response); } + catch (JsonParsingError&) {} - const std::optional itemId = getPrimitiveFromJsonObject(jresponse, "id"); - if (!itemId) - throw SysError(formatGoogleErrorRaw(response)); + const std::optional itemId = getPrimitiveFromJsonObject(jresponse, "id"); + if (!itemId) + throw SysError(formatGoogleErrorRaw(response)); - return *itemId; + return *itemId; } @@ -1612,35 +1616,42 @@ public: rootId_ (getRootItemId (accessBuf.getAccessToken())), //throw SysError accessBuf_(accessBuf) {} // - GoogleFileState(MemoryStreamIn& stream, GoogleAccessBuffer& accessBuf) : accessBuf_(accessBuf) //throw UnexpectedEndOfStreamError + GoogleFileState(MemoryStreamIn& stream, GoogleAccessBuffer& accessBuf, int dbVersion) : accessBuf_(accessBuf) //throw UnexpectedEndOfStreamError { lastSyncToken_ = readContainer(stream); //UnexpectedEndOfStreamError - rootId_ = readContainer(stream); //UnexpectedEndOfStreamError + rootId_ = readContainer(stream); // - for (;;) + //TODO: remove migration code at some time! 2019-12-05 + if (dbVersion == 1) + ; //fully discard old state due to missing "isShared" attribute :( + else { - const std::string folderId = readContainer(stream); //UnexpectedEndOfStreamError - if (folderId.empty()) - break; - folderContents_[folderId].isKnownFolder = true; - } + for (;;) + { + const std::string folderId = readContainer(stream); //UnexpectedEndOfStreamError + if (folderId.empty()) + break; + folderContents_[folderId].isKnownFolder = true; + } - size_t itemCount = readNumber(stream); - while (itemCount-- != 0) - { - const std::string itemId = readContainer(stream); //UnexpectedEndOfStreamError + size_t itemCount = readNumber(stream); + while (itemCount-- != 0) + { + const std::string itemId = readContainer(stream); //UnexpectedEndOfStreamError - GoogleItemDetails details = {}; - details.itemName = readContainer(stream); // - details.isFolder = readNumber (stream) != 0; //UnexpectedEndOfStreamError - details.fileSize = readNumber (stream); // - details.modTime = readNumber (stream); // + GoogleItemDetails details = {}; + details.itemName = readContainer(stream); // + details.isFolder = readNumber (stream) != 0; // + details.isShared = readNumber (stream) != 0; //UnexpectedEndOfStreamError + details.fileSize = readNumber (stream); // + details.modTime = readNumber (stream); // - size_t parentsCount = readNumber(stream); //UnexpectedEndOfStreamError - while (parentsCount-- != 0) - details.parentIds.push_back(readContainer(stream)); //UnexpectedEndOfStreamError + size_t parentsCount = readNumber(stream); //UnexpectedEndOfStreamError + while (parentsCount-- != 0) + details.parentIds.push_back(readContainer(stream)); //UnexpectedEndOfStreamError - updateItemState(itemId, std::move(details)); + updateItemState(itemId, std::move(details)); + } } } @@ -1662,6 +1673,7 @@ public: writeContainer(stream, itemId); writeContainer(stream, details.itemName); writeNumber< int8_t>(stream, details.isFolder); + writeNumber< int8_t>(stream, details.isShared); writeNumber(stream, details.fileSize); writeNumber< int64_t>(stream, details.modTime); static_assert(sizeof(details.modTime) <= sizeof(int64_t)); //ensure cross-platform compatibility! @@ -1755,12 +1767,12 @@ public: GoogleItemDetails details = {}; details.itemName = utfTo(folderName); details.isFolder = true; + details.isShared = false; details.modTime = std::time(nullptr); details.parentIds.push_back(parentId); //avoid needless conflicts due to different Google Drive folder modTime! - auto it = itemDetails_.find(folderId); - if (it != itemDetails_.end()) + if (auto it = itemDetails_.find(folderId); it != itemDetails_.end()) details.modTime = it->second.modTime; notifyItemUpdate(stateDelta, folderId, details); @@ -1773,8 +1785,7 @@ public: void notifyParentRemoved(const FileStateDelta& stateDelta, const std::string& itemId, const std::string& parentIdOld) { - auto it = itemDetails_.find(itemId); - if (it != itemDetails_.end()) + if (auto it = itemDetails_.find(itemId); it != itemDetails_.end()) { GoogleItemDetails detailsNew = it->second; std::erase_if(detailsNew.parentIds, [&](const std::string& id) { return id == parentIdOld; }); @@ -1786,8 +1797,7 @@ public: void notifyMoveAndRename(const FileStateDelta& stateDelta, const std::string& itemId, const std::string& parentIdFrom, const std::string& parentIdTo, const Zstring& newName) { - auto it = itemDetails_.find(itemId); - if (it != itemDetails_.end()) + if (auto it = itemDetails_.find(itemId); it != itemDetails_.end()) { GoogleItemDetails detailsNew = it->second; detailsNew.itemName = utfTo(newName); @@ -1809,8 +1819,8 @@ private: void notifyItemUpdate(const FileStateDelta& stateDelta, const std::string& itemId, const std::optional& details) { - if (stateDelta.changedIds->find(itemId) == stateDelta.changedIds->end()) //=> no conflicting changes in the meantime - updateItemState(itemId, details); //accept new state data + if (!contains(*stateDelta.changedIds, itemId)) //no conflicting changes in the meantime? + updateItemState(itemId, details); //=> accept new state data else //conflict? { auto it = itemDetails_.find(itemId); @@ -1896,7 +1906,6 @@ private: void updateItemState(const std::string& itemId, const std::optional& details) { auto it = itemDetails_.find(itemId); - if (!details == (it == itemDetails_.end())) if (!details || *details == it->second) //notified changes match our current file state return; //=> avoid misleading changeLog_ entries after Google Drive sync!!! @@ -1930,11 +1939,8 @@ private: folderContents_[parentId].childItems.push_back(it); //new insert => no need for duplicate check for (const std::string& parentId : parentIdsRemoved) - { - auto itP = folderContents_.find(parentId); - if (itP != folderContents_.end()) + if (auto itP = folderContents_.find(parentId); itP != folderContents_.end()) std::erase_if(itP->second.childItems, [&](auto itChild) { return itChild == it; }); - } //if all parents are removed, Google Drive will (recursively) delete the item => don't prematurely do this now: wait for change notifications! it->second = *details; @@ -1952,16 +1958,13 @@ private: if (it != itemDetails_.end()) { for (const std::string& parentId : it->second.parentIds) //1. delete from parent folders - { - auto itP = folderContents_.find(parentId); - if (itP != folderContents_.end()) + if (auto itP = folderContents_.find(parentId); itP != folderContents_.end()) std::erase_if(itP->second.childItems, [&](auto itChild) { return itChild == it; }); - } + itemDetails_.erase(it); } - auto itP = folderContents_.find(itemId); - if (itP != folderContents_.end()) + if (auto itP = folderContents_.find(itemId); itP != folderContents_.end()) { for (auto itChild : itP->second.childItems) //2. delete as parent from child items (don't wait for change notifications of children) std::erase_if(itChild->second.parentIds, [&](const std::string& id) { return id == itemId; }); @@ -2229,24 +2232,30 @@ private: { rawStream = decompress(zstream); //throw SysError } - catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(dbFilePath)), e.toString()); } + catch (const SysError& e) { throw FileError(_("Database file is corrupted:") + L" " + fmtPath(dbFilePath), e.toString()); } MemoryStreamIn streamIn(rawStream); try { + //-------- file format header -------- char tmp[sizeof(DB_FORMAT_DESCR)] = {}; - readArray(streamIn, &tmp, sizeof(tmp)); //file format header - const int fileVersion = readNumber(streamIn); // + readArray(streamIn, &tmp, sizeof(tmp)); //throw UnexpectedEndOfStreamError + + if (!std::equal(std::begin(tmp), std::end(tmp), std::begin(DB_FORMAT_DESCR))) + throw FileError(replaceCpy(_("Database file %x is incompatible."), L"%x", fmtPath(dbFilePath))); + + const int dbVersion = readNumber(streamIn); - if (!std::equal(std::begin(tmp), std::end(tmp), std::begin(DB_FORMAT_DESCR)) || - fileVersion != DB_FORMAT_VER) - throw UnexpectedEndOfStreamError(); //well, not really...!? + //TODO: remove migration code at some time! 2019-12-05 + if (dbVersion != 1 && + dbVersion != DB_FORMAT_VER) + throw FileError(replaceCpy(_("Database file %x is incompatible."), L"%x", fmtPath(dbFilePath))); - auto accessBuf = makeSharedRef(streamIn); //throw UnexpectedEndOfStreamError - auto fileState = makeSharedRef(streamIn, accessBuf.ref()); //throw UnexpectedEndOfStreamError + auto accessBuf = makeSharedRef(streamIn); //throw UnexpectedEndOfStreamError + auto fileState = makeSharedRef(streamIn, accessBuf.ref(), dbVersion); //throw UnexpectedEndOfStreamError return { accessBuf, fileState }; } - catch (UnexpectedEndOfStreamError&) { throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(dbFilePath)), L"Unexpected end of stream."); } + catch (UnexpectedEndOfStreamError&) { throw FileError(_("Database file is corrupted:") + L" " + fmtPath(dbFilePath), L"Unexpected end of stream."); } } struct UserSession @@ -2447,10 +2456,10 @@ struct InputStreamGdrive : public AbstractFileSystem::InputStream { accessGlobalFileState(gdrivePath_.userEmail, [&](GoogleFileState& fileState) //throw SysError { - std::pair gdriveAttr = fileState.getFileAttributes(gdrivePath_.itemPath); //throw SysError - attr.modTime = gdriveAttr.second.modTime; - attr.fileSize = gdriveAttr.second.fileSize; - attr.fileId = copyStringTo(gdriveAttr.first); + const auto& [itemId, gdriveAttr] = fileState.getFileAttributes(gdrivePath_.itemPath); //throw SysError + attr.modTime = gdriveAttr.modTime; + attr.fileSize = gdriveAttr.fileSize; + attr.fileId = copyStringTo(itemId); }); } catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(getGoogleDisplayPath(gdrivePath_))), e.toString()); } @@ -2530,6 +2539,7 @@ struct OutputStreamGdrive : public AbstractFileSystem::OutputStreamImpl newFileItem.itemId = fileIdNew; newFileItem.details.itemName = utfTo(fileName); newFileItem.details.isFolder = false; + newFileItem.details.isShared = false; newFileItem.details.fileSize = asyncStreamIn->getTotalBytesRead(); if (modTime) //else: whatever modTime Google Drive selects will be notified after GOOGLE_DRIVE_SYNC_INTERVAL newFileItem.details.modTime = *modTime; @@ -2678,7 +2688,7 @@ private: catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot create directory %x."), L"%x", fmtPath(getDisplayPath(afsPath))), e.toString()); } } - void removeItemPlainImpl(const AfsPath& afsPath) const //throw SysError + void removeItemPlainImpl(const AfsPath& afsPath, bool permanent /*...or move to trash*/) const //throw SysError { std::string itemId; std::optional parentIdToUnlink; @@ -2687,12 +2697,12 @@ private: const std::optional parentPath = getParentPath(afsPath); if (!parentPath) throw SysError(L"Item is device root"); - std::pair gdriveAttr = fileState.getFileAttributes(afsPath); //throw SysError - itemId = gdriveAttr.first; - assert(gdriveAttr.second.parentIds.size() > 1 || - (gdriveAttr.second.parentIds.size() == 1 && gdriveAttr.second.parentIds[0] == fileState.getItemId(*parentPath))); + GoogleItemDetails gdriveAttr; + std::tie(itemId, gdriveAttr) = fileState.getFileAttributes(afsPath); //throw SysError + assert(std::find(gdriveAttr.parentIds.begin(), gdriveAttr.parentIds.end(), fileState.getItemId(*parentPath)) != gdriveAttr.parentIds.end()); - if (gdriveAttr.second.parentIds.size() != 1) //hard-link handling + //hard-link handling applies to shared files as well: 1. it's the right thing (TM) 2. deleting would fail anyway because we're not the owner + if (gdriveAttr.parentIds.size() > 1 || gdriveAttr.isShared) parentIdToUnlink = fileState.getItemId(*parentPath); //throw SysError }); @@ -2708,7 +2718,10 @@ private: } else { - gdriveDeleteItem(itemId, aai.accessToken); //throw SysError + if (permanent) + gdriveDeleteItem(itemId, aai.accessToken); //throw SysError + else + gdriveMoveToTrash(itemId, aai.accessToken); //throw SysError //buffer new file state ASAP (don't wait GOOGLE_DRIVE_SYNC_INTERVAL) accessGlobalFileState(googleUserEmail_, [&](GoogleFileState& fileState) //throw SysError @@ -2722,7 +2735,7 @@ private: { try { - removeItemPlainImpl(afsPath); //throw SysError + removeItemPlainImpl(afsPath, true /*permanent*/); //throw SysError } catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot delete file %x."), L"%x", fmtPath(getDisplayPath(afsPath))), e.toString()); } } @@ -2736,7 +2749,7 @@ private: { try { - removeItemPlainImpl(afsPath); //throw SysError + removeItemPlainImpl(afsPath, true /*permanent*/); //throw SysError } catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtPath(getDisplayPath(afsPath))), e.toString()); } } @@ -2753,9 +2766,8 @@ private: } catch (const FileError&) { - if (!itemStillExists(afsPath)) //throw FileError - return; - throw; + if (itemStillExists(afsPath)) //throw FileError + throw; } } @@ -2858,9 +2870,10 @@ private: std::string parentIdTo; const GooglePersistentSessions::AsyncAccessInfo aai = accessGlobalFileState(googleUserEmail_, [&](GoogleFileState& fileState) //throw SysError { - std::pair gdriveAttr = fileState.getFileAttributes(pathFrom); //throw SysError - itemIdFrom = gdriveAttr.first; - modTimeFrom = gdriveAttr.second.modTime; + GoogleItemDetails gdriveAttr; + std::tie(itemIdFrom, gdriveAttr) = fileState.getFileAttributes(pathFrom); //throw SysError + + modTimeFrom = gdriveAttr.modTime; parentIdFrom = fileState.getItemId(*parentPathFrom); //throw SysError GoogleFileState::PathStatus psTo = fileState.getPathStatus(pathTo.afsPath); //throw SysError @@ -2937,13 +2950,14 @@ private: bool supportsRecycleBin(const AfsPath& afsPath) const override { return true; } //throw FileError - struct RecycleSessionGdrive : public RecycleSession - { - void recycleItemIfExists(const AbstractPath& itemPath, const Zstring& logicalRelPath) override { AFS::recycleItemIfExists(itemPath); } //throw FileError - void tryCleanup(const std::function& notifyDeletionStatus) override {}; //throw FileError - }; std::unique_ptr createRecyclerSession(const AfsPath& afsPath) const override //throw FileError, return value must be bound! { + struct RecycleSessionGdrive : public RecycleSession + { + void recycleItemIfExists(const AbstractPath& itemPath, const Zstring& logicalRelPath) override { AFS::recycleItemIfExists(itemPath); } //throw FileError + void tryCleanup(const std::function& notifyDeletionStatus) override {}; //throw FileError + }; + return std::make_unique(); } @@ -2951,24 +2965,13 @@ private: { try { - GoogleFileState::PathStatus ps; - const GooglePersistentSessions::AsyncAccessInfo aai = accessGlobalFileState(googleUserEmail_, [&](GoogleFileState& fileState) //throw SysError - { - ps = fileState.getPathStatus(afsPath); //throw SysError - }); - if (ps.relPath.empty()) - { - gdriveMoveToTrash(ps.existingItemId, aai.accessToken); //throw SysError - - //buffer new file state ASAP (don't wait GOOGLE_DRIVE_SYNC_INTERVAL) - accessGlobalFileState(googleUserEmail_, [&](GoogleFileState& fileState) //throw SysError - { - //a hardlink with multiple parents will be not be accessible anymore via any of its path aliases! - fileState.notifyItemDeleted(aai.stateDelta, ps.existingItemId); - }); - } + removeItemPlainImpl(afsPath, false /*permanent*/); //throw SysError + } + catch (const SysError& e) + { + if (itemStillExists(afsPath)) //throw FileError + throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtPath(getDisplayPath(afsPath))), e.toString()); } - catch (const SysError& e) { throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtPath(getDisplayPath(afsPath))), e.toString()); } } const Zstring googleUserEmail_; @@ -3059,10 +3062,10 @@ GdrivePath fff::getResolvedGooglePath(const Zstring& folderPathPhrase) //noexcep if (startsWithAsciiNoCase(path, googleDrivePrefix)) path = path.c_str() + strLength(googleDrivePrefix); - const AfsPath sanPath = sanitizeRootRelativePath(path); //Win/macOS compatibility: let's ignore slash/backslash differences + const AfsPath& sanPath = sanitizeRootRelativePath(path); //Win/macOS compatibility: let's ignore slash/backslash differences - const Zstring userEmail = beforeFirst(sanPath.value, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL); - const AfsPath afsPath (afterFirst(sanPath.value, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE)); + const Zstring& userEmail = beforeFirst(sanPath.value, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL); + const AfsPath afsPath (afterFirst(sanPath.value, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE)); return { userEmail, afsPath }; } @@ -3078,6 +3081,6 @@ bool fff::acceptsItemPathPhraseGdrive(const Zstring& itemPathPhrase) //noexcept AbstractPath fff::createItemPathGdrive(const Zstring& itemPathPhrase) //noexcept { - const GdrivePath gdrivePath = getResolvedGooglePath(itemPathPhrase); //noexcept + const GdrivePath& gdrivePath = getResolvedGooglePath(itemPathPhrase); //noexcept return AbstractPath(makeSharedRef(gdrivePath.userEmail), gdrivePath.itemPath); } diff --git a/FreeFileSync/Source/afs/native.cpp b/FreeFileSync/Source/afs/native.cpp index 937523fc..da016788 100644 --- a/FreeFileSync/Source/afs/native.cpp +++ b/FreeFileSync/Source/afs/native.cpp @@ -670,7 +670,7 @@ bool fff::acceptsItemPathPhraseNative(const Zstring& itemPathPhrase) //noexcept AbstractPath fff::createItemPathNative(const Zstring& itemPathPhrase) //noexcept { //TODO: get volume by name hangs for idle HDD! => run createItemPathNative during getFolderStatusNonBlocking() but getResolvedFilePath currently not thread-safe! - const Zstring itemPath = getResolvedFilePath(itemPathPhrase); + const Zstring& itemPath = getResolvedFilePath(itemPathPhrase); return createItemPathNativeNoFormatting(itemPath); } diff --git a/FreeFileSync/Source/afs/sftp.cpp b/FreeFileSync/Source/afs/sftp.cpp index 163df3a5..1fcedc43 100644 --- a/FreeFileSync/Source/afs/sftp.cpp +++ b/FreeFileSync/Source/afs/sftp.cpp @@ -2004,6 +2004,6 @@ bool fff::acceptsItemPathPhraseSftp(const Zstring& itemPathPhrase) //noexcept AbstractPath fff::createItemPathSftp(const Zstring& itemPathPhrase) //noexcept { - const SftpPathInfo pi = getResolvedSftpPath(itemPathPhrase); //noexcept + const SftpPathInfo& pi = getResolvedSftpPath(itemPathPhrase); //noexcept return AbstractPath(makeSharedRef(pi.login), pi.afsPath); } diff --git a/FreeFileSync/Source/base/application.cpp b/FreeFileSync/Source/base/application.cpp index d032955b..d66b08ff 100644 --- a/FreeFileSync/Source/base/application.cpp +++ b/FreeFileSync/Source/base/application.cpp @@ -132,6 +132,9 @@ int Application::OnExit() } +wxLayoutDirection Application::GetLayoutDirection() const { return getLayoutDirection(); } + + void Application::onEnterEventLoop(wxEvent& event) { Disconnect(EVENT_ENTER_EVENT_LOOP, wxEventHandler(Application::onEnterEventLoop), nullptr, this); diff --git a/FreeFileSync/Source/base/application.h b/FreeFileSync/Source/base/application.h index c08491c8..a52e6617 100644 --- a/FreeFileSync/Source/base/application.h +++ b/FreeFileSync/Source/base/application.h @@ -23,7 +23,7 @@ private: int OnExit() override; bool OnExceptionInMainLoop() override { throw; } //just re-throw and avoid display of additional messagebox: it will be caught in OnRun() void OnUnhandledException () override { throw; } //just re-throw and avoid display of additional messagebox - + wxLayoutDirection GetLayoutDirection() const override; void onEnterEventLoop(wxEvent& event); void onQueryEndSession(wxEvent& event); void launch(const std::vector& commandArgs); diff --git a/FreeFileSync/Source/base/config.cpp b/FreeFileSync/Source/base/config.cpp index 3ed3f416..552b377f 100644 --- a/FreeFileSync/Source/base/config.cpp +++ b/FreeFileSync/Source/base/config.cpp @@ -11,18 +11,17 @@ #include #include #include "ffs_paths.h" -#include "../afs/concrete.h" +//#include "../afs/concrete.h" using namespace zen; using namespace fff; //functionally needed for correct overload resolution!!! -//using AFS = AbstractFileSystem; namespace { //------------------------------------------------------------------------------------------------------------------------------- -const int XML_FORMAT_GLOBAL_CFG = 14; //2019-11-19 +const int XML_FORMAT_GLOBAL_CFG = 15; //2019-11-30 const int XML_FORMAT_SYNC_CFG = 14; //2018-08-13 //------------------------------------------------------------------------------------------------------------------------------- } @@ -106,20 +105,24 @@ XmlBatchConfig fff::convertGuiToBatch(const XmlGuiConfig& guiCfg, const BatchExc namespace { -std::vector splitFilterByLines(const Zstring& filterPhrase) +std::vector splitFilterByLines(Zstring filterPhrase) { + trim(filterPhrase); if (filterPhrase.empty()) return {}; + return split(filterPhrase, Zstr('\n'), SplitType::ALLOW_EMPTY); } Zstring mergeFilterLines(const std::vector& filterLines) { - if (filterLines.empty()) - return Zstring(); - Zstring out = filterLines[0]; - std::for_each(filterLines.begin() + 1, filterLines.end(), [&](const Zstring& line) { out += Zstr('\n'); out += line; }); - return out; + Zstring out; + for (const Zstring& line : filterLines) + { + out += line; + out += Zstr('\n'); + } + return trimCpy(out); } } @@ -1562,20 +1565,18 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer) for (const ConfigFileItemV9& item : cfgFileHistory) cfg.gui.mainDlg.cfgFileHistory.emplace_back(item.filePath, item.lastSyncTime, getNullPath(), SyncResult::finishedSuccess, wxNullColour); } - //TODO: remove after migration! 2019-11-19 - else if (formatVer < 14) + else { inConfig["Configurations"].attribute("MaxSize", cfg.gui.mainDlg.cfgHistItemsMax); inConfig["Configurations"](cfg.gui.mainDlg.cfgFileHistory); - - for (ConfigFileItem& item : cfg.gui.mainDlg.cfgFileHistory) - if (equalNativePath(item.cfgFilePath, getLastRunConfigPath())) - item.backColor = wxColor(0xdd, 0xdd, 0xdd); //light grey from onCfgGridContext() } - else + //TODO: remove after migration! 2019-11-30 + if (formatVer < 15) { - inConfig["Configurations"].attribute("MaxSize", cfg.gui.mainDlg.cfgHistItemsMax); - inConfig["Configurations"](cfg.gui.mainDlg.cfgFileHistory); + const Zstring lastRunConfigPath = getConfigDirPathPf() + Zstr("LastRun.ffs_gui"); + for (ConfigFileItem& item : cfg.gui.mainDlg.cfgFileHistory) + if (equalNativePath(item.cfgFilePath, lastRunConfigPath)) + item.backColor = wxColor(0xdd, 0xdd, 0xdd); //light grey from onCfgGridContext() } //TODO: remove parameter migration after some time! 2018-01-08 @@ -1675,18 +1676,65 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer) else inWnd["Perspective"](cfg.gui.mainDlg.guiPerspectiveLast); + //TODO: remove after migration! 2019-11-30 + auto splitEditMerge = [](wxString& perspective, wchar_t delim, const std::function& editItem) + { + std::vector v = split(perspective, delim, SplitType::ALLOW_EMPTY); + assert(!v.empty()); + perspective.clear(); + + std::for_each(v.begin(), v.end() - 1, [&](wxString& item) + { + editItem(item); + perspective += item; + perspective += delim; + }); + editItem(v.back()); + perspective += v.back(); + }; + //TODO: remove after migration! 2018-07-27 if (formatVer < 10) + splitEditMerge(cfg.gui.mainDlg.guiPerspectiveLast, L'|', [&](wxString& paneCfg) + { + if (contains(paneCfg, L"name=TopPanel")) + replace(paneCfg, L";row=2;", L";row=3;"); + }); + + //TODO: remove after migration! 2019-11-30 + if (formatVer < 15) { - wxString newPersp; - for (wxString& item : split(cfg.gui.mainDlg.guiPerspectiveLast, L"|", SplitType::SKIP_EMPTY)) + //set minimal TopPanel height => search and set actual height to 0 and let MainDialog's min-size handling kick in: + std::optional tpDir; + std::optional tpLayer; + std::optional tpRow; + splitEditMerge(cfg.gui.mainDlg.guiPerspectiveLast, L'|', [&](wxString& paneCfg) { - if (contains(item, L"name=SearchPanel;")) - replace(item, L";row=2;", L";row=3;"); + if (contains(paneCfg, L"name=TopPanel")) + splitEditMerge(paneCfg, L';', [&](wxString& paneAttr) + { + if (startsWith(paneAttr, L"dir=")) + tpDir = stringTo(afterFirst(paneAttr, L'=', IF_MISSING_RETURN_NONE)); + else if (startsWith(paneAttr, L"layer=")) + tpLayer = stringTo(afterFirst(paneAttr, L'=', IF_MISSING_RETURN_NONE)); + else if (startsWith(paneAttr, L"row=")) + tpRow = stringTo(afterFirst(paneAttr, L'=', IF_MISSING_RETURN_NONE)); + }); + }); + + if (tpDir && tpLayer && tpRow) + { + const wxString tpSize = L"dock_size(" + + numberTo(*tpDir ) + L"," + + numberTo(*tpLayer) + L"," + + numberTo(*tpRow ) + L")="; - newPersp += (newPersp.empty() ? L"" : L"|") + item; + splitEditMerge(cfg.gui.mainDlg.guiPerspectiveLast, L'|', [&](wxString& paneCfg) + { + if (startsWith(paneCfg, tpSize)) + paneCfg = tpSize + L"0"; + }); } - cfg.gui.mainDlg.guiPerspectiveLast = newPersp; } std::vector tmp = splitFilterByLines(cfg.gui.defaultExclusionFilter); //default value @@ -1761,6 +1809,13 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer) //TODO: remove macro migration after some time! 2016-07-18 for (ExternalApp& item : cfg.gui.externalApps) replace(item.cmdLine, Zstr("%item_folder%"), Zstr("%folder_path%")); + //TODO: remove after migration! 2019-11-30 + if (formatVer < 15) + for (ExternalApp& item : cfg.gui.externalApps) + { + replace(item.cmdLine, Zstr("%folder_path%"), Zstr("%parent_path%")); + replace(item.cmdLine, Zstr("%folder_path2%"), Zstr("%parent_path2%")); + } //last update check inGui["LastOnlineCheck" ](cfg.gui.lastUpdateCheck); diff --git a/FreeFileSync/Source/base/config.h b/FreeFileSync/Source/base/config.h index 89edfeb9..14ea2565 100644 --- a/FreeFileSync/Source/base/config.h +++ b/FreeFileSync/Source/base/config.h @@ -250,7 +250,7 @@ struct XmlGlobalSettings { //default external app descriptions will be translated "on the fly"!!! //CONTRACT: first entry will be used for [Enter] or mouse double-click! - { L"Browse directory", Zstr("xdg-open \"%folder_path%\"") }, + { L"Browse directory", Zstr("xdg-open \"%parent_path%\"") }, { L"Open with default application", Zstr("xdg-open \"%local_path%\"") }, //mark for extraction: _("Browse directory") Linux doesn't use the term "folder" }; diff --git a/FreeFileSync/Source/base/db_file.cpp b/FreeFileSync/Source/base/db_file.cpp index c7ad54d5..aba2947f 100644 --- a/FreeFileSync/Source/base/db_file.cpp +++ b/FreeFileSync/Source/base/db_file.cpp @@ -106,7 +106,7 @@ DbStreams loadStreams(const AbstractPath& dbPath, const IOCallback& notifyUnbuff //TODO: remove migration code at some time! 2017-02-01 if (version != 9 && - version != DB_FORMAT_CONTAINER) //read file format version number + version != DB_FORMAT_CONTAINER) throw FileError(replaceCpy(_("Database file %x is incompatible."), L"%x", fmtPath(AFS::getDisplayPath(dbPath)))); DbStreams output; @@ -154,11 +154,11 @@ DbStreams loadStreams(const AbstractPath& dbPath, const IOCallback& notifyUnbuff } catch (UnexpectedEndOfStreamError&) { - throw FileError(_("Database file is corrupted:") + L"\n" + fmtPath(AFS::getDisplayPath(dbPath)), L"Unexpected end of stream."); + throw FileError(_("Database file is corrupted:") + L" " + fmtPath(AFS::getDisplayPath(dbPath)), L"Unexpected end of stream."); } catch (const std::bad_alloc& e) //still required? { - throw FileError(_("Database file is corrupted:") + L"\n" + fmtPath(AFS::getDisplayPath(dbPath)), + throw FileError(_("Database file is corrupted:") + L" " + fmtPath(AFS::getDisplayPath(dbPath)), _("Out of memory.") + L" " + utfTo(e.what())); } } diff --git a/FreeFileSync/Source/base/dir_lock.cpp b/FreeFileSync/Source/base/dir_lock.cpp index 85d2be90..f32e5832 100644 --- a/FreeFileSync/Source/base/dir_lock.cpp +++ b/FreeFileSync/Source/base/dir_lock.cpp @@ -182,9 +182,11 @@ LockInformation getLockInfoFromCurrentProcess() //throw FileError LockInformation unserialize(MemoryStreamIn& stream) //throw UnexpectedEndOfStreamError { + //-------- file format header -------- char tmp[sizeof(LOCK_FORMAT_DESCR)] = {}; - readArray(stream, &tmp, sizeof(tmp)); //file format header - const int lockFileVersion = readNumber(stream); // + readArray(stream, &tmp, sizeof(tmp)); //throw UnexpectedEndOfStreamError + + const int lockFileVersion = readNumber(stream); //throw UnexpectedEndOfStreamError if (!std::equal(std::begin(tmp), std::end(tmp), std::begin(LOCK_FORMAT_DESCR)) || lockFileVersion != LOCK_FORMAT_VER) @@ -239,10 +241,10 @@ std::string retrieveLockId(const Zstring& lockFilePath) //throw FileError enum class ProcessStatus { - NOT_RUNNING, - RUNNING, - ITS_US, - CANT_TELL, + notRunning, + running, + itsUs, + noIdea, }; ProcessStatus getProcessStatus(const LockInformation& lockInfo) //throw FileError @@ -251,15 +253,15 @@ ProcessStatus getProcessStatus(const LockInformation& lockInfo) //throw FileErro if (lockInfo.computerName != localInfo.computerName || lockInfo.userId != localInfo.userId) //another user may run a session right now! - return ProcessStatus::CANT_TELL; //lock owned by different computer in this network + return ProcessStatus::noIdea; //lock owned by different computer in this network if (lockInfo.sessionId == localInfo.sessionId && lockInfo.processId == localInfo.processId) //obscure, but possible: deletion failed or a lock file is "stolen" and put back while the program is running - return ProcessStatus::ITS_US; + return ProcessStatus::itsUs; if (std::optional sessionId = getSessionId(lockInfo.processId)) //throw FileError - return *sessionId == lockInfo.sessionId ? ProcessStatus::RUNNING : ProcessStatus::NOT_RUNNING; - return ProcessStatus::NOT_RUNNING; + return *sessionId == lockInfo.sessionId ? ProcessStatus::running : ProcessStatus::notRunning; + return ProcessStatus::notRunning; } @@ -289,17 +291,17 @@ void waitOnDirLock(const Zstring& lockFilePath, const DirLockCallback& notifySta { const LockInformation& lockInfo = retrieveLockInfo(lockFilePath); //throw FileError - infoMsg += L" | " + _("Lock owner:") + L' ' + utfTo(lockInfo.userId); + infoMsg += L" | " + _("User name:") + L' ' + utfTo(lockInfo.userId); originalLockId = lockInfo.lockId; switch (getProcessStatus(lockInfo)) //throw FileError { - case ProcessStatus::ITS_US: //since we've already passed LockAdmin, the lock file seems abandoned ("stolen"?) although it's from this process - case ProcessStatus::NOT_RUNNING: + case ProcessStatus::itsUs: //since we've already passed LockAdmin, the lock file seems abandoned ("stolen"?) although it's from this process + case ProcessStatus::notRunning: lockOwnderDead = true; break; - case ProcessStatus::RUNNING: - case ProcessStatus::CANT_TELL: + case ProcessStatus::running: + case ProcessStatus::noIdea: break; } } diff --git a/FreeFileSync/Source/base/icon_buffer.h b/FreeFileSync/Source/base/icon_buffer.h index c088a56a..d6dd504f 100644 --- a/FreeFileSync/Source/base/icon_buffer.h +++ b/FreeFileSync/Source/base/icon_buffer.h @@ -32,8 +32,8 @@ public: static int getSize(IconSize sz); //expected and *maximum* icon size in pixel int getSize() const { return getSize(iconSizeType_); } // - void setWorkload (const std::vector& load); //(re-)set new workload of icons to be retrieved; - bool readyForRetrieval(const AbstractPath& filePath); + void setWorkload (const std::vector& load); //(re-)set new workload of icons to be retrieved; + bool readyForRetrieval(const AbstractPath& filePath); std::optional retrieveFileIcon (const AbstractPath& filePath); //... and mark as hot wxBitmap getIconByExtension(const Zstring& filePath); //...and add to buffer //retrieveFileIcon() + getIconByExtension() are safe to call from within WM_PAINT handler! no COM calls (...on calling thread) diff --git a/FreeFileSync/Source/base/localization.cpp b/FreeFileSync/Source/base/localization.cpp index d6491c86..ef1ee778 100644 --- a/FreeFileSync/Source/base/localization.cpp +++ b/FreeFileSync/Source/base/localization.cpp @@ -100,6 +100,36 @@ FFSTranslation::FFSTranslation(const std::string& lngStream) //throw lng::Parsin std::vector loadTranslations() { + const Zstring& zipPath = getResourceDirPf() + Zstr("Languages.zip"); + std::vector> streams; + + try //to load from ZIP first: + { + const std::string rawStream = loadBinContainer(zipPath, nullptr /*notifyUnbufferedIO*/); //throw FileError + wxMemoryInputStream memStream(rawStream.c_str(), rawStream.size()); //does not take ownership + wxZipInputStream zipStream(memStream, wxConvUTF8); + + while (const auto& entry = std::unique_ptr(zipStream.GetNextEntry())) //take ownership! + if (std::string stream(entry->GetSize(), '\0'); !stream.empty() && zipStream.ReadAll(&stream[0], stream.size())) + streams.emplace_back(utfTo(entry->GetName()), std::move(stream)); + else + assert(false); + } + catch (FileError&) //fall back to folder + { + traverseFolder(beforeLast(zipPath, Zstr(".zip"), IF_MISSING_RETURN_NONE), [&](const FileInfo& fi) + { + if (endsWith(fi.fullPath, Zstr(".lng"))) + try + { + std::string stream = loadBinContainer(fi.fullPath, nullptr /*notifyUnbufferedIO*/); //throw FileError + streams.emplace_back(fi.itemName, std::move(stream)); + } + catch (FileError&) { assert(false); } + }, nullptr, nullptr, [](const std::wstring& errorMsg) { assert(false); }); //errors are not really critical in this context + } + //-------------------------------------------------------------------- + std::vector locMapping; { //default entry: @@ -113,50 +143,36 @@ std::vector loadTranslations() locMapping.push_back(newEntry); } - try - { - const std::string rawStream = loadBinContainer(fff::getResourceDirPf() + Zstr("Languages.zip"), nullptr /*notifyUnbufferedIO*/); //throw FileError - wxMemoryInputStream memStream(rawStream.c_str(), rawStream.size()); //does not take ownership - wxZipInputStream zipStream(memStream, wxConvUTF8); - - while (const auto& entry = std::unique_ptr(zipStream.GetNextEntry())) //take ownership!) + for (/*const*/ auto& [fileName, stream] : streams) + try { - std::string stream(entry->GetSize(), '\0'); - if (!stream.empty() && zipStream.ReadAll(&stream[0], stream.size())) - try - { - const lng::TransHeader lngHeader = lng::parseHeader(stream); //throw ParsingError - assert(!lngHeader.languageName .empty()); - assert(!lngHeader.translatorName.empty()); - assert(!lngHeader.localeName .empty()); - assert(!lngHeader.flagFile .empty()); - /* - Some ISO codes are used by multiple wxLanguage IDs which can lead to incorrect mapping by wxLocale::FindLanguageInfo()!!! - => Identify by description, e.g. "Chinese (Traditional)". The following IDs are affected: - wxLANGUAGE_CHINESE_TRADITIONAL - wxLANGUAGE_ENGLISH_UK - wxLANGUAGE_SPANISH //non-unique, but still mapped correctly (or is it incidentally???) - wxLANGUAGE_SERBIAN // - */ - if (const wxLanguageInfo* locInfo = wxLocale::FindLanguageInfo(utfTo(lngHeader.localeName))) - { - TranslationInfo newEntry; - newEntry.languageID = static_cast(locInfo->Language); - newEntry.languageName = utfTo(lngHeader.languageName); - newEntry.translatorName = utfTo(lngHeader.translatorName); - newEntry.languageFlag = utfTo(lngHeader.flagFile); - newEntry.lngFileName = utfTo(entry->GetName()); - newEntry.lngStream = std::move(stream); - locMapping.push_back(newEntry); - } - else assert(false); - } - catch (lng::ParsingError&) { assert(false); } //better not show an error message here; scenario: batch jobs - else - assert(false); + const lng::TransHeader lngHeader = lng::parseHeader(stream); //throw ParsingError + assert(!lngHeader.languageName .empty()); + assert(!lngHeader.translatorName.empty()); + assert(!lngHeader.localeName .empty()); + assert(!lngHeader.flagFile .empty()); + /* + Some ISO codes are used by multiple wxLanguage IDs which can lead to incorrect mapping by wxLocale::FindLanguageInfo()!!! + => Identify by description, e.g. "Chinese (Traditional)". The following IDs are affected: + wxLANGUAGE_CHINESE_TRADITIONAL + wxLANGUAGE_ENGLISH_UK + wxLANGUAGE_SPANISH //non-unique, but still mapped correctly (or is it incidentally???) + wxLANGUAGE_SERBIAN // + */ + if (const wxLanguageInfo* locInfo = wxLocale::FindLanguageInfo(utfTo(lngHeader.localeName))) + { + TranslationInfo newEntry; + newEntry.languageID = static_cast(locInfo->Language); + newEntry.languageName = utfTo(lngHeader.languageName); + newEntry.translatorName = utfTo(lngHeader.translatorName); + newEntry.languageFlag = utfTo(lngHeader.flagFile); + newEntry.lngFileName = fileName; + newEntry.lngStream = std::move(stream); + locMapping.push_back(newEntry); + } + else assert(false); } - } - catch (FileError&) { assert(false); } + catch (lng::ParsingError&) { assert(false); } //better not show an error message here; scenario: batch jobs std::sort(locMapping.begin(), locMapping.end(), [](const TranslationInfo& lhs, const TranslationInfo& rhs) { @@ -337,11 +353,11 @@ public: writeNumber(moBuf_, 0); //format version writeNumber(moBuf_, transMapping.size()); //string count writeNumber(moBuf_, headerSize); //string references offset: original - writeNumber(moBuf_, headerSize + 8 * transMapping.size()); //string references offset: translation + writeNumber(moBuf_, headerSize + (2 * sizeof(uint32_t)) * transMapping.size()); //string references offset: translation writeNumber(moBuf_, 0); //size of hashing table writeNumber(moBuf_, 0); //offset of hashing table - const int stringsOffset = headerSize + 2 * 8 * transMapping.size(); + const int stringsOffset = headerSize + 2 * (2 * sizeof(uint32_t)) * transMapping.size(); std::string stringsList; for (const auto& [original, translation] : transMapping) @@ -351,9 +367,9 @@ public: stringsList.append(original.c_str(), original.size() + 1); //include 0-termination } - for (const auto& item : transMapping) + for (const auto& [original, trans] : transMapping) { - const auto& translation = utfTo(item.second); + const auto& translation = utfTo(trans); writeNumber(moBuf_, translation.size()); //string length writeNumber(moBuf_, stringsOffset + stringsList.size()); //string offset stringsList.append(translation.c_str(), translation.size() + 1); //include 0-termination @@ -402,44 +418,41 @@ public: void init(wxLanguage lng) { - const wxLanguageInfo* sysLngInfo = wxLocale::GetLanguageInfo(sysLng_); - const wxLanguageInfo* selLngInfo = wxLocale::GetLanguageInfo(lng); - - const bool sysLangIsRTL = sysLngInfo ? sysLngInfo->LayoutDirection == wxLayout_RightToLeft : false; - const bool selectedLangIsRTL = selLngInfo ? selLngInfo->LayoutDirection == wxLayout_RightToLeft : false; + lng_ = lng; - const wxLanguage initLng = sysLangIsRTL == selectedLangIsRTL ? - sysLng_ : //use sys-lang to preserve sub-language specific rules (e.g. German Swiss number punctuation) - lng; //have to use the supplied language to enable RTL layout different than user settings + if (const wxLanguageInfo* selLngInfo = wxLocale::GetLanguageInfo(lng)) + layoutDir_ = selLngInfo->LayoutDirection; + else + layoutDir_ = wxLayout_LeftToRight; - if (!locale_ || localeLng_ != initLng) + //use sys-lang to preserve sub-language specific rules (e.g. German Swiss number punctuation) + //beneficial even for Arabic locale: support user-specific date settings (instead of Hijri calendar year 1441 = Gregorian 2019) + if (!locale_) { //wxWidgets shows a modal dialog on error during wxLocale::Init() -> at least we can shut it up! wxLog* oldLogTarget = wxLog::SetActiveTarget(new wxLogStderr); //transfer and receive ownership! ZEN_ON_SCOPE_EXIT(delete wxLog::SetActiveTarget(oldLogTarget)); - locale_.reset(); //avoid global locale lifetime overlap! wxWidgets cannot handle this and will crash! - locale_ = std::make_unique(initLng, wxLOCALE_DONT_LOAD_DEFAULT /*we're not using wxwin.mo*/); + //locale_.reset(); //avoid global locale lifetime overlap! wxWidgets cannot handle this and will crash! + locale_ = std::make_unique(sysLng_, wxLOCALE_DONT_LOAD_DEFAULT /*we're not using wxwin.mo*/); assert(locale_->IsOk()); - localeLng_ = initLng; } - - lng_ = lng; } - void tearDown() { locale_.reset(); lng_ = localeLng_ = wxLANGUAGE_UNKNOWN; } + void tearDown() { locale_.reset(); lng_ = wxLANGUAGE_UNKNOWN; layoutDir_ = wxLayout_Default; } - wxLanguage getLanguage () const { return lng_; } wxLanguage getSysLanguage() const { return sysLng_; } + wxLanguage getLanguage () const { return lng_; } + wxLayoutDirection getLayoutDirection() const { return layoutDir_; } private: wxWidgetsLocale() {} ~wxWidgetsLocale() { assert(!locale_); } - std::unique_ptr locale_; - wxLanguage localeLng_ = wxLANGUAGE_UNKNOWN; - wxLanguage lng_ = wxLANGUAGE_UNKNOWN; const wxLanguage sysLng_ = static_cast(wxLocale::GetSystemLanguage()); + wxLanguage lng_ = wxLANGUAGE_UNKNOWN; + wxLayoutDirection layoutDir_ = wxLayout_Default; + std::unique_ptr locale_; }; } @@ -517,14 +530,20 @@ void fff::setLanguage(wxLanguage lng) //throw FileError } +wxLanguage fff::getSystemLanguage() +{ + static const wxLanguage sysLng = mapLanguageDialect(wxWidgetsLocale::getInstance().getSysLanguage()); + return sysLng; +} + + wxLanguage fff::getLanguage() { return wxWidgetsLocale::getInstance().getLanguage(); } -wxLanguage fff::getSystemLanguage() +wxLayoutDirection fff::getLayoutDirection() { - static const wxLanguage sysLng = mapLanguageDialect(wxWidgetsLocale::getInstance().getSysLanguage()); - return sysLng; + return wxWidgetsLocale::getInstance().getLayoutDirection(); } diff --git a/FreeFileSync/Source/base/localization.h b/FreeFileSync/Source/base/localization.h index 51fea760..e635ac1e 100644 --- a/FreeFileSync/Source/base/localization.h +++ b/FreeFileSync/Source/base/localization.h @@ -9,6 +9,7 @@ #include #include +#include #include @@ -25,11 +26,11 @@ struct TranslationInfo }; const std::vector& getExistingTranslations(); - -void setLanguage(wxLanguage lng); //throw FileError +wxLanguage getSystemLanguage(); wxLanguage getLanguage(); +wxLayoutDirection getLayoutDirection(); -wxLanguage getSystemLanguage(); +void setLanguage(wxLanguage lng); //throw FileError void releaseWxLocale(); //wxLocale crashes miserably on wxGTK when destructor runs during global cleanup => call in wxApp::OnExit //"You should delete all wxWidgets object that you created by the time OnExit finishes. In particular, do not destroy them from application class' destructor!" diff --git a/FreeFileSync/Source/base/log_file.cpp b/FreeFileSync/Source/base/log_file.cpp index 76a9b7a1..39e8f0a7 100644 --- a/FreeFileSync/Source/base/log_file.cpp +++ b/FreeFileSync/Source/base/log_file.cpp @@ -117,9 +117,6 @@ AbstractPath saveNewLogFile(const ProcessSummary& summary, //throw FileError const AbstractPath& logFolderPath, const std::function& notifyStatus /*throw X*/) { - //create logfile folder if required - AFS::createFolderIfMissingRecursion(logFolderPath); //throw FileError - //const std::string colon = "\xcb\xb8"; //="modifier letter raised colon" => regular colon is forbidden in file names on Windows and OS X //=> too many issues, most notably cmd.exe is not Unicode-aware: https://freefilesync.org/forum/viewtopic.php?t=1679 @@ -162,6 +159,17 @@ AbstractPath saveNewLogFile(const ProcessSummary& summary, //throw FileError const AbstractPath logFilePath = AFS::appendRelPath(logFolderPath, logFileName); + //----------------------------------------------------------------------- + try //create logfile folder if required + { + AFS::createFolderIfMissingRecursion(logFolderPath); //throw FileError + } + catch (const FileError& e) //add context info regarding log file! + { + throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(AFS::getDisplayPath(logFilePath))), e.toString()); + } + //----------------------------------------------------------------------- + auto notifyUnbufferedIO = [notifyStatus, bytesWritten_ = int64_t(0), msg_ = replaceCpy(_("Saving file %x..."), L"%x", fmtPath(AFS::getDisplayPath(logFilePath)))] diff --git a/FreeFileSync/Source/base/path_filter.h b/FreeFileSync/Source/base/path_filter.h index 549bf0cc..f1087722 100644 --- a/FreeFileSync/Source/base/path_filter.h +++ b/FreeFileSync/Source/base/path_filter.h @@ -14,22 +14,18 @@ namespace fff { -//------------------------------------------------------------------ -/* -Semantics of PathFilter: -1. using it creates a NEW folder hierarchy! -> must be considered by variant! -2. it applies equally to both sides => it always matches either both sides or none! => can be used while traversing a single folder! - - class hierarchy: - - PathFilter (interface) - /|\ - _________|_____________ - | | | -NullFilter NameFilter CombinedFilter -*/ +/* Semantics of PathFilter: + 1. using it creates a NEW folder hierarchy! -> must be considered by variant! + 2. it applies equally to both sides => it always matches either both sides or none! => can be used while traversing a single folder! + + PathFilter (interface) + /|\ + ____________|_____________ + | | | + NullFilter NameFilter CombinedFilter + */ class PathFilter; -using FilterRef = zen::SharedRef; //Thread-safety: internally synchronized! +using FilterRef = zen::SharedRef; const Zchar FILTER_ITEM_SEPARATOR = Zstr('|'); diff --git a/FreeFileSync/Source/base/structures.cpp b/FreeFileSync/Source/base/structures.cpp index ba8b3a83..18448ece 100644 --- a/FreeFileSync/Source/base/structures.cpp +++ b/FreeFileSync/Source/base/structures.cpp @@ -103,10 +103,10 @@ std::wstring fff::getVariantName(DirectionConfig::Variant var) //const wchar_t arrowLeft [] = L"\u25C4\u2013 "; //black triangle pointer //const wchar_t arrowRight[] = L" \u2013\u25BA"; // const wchar_t arrowLeft [] = L"\uFF1C\u2013 "; //fullwidth less-than + en dash - const wchar_t arrowRight[] = L" \u2013\uFF1E"; //en dash + fullwidth greater-than - const wchar_t angleRight[] = L" \uFF1E"; + const wchar_t arrowRight[] = L" \u2013\uFF1E"; //en dash + fullwidth greater-than + const wchar_t angleRight[] = L" \uFF1E"; //=> drawback: - not drawn correctly before Vista - // - RTL: the full width less-than is not mirrored automatically (=> Windows Unicode bug!?) + // - RTL: the full width less-than is not mirrored automatically (=> Windows Unicode bug!) #endif return getVariantNameImpl(var, arrowLeft, arrowRight, angleRight); } diff --git a/FreeFileSync/Source/base/synchronization.cpp b/FreeFileSync/Source/base/synchronization.cpp index fdb9e23e..3533573b 100644 --- a/FreeFileSync/Source/base/synchronization.cpp +++ b/FreeFileSync/Source/base/synchronization.cpp @@ -108,7 +108,7 @@ void SyncStatistics::processFile(const FilePair& file) break; case SO_MOVE_LEFT_FROM: //ignore; already counted - case SO_MOVE_RIGHT_FROM: // + case SO_MOVE_RIGHT_FROM: //=> harmonize with FileView::applyFilterByAction() break; case SO_OVERWRITE_LEFT: diff --git a/FreeFileSync/Source/ui/abstract_folder_picker.cpp b/FreeFileSync/Source/ui/abstract_folder_picker.cpp index e9cfc6e6..4c96e6f7 100644 --- a/FreeFileSync/Source/ui/abstract_folder_picker.cpp +++ b/FreeFileSync/Source/ui/abstract_folder_picker.cpp @@ -88,7 +88,7 @@ AbstractFolderPickerDlg::AbstractFolderPickerDlg(wxWindow* parent, AbstractPath& setStandardButtonLayout(*bSizerStdButtons, StdButtons().setAffirmative(m_buttonOkay).setCancel(m_buttonCancel)); m_staticTextStatus->SetLabel(L""); - m_treeCtrlFileSystem->SetMinSize(wxSize(fastFromDIP(350), fastFromDIP(400))); + m_treeCtrlFileSystem->SetMinSize({fastFromDIP(350), fastFromDIP(400)}); const int iconSize = IconBuffer::getSize(IconBuffer::SIZE_SMALL); auto imgList = std::make_unique(iconSize, iconSize); diff --git a/FreeFileSync/Source/ui/cfg_grid.cpp b/FreeFileSync/Source/ui/cfg_grid.cpp index 9e8eb69a..b15a3302 100644 --- a/FreeFileSync/Source/ui/cfg_grid.cpp +++ b/FreeFileSync/Source/ui/cfg_grid.cpp @@ -333,6 +333,14 @@ private: return std::wstring(); } + void renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected) override + { + if (selected) + clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT)); + else + clearArea(dc, rect, wxSystemSettings::GetColour(enabled ? wxSYS_COLOUR_WINDOW : wxSYS_COLOUR_BTNFACE)); + } + enum class HoverAreaLog { LINK, @@ -346,12 +354,7 @@ private: if (selected) textColor.Set(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT)); else - { - //if (enabled) textColor.Set(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); - //else - // textColor.Set(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT)); - } if (const ConfigView::Details* item = cfgView_.getItem(row)) switch (static_cast(colType)) @@ -369,7 +372,7 @@ private: rectTmp2.x += rectTmp2.width; rectTmp2.width = rectTmp.width - rectTmp2.width; - dc.GradientFillLinear(rectTmp2, item->cfgItem.backColor, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW), wxEAST); + dc.GradientFillLinear(rectTmp2, item->cfgItem.backColor, wxSystemSettings::GetColour(enabled ? wxSYS_COLOUR_WINDOW : wxSYS_COLOUR_BTNFACE), wxEAST); } else //always show a glimpse of the background color { @@ -467,14 +470,6 @@ private: return 0; } - void renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected) override - { - if (selected) - clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT)); - else - clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); - } - HoverArea getRowMouseHover(size_t row, ColumnType colType, int cellRelativePosX, int cellWidth) override { if (const ConfigView::Details* item = cfgView_.getItem(row)) @@ -494,7 +489,7 @@ private: return HoverArea::NONE; } - void renderColumnLabel(Grid& tree, wxDC& dc, const wxRect& rect, ColumnType colType, bool highlighted) override + void renderColumnLabel(wxDC& dc, const wxRect& rect, ColumnType colType, bool enabled, bool highlighted) override { const auto colTypeCfg = static_cast(colType); @@ -512,24 +507,27 @@ private: case ColumnTypeCfg::lastSync: rectRemain.x += getColumnGapLeft(); rectRemain.width -= getColumnGapLeft(); - drawColumnLabelText(dc, rectRemain, getColumnLabel(colType)); + drawColumnLabelText(dc, rectRemain, getColumnLabel(colType), enabled); if (sortMarker.IsOk()) drawBitmapRtlNoMirror(dc, sortMarker, rectInner, wxALIGN_CENTER_HORIZONTAL); break; case ColumnTypeCfg::lastLog: - drawBitmapRtlNoMirror(dc, getResourceImage(L"log_file_sicon"), rectInner, wxALIGN_CENTER); + { + const wxBitmap logIcon = getResourceImage(L"log_file_sicon"); + drawBitmapRtlNoMirror(dc, enabled ? logIcon : logIcon.ConvertToDisabled(), rectInner, wxALIGN_CENTER); if (sortMarker.IsOk()) { - const int gapLeft = (rectInner.width + getResourceImage(L"log_file_sicon").GetWidth()) / 2; + const int gapLeft = (rectInner.width + logIcon.GetWidth()) / 2; rectRemain.x += gapLeft; rectRemain.width -= gapLeft; drawBitmapRtlNoMirror(dc, sortMarker, rectRemain, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); } - break; + } + break; } } diff --git a/FreeFileSync/Source/ui/command_box.cpp b/FreeFileSync/Source/ui/command_box.cpp index b862d365..7dc2607d 100644 --- a/FreeFileSync/Source/ui/command_box.cpp +++ b/FreeFileSync/Source/ui/command_box.cpp @@ -49,7 +49,7 @@ CommandBox::CommandBox(wxWindow* parent, defaultCommands_(getDefaultCommands()) { //#################################### - /*#*/ SetMinSize(wxSize(fastFromDIP(150), -1)); //# workaround yet another wxWidgets bug: default minimum size is much too large for a wxComboBox + /*#*/ SetMinSize({fastFromDIP(150), -1}); //# workaround yet another wxWidgets bug: default minimum size is much too large for a wxComboBox //#################################### Connect(wxEVT_KEY_DOWN, wxKeyEventHandler (CommandBox::OnKeyEvent ), nullptr, this); diff --git a/FreeFileSync/Source/ui/file_grid.cpp b/FreeFileSync/Source/ui/file_grid.cpp index e369527e..bc7b7037 100644 --- a/FreeFileSync/Source/ui/file_grid.cpp +++ b/FreeFileSync/Source/ui/file_grid.cpp @@ -277,31 +277,25 @@ private: protected: void renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected) override { - if (enabled) + if (enabled && !selected) { - if (selected) - dc.GradientFillLinear(rect, getColorSelectionGradientFrom(), getColorSelectionGradientTo(), wxEAST); - //ignore focus + //alternate background color to improve readability (while lacking cell borders) + if (getRowDisplayType(row) == DisplayType::NORMAL) + fillBackgroundDefaultColorAlternating(dc, rect, row % 2 == 0); else - { - //alternate background color to improve readability (while lacking cell borders) - if (getRowDisplayType(row) == DisplayType::NORMAL) - fillBackgroundDefaultColorAlternating(dc, rect, row % 2 == 0); - else - clearArea(dc, rect, getBackGroundColor(row)); + clearArea(dc, rect, getBackGroundColor(row)); - //draw horizontal border if required - DisplayType dispTp = getRowDisplayType(row); - if (dispTp != DisplayType::NORMAL && - dispTp == getRowDisplayType(row + 1)) - { - wxDCPenChanger dummy2(dc, getColorGridLine()); - dc.DrawLine(rect.GetBottomLeft(), rect.GetBottomRight() + wxPoint(1, 0)); - } + //draw horizontal border if required + DisplayType dispTp = getRowDisplayType(row); + if (dispTp != DisplayType::NORMAL && + dispTp == getRowDisplayType(row + 1)) + { + wxDCPenChanger dummy2(dc, getColorGridLine()); + dc.DrawLine(rect.GetBottomLeft(), rect.GetBottomRight() + wxPoint(1, 0)); } } else - clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); + GridData::renderRowBackgound(dc, rect, row, enabled, enabled && selected); } wxColor getBackGroundColor(size_t row) const @@ -668,14 +662,14 @@ private: return std::wstring(); } - void renderColumnLabel(Grid& tree, wxDC& dc, const wxRect& rect, ColumnType colType, bool highlighted) override + void renderColumnLabel(wxDC& dc, const wxRect& rect, ColumnType colType, bool enabled, bool highlighted) override { const wxRect rectInner = drawColumnLabelBackground(dc, rect, highlighted); wxRect rectRemain = rectInner; rectRemain.x += getColumnGapLeft(); rectRemain.width -= getColumnGapLeft(); - drawColumnLabelText(dc, rectRemain, getColumnLabel(colType)); + drawColumnLabelText(dc, rectRemain, getColumnLabel(colType), enabled); //draw sort marker if (const FileView* view = getGridDataView()) @@ -822,7 +816,7 @@ private: { wxRect rectTmp = rect; rectTmp.width /= 20; - dc.GradientFillLinear(rectTmp, getColorSelectionGradientFrom(), GridDataRim::getBackGroundColor(row), wxEAST); + dc.GradientFillLinear(rectTmp, getColorSelectionGradientFrom(), getBackGroundColor(row), wxEAST); } } } @@ -924,14 +918,6 @@ public: void highlightSyncAction(bool value) { highlightSyncAction_ = value; } private: - enum class HoverAreaCenter //each cell can be divided into four blocks concerning mouse selections - { - CHECK_BOX, - DIR_LEFT, - DIR_NONE, - DIR_RIGHT - }; - std::wstring getValue(size_t row, ColumnType colType) const override { if (const FileSystemObject* fsObj = getRawData(row)) @@ -949,27 +935,30 @@ private: void renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected) override { - if (enabled) + if (enabled && !selected) { - if (selected) - dc.GradientFillLinear(rect, getColorSelectionGradientFrom(), getColorSelectionGradientTo(), wxEAST); - else + if (const FileSystemObject* fsObj = getRawData(row)) { - if (const FileSystemObject* fsObj = getRawData(row)) - { - if (fsObj->isActive()) - fillBackgroundDefaultColorAlternating(dc, rect, row % 2 == 0); - else - clearArea(dc, rect, getColorNotActive()); - } + if (fsObj->isActive()) + fillBackgroundDefaultColorAlternating(dc, rect, row % 2 == 0); else - clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + clearArea(dc, rect, getColorNotActive()); } + else + clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); } else - clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); + GridData::renderRowBackgound(dc, rect, row, enabled, enabled && selected); } + enum class HoverAreaCenter //each cell can be divided into four blocks concerning mouse selections + { + CHECK_BOX, + DIR_LEFT, + DIR_NONE, + DIR_RIGHT + }; + void renderCell(wxDC& dc, const wxRect& rect, size_t row, ColumnType colType, bool enabled, bool selected, HoverArea rowHover) override { auto drawHighlightBackground = [&](const FileSystemObject& fsObj, const wxColor& col) @@ -1094,7 +1083,7 @@ private: std::wstring getToolTip(ColumnType colType) const override { return getColumnLabel(colType); } - void renderColumnLabel(Grid& tree, wxDC& dc, const wxRect& rect, ColumnType colType, bool highlighted) override + void renderColumnLabel(wxDC& dc, const wxRect& rect, ColumnType colType, bool enabled, bool highlighted) override { const auto colTypeCenter = static_cast(colType); @@ -1120,7 +1109,7 @@ private: } if (colIcon.IsOk()) - drawBitmapRtlNoMirror(dc, colIcon, rectInner, wxALIGN_CENTER); + drawBitmapRtlNoMirror(dc, enabled ? colIcon : colIcon.ConvertToDisabled(), rectInner, wxALIGN_CENTER); //draw sort marker if (const FileView* view = getGridDataView()) diff --git a/FreeFileSync/Source/ui/file_view.cpp b/FreeFileSync/Source/ui/file_view.cpp index 0342d800..4b878ad2 100644 --- a/FreeFileSync/Source/ui/file_view.cpp +++ b/FreeFileSync/Source/ui/file_view.cpp @@ -15,14 +15,6 @@ using namespace fff; namespace { -struct CompileTimeReminder : public FSObjectVisitor -{ - void visit(const FilePair& file ) override {} - void visit(const SymlinkPair& symlink) override {} - void visit(const FolderPair& folder ) override {} -} checkDymanicCasts; //just a compile-time reminder to manually check dynamic casts in this file if ever needed - - template void addNumbers(const FileSystemObject& fsObj, ViewStats& stats) { @@ -178,6 +170,9 @@ FileView::ActionViewStats FileView::applyFilterByAction(bool showExcluded, //map { ActionViewStats stats; + int moveLeft = 0; + int moveRight = 0; + updateView([&](const FileSystemObject& fsObj) { auto categorize = [&](bool showCategory, int& categoryCount) @@ -207,15 +202,17 @@ FileView::ActionViewStats FileView::applyFilterByAction(bool showExcluded, //map case SO_DELETE_RIGHT: return categorize(showDeleteRight, stats.deleteRight); case SO_OVERWRITE_LEFT: - case SO_COPY_METADATA_TO_LEFT: //no extra button on screen - case SO_MOVE_LEFT_TO: - case SO_MOVE_LEFT_FROM: + case SO_COPY_METADATA_TO_LEFT: //no extra filter button return categorize(showUpdateLeft, stats.updateLeft); + case SO_MOVE_LEFT_FROM: + case SO_MOVE_LEFT_TO: + return categorize(showUpdateLeft, moveLeft); case SO_OVERWRITE_RIGHT: - case SO_COPY_METADATA_TO_RIGHT: //no extra button on screen + case SO_COPY_METADATA_TO_RIGHT: //no extra filter button + return categorize(showUpdateRight, stats.updateRight); case SO_MOVE_RIGHT_FROM: case SO_MOVE_RIGHT_TO: - return categorize(showUpdateRight, stats.updateRight); + return categorize(showUpdateRight, moveRight); case SO_DO_NOTHING: return categorize(showDoNothing, stats.updateNone); case SO_EQUAL: @@ -227,6 +224,10 @@ FileView::ActionViewStats FileView::applyFilterByAction(bool showExcluded, //map return true; }); + assert(moveLeft % 2 == 0 && moveRight % 2 == 0); + stats.updateLeft += moveLeft / 2; //count move operations as single update + stats.updateRight += moveRight / 2; //=> harmonize with SyncStatistics::processFile() + return stats; } @@ -274,8 +275,8 @@ private: CmpNaturalSort: 850 ms CmpLocalPath: 233 ms CmpAsciiNoCase: 189 ms - No sorting: 30 ms - */ + No sorting: 30 ms + */ template static std::vector getItemsSorted(std::list& itemList) { @@ -329,6 +330,14 @@ void FileView::setData(FolderComparison& folderCmp) //------------------------------------ SORTING ----------------------------------------- namespace { +struct CompileTimeReminder : public FSObjectVisitor +{ + void visit(const FilePair& file ) override {} + void visit(const SymlinkPair& symlink) override {} + void visit(const FolderPair& folder ) override {} +} checkDymanicCasts; //just a compile-time reminder to manually check dynamic casts in this file if ever needed + + inline bool isDirectoryPair(const FileSystemObject& fsObj) { @@ -537,12 +546,12 @@ struct FileView::LessRelativeFolder //presort by folder pair if (a.folderIndex != b.folderIndex) - { - if constexpr (ascending) - return a.folderIndex < b.folderIndex; - else - return a.folderIndex > b.folderIndex; - } + { + if constexpr (ascending) + return a.folderIndex < b.folderIndex; + else + return a.folderIndex > b.folderIndex; + } return lessRelativeFolder(*fsObjA, *fsObjB); } diff --git a/FreeFileSync/Source/ui/folder_history_box.cpp b/FreeFileSync/Source/ui/folder_history_box.cpp index 70eaa9dc..8109757a 100644 --- a/FreeFileSync/Source/ui/folder_history_box.cpp +++ b/FreeFileSync/Source/ui/folder_history_box.cpp @@ -28,7 +28,7 @@ FolderHistoryBox::FolderHistoryBox(wxWindow* parent, wxComboBox(parent, id, value, pos, size, n, choices, style, validator, name) { //##################################### - /*##*/ SetMinSize(wxSize(fastFromDIP(150), -1)); //## workaround yet another wxWidgets bug: default minimum size is much too large for a wxComboBox + /*##*/ SetMinSize({fastFromDIP(150), -1}); //## workaround yet another wxWidgets bug: default minimum size is much too large for a wxComboBox //##################################### Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(FolderHistoryBox::OnKeyEvent), nullptr, this); diff --git a/FreeFileSync/Source/ui/folder_pair.h b/FreeFileSync/Source/ui/folder_pair.h index cb5794b6..7a90521c 100644 --- a/FreeFileSync/Source/ui/folder_pair.h +++ b/FreeFileSync/Source/ui/folder_pair.h @@ -38,7 +38,7 @@ public: std::optional getCompConfig () const { return localCmpCfg_; } std::optional getSyncConfig () const { return localSyncCfg_; } - FilterConfig getFilterConfig() const { return localFilter_; } + FilterConfig getFilterConfig() const { return localFilter_; } FolderPairPanelBasic(GuiPanel& basicPanel) : //takes reference on basic panel to be enhanced @@ -57,40 +57,36 @@ private: { using namespace zen; - const wxImage imgCmp = shrinkImage(getResourceImage(L"cfg_compare").ConvertToImage(), fastFromDIP(20)); - const wxImage imgSync = shrinkImage(getResourceImage(L"cfg_sync" ).ConvertToImage(), fastFromDIP(20)); - const wxImage imgFilter = shrinkImage(getResourceImage(L"cfg_filter" ).ConvertToImage(), fastFromDIP(20)); - if (localCmpCfg_) { - setImage(*basicPanel_.m_bpButtonLocalCompCfg, imgCmp); + setImage(*basicPanel_.m_bpButtonLocalCompCfg, imgCmp_); basicPanel_.m_bpButtonLocalCompCfg->SetToolTip(_("Local comparison settings") + L" (" + getVariantName(localCmpCfg_->compareVar) + L")"); } else { - setImage(*basicPanel_.m_bpButtonLocalCompCfg, greyScale(imgCmp)); + setImage(*basicPanel_.m_bpButtonLocalCompCfg, greyScale(imgCmp_)); basicPanel_.m_bpButtonLocalCompCfg->SetToolTip(_("Local comparison settings")); } if (localSyncCfg_) { - setImage(*basicPanel_.m_bpButtonLocalSyncCfg, imgSync); + setImage(*basicPanel_.m_bpButtonLocalSyncCfg, imgSync_); basicPanel_.m_bpButtonLocalSyncCfg->SetToolTip(_("Local synchronization settings") + L" (" + getVariantName(localSyncCfg_->directionCfg.var) + L")"); } else { - setImage(*basicPanel_.m_bpButtonLocalSyncCfg, greyScale(imgSync)); + setImage(*basicPanel_.m_bpButtonLocalSyncCfg, greyScale(imgSync_)); basicPanel_.m_bpButtonLocalSyncCfg->SetToolTip(_("Local synchronization settings")); } if (!isNullFilter(localFilter_)) { - setImage(*basicPanel_.m_bpButtonLocalFilter, imgFilter); + setImage(*basicPanel_.m_bpButtonLocalFilter, imgFilter_); basicPanel_.m_bpButtonLocalFilter->SetToolTip(_("Local filter") + L" (" + _("Active") + L")"); } else { - setImage(*basicPanel_.m_bpButtonLocalFilter, greyScale(imgFilter)); + setImage(*basicPanel_.m_bpButtonLocalFilter, greyScale(imgFilter_)); basicPanel_.m_bpButtonLocalFilter->SetToolTip(_("Local filter") + L" (" + _("None") + L")"); } } @@ -167,9 +163,12 @@ private: //alternate configuration attached to it std::optional localCmpCfg_; std::optional localSyncCfg_; - FilterConfig localFilter_; + FilterConfig localFilter_; + + const wxImage imgCmp_ = zen::shrinkImage(zen::getResourceImage(L"cfg_compare").ConvertToImage(), zen::fastFromDIP(20)); + const wxImage imgSync_ = zen::shrinkImage(zen::getResourceImage(L"cfg_sync" ).ConvertToImage(), zen::fastFromDIP(20)); + const wxImage imgFilter_ = zen::shrinkImage(zen::getResourceImage(L"cfg_filter" ).ConvertToImage(), zen::fastFromDIP(20)); }; } - #endif //FOLDER_PAIR_H_89341750847252345 diff --git a/FreeFileSync/Source/ui/gui_generated.cpp b/FreeFileSync/Source/ui/gui_generated.cpp index 559dfa0d..7c9dbb81 100644 --- a/FreeFileSync/Source/ui/gui_generated.cpp +++ b/FreeFileSync/Source/ui/gui_generated.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version May 29 2018) +// C++ code generated with wxFormBuilder (version Oct 26 2018) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -34,9 +34,8 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_menuFile->AppendSeparator(); - wxMenuItem* m_menuItem4; - m_menuItem4 = new wxMenuItem( m_menuFile, wxID_EXIT, wxString( _("E&xit") ), wxEmptyString, wxITEM_NORMAL ); - m_menuFile->Append( m_menuItem4 ); + m_menuItemQuit = new wxMenuItem( m_menuFile, wxID_EXIT, wxString( _("E&xit") ), wxEmptyString, wxITEM_NORMAL ); + m_menuFile->Append( m_menuItemQuit ); m_menubar->Append( m_menuFile, _("&File") ); @@ -150,6 +149,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer261->Add( m_buttonCancel, 0, wxEXPAND, 5 ); m_buttonCompare = new zen::BitmapTextButton( m_panelTopButtons, wxID_ANY, _("Compare"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonCompare->SetDefault(); m_buttonCompare->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); m_buttonCompare->SetToolTip( _("dummy") ); @@ -159,12 +159,12 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer261->Add( 4, 0, 0, 0, 5 ); - m_bpButtonCmpConfig = new wxBitmapButton( m_panelTopButtons, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonCmpConfig = new wxBitmapButton( m_panelTopButtons, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonCmpConfig->SetToolTip( _("dummy") ); bSizer261->Add( m_bpButtonCmpConfig, 0, wxEXPAND, 5 ); - m_bpButtonCmpContext = new wxBitmapButton( m_panelTopButtons, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonCmpContext = new wxBitmapButton( m_panelTopButtons, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonCmpContext->SetToolTip( _("dummy") ); bSizer261->Add( m_bpButtonCmpContext, 0, wxEXPAND, 5 ); @@ -184,12 +184,12 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer199->Add( 0, 0, 1, 0, 5 ); - m_bpButtonFilter = new wxBitmapButton( m_panelTopButtons, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|wxFULL_REPAINT_ON_RESIZE ); + m_bpButtonFilter = new wxBitmapButton( m_panelTopButtons, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0|wxFULL_REPAINT_ON_RESIZE ); m_bpButtonFilter->SetToolTip( _("dummy") ); bSizer199->Add( m_bpButtonFilter, 0, wxEXPAND, 5 ); - m_bpButtonFilterContext = new wxBitmapButton( m_panelTopButtons, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonFilterContext = new wxBitmapButton( m_panelTopButtons, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonFilterContext->SetToolTip( _("dummy") ); bSizer199->Add( m_bpButtonFilterContext, 0, wxEXPAND, 5 ); @@ -209,12 +209,12 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer262->Add( 0, 0, 1, 0, 5 ); - m_bpButtonSyncConfig = new wxBitmapButton( m_panelTopButtons, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonSyncConfig = new wxBitmapButton( m_panelTopButtons, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonSyncConfig->SetToolTip( _("dummy") ); bSizer262->Add( m_bpButtonSyncConfig, 0, wxEXPAND, 5 ); - m_bpButtonSyncContext = new wxBitmapButton( m_panelTopButtons, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonSyncContext = new wxBitmapButton( m_panelTopButtons, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonSyncContext->SetToolTip( _("dummy") ); bSizer262->Add( m_bpButtonSyncContext, 0, wxEXPAND, 5 ); @@ -243,7 +243,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer1791->Fit( m_panelTopButtons ); bSizerPanelHolder->Add( m_panelTopButtons, 0, wxEXPAND, 5 ); - m_panelDirectoryPairs = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSTATIC_BORDER|wxTAB_TRAVERSAL ); + m_panelDirectoryPairs = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL|wxBORDER_STATIC ); wxBoxSizer* bSizer1601; bSizer1601 = new wxBoxSizer( wxVERTICAL ); @@ -269,12 +269,12 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer159; bSizer159 = new wxBoxSizer( wxHORIZONTAL ); - m_bpButtonAddPair = new wxBitmapButton( m_panelTopLeft, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonAddPair = new wxBitmapButton( m_panelTopLeft, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonAddPair->SetToolTip( _("Add folder pair") ); bSizer159->Add( m_bpButtonAddPair, 0, wxEXPAND, 5 ); - m_bpButtonRemovePair = new wxBitmapButton( m_panelTopLeft, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonRemovePair = new wxBitmapButton( m_panelTopLeft, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonRemovePair->SetToolTip( _("Remove folder pair") ); bSizer159->Add( m_bpButtonRemovePair, 0, wxEXPAND, 5 ); @@ -293,7 +293,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer182->Add( m_buttonSelectFolderLeft, 0, wxEXPAND, 5 ); - m_bpButtonSelectAltFolderLeft = new wxBitmapButton( m_panelTopLeft, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonSelectAltFolderLeft = new wxBitmapButton( m_panelTopLeft, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonSelectAltFolderLeft->SetToolTip( _("Access online storage") ); bSizer182->Add( m_bpButtonSelectAltFolderLeft, 0, wxEXPAND, 5 ); @@ -311,7 +311,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer1771; bSizer1771 = new wxBoxSizer( wxVERTICAL ); - m_bpButtonSwapSides = new wxBitmapButton( m_panelTopCenter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonSwapSides = new wxBitmapButton( m_panelTopCenter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonSwapSides->SetToolTip( _("dummy") ); bSizer1771->Add( m_bpButtonSwapSides, 0, wxEXPAND, 5 ); @@ -319,17 +319,17 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer160; bSizer160 = new wxBoxSizer( wxHORIZONTAL ); - m_bpButtonLocalCompCfg = new wxBitmapButton( m_panelTopCenter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonLocalCompCfg = new wxBitmapButton( m_panelTopCenter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonLocalCompCfg->SetToolTip( _("dummy") ); bSizer160->Add( m_bpButtonLocalCompCfg, 0, wxEXPAND, 5 ); - m_bpButtonLocalFilter = new wxBitmapButton( m_panelTopCenter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonLocalFilter = new wxBitmapButton( m_panelTopCenter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonLocalFilter->SetToolTip( _("dummy") ); bSizer160->Add( m_bpButtonLocalFilter, 0, wxEXPAND, 5 ); - m_bpButtonLocalSyncCfg = new wxBitmapButton( m_panelTopCenter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonLocalSyncCfg = new wxBitmapButton( m_panelTopCenter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonLocalSyncCfg->SetToolTip( _("dummy") ); bSizer160->Add( m_bpButtonLocalSyncCfg, 0, wxEXPAND, 5 ); @@ -364,7 +364,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer179->Add( m_buttonSelectFolderRight, 0, wxEXPAND, 5 ); - m_bpButtonSelectAltFolderRight = new wxBitmapButton( m_panelTopRight, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonSelectAltFolderRight = new wxBitmapButton( m_panelTopRight, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonSelectAltFolderRight->SetToolTip( _("Access online storage") ); bSizer179->Add( m_bpButtonSelectAltFolderRight, 0, wxEXPAND, 5 ); @@ -429,7 +429,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer1781->Fit( m_splitterMain ); bSizer1711->Add( m_splitterMain, 1, wxEXPAND, 5 ); - m_panelStatusBar = new wxPanel( m_panelCenter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSTATIC_BORDER|wxTAB_TRAVERSAL ); + m_panelStatusBar = new wxPanel( m_panelCenter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL|wxBORDER_STATIC ); wxBoxSizer* bSizer451; bSizer451 = new wxBoxSizer( wxHORIZONTAL ); @@ -591,7 +591,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer1713; bSizer1713 = new wxBoxSizer( wxHORIZONTAL ); - m_bpButtonHideSearch = new wxBitmapButton( m_panelSearch, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonHideSearch = new wxBitmapButton( m_panelSearch, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonHideSearch->SetToolTip( _("Close search bar") ); bSizer1713->Add( m_bpButtonHideSearch, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 ); @@ -754,7 +754,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer17611; bSizer17611 = new wxBoxSizer( wxVERTICAL ); - m_bpButtonNew = new wxBitmapButton( m_panelConfig, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonNew = new wxBitmapButton( m_panelConfig, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonNew->SetToolTip( _("dummy") ); bSizer17611->Add( m_bpButtonNew, 0, wxEXPAND, 5 ); @@ -769,7 +769,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer1761; bSizer1761 = new wxBoxSizer( wxVERTICAL ); - m_bpButtonOpen = new wxBitmapButton( m_panelConfig, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonOpen = new wxBitmapButton( m_panelConfig, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonOpen->SetToolTip( _("dummy") ); bSizer1761->Add( m_bpButtonOpen, 0, wxEXPAND, 5 ); @@ -784,7 +784,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer175; bSizer175 = new wxBoxSizer( wxVERTICAL ); - m_bpButtonSave = new wxBitmapButton( m_panelConfig, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonSave = new wxBitmapButton( m_panelConfig, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonSave->SetToolTip( _("dummy") ); bSizer175->Add( m_bpButtonSave, 0, wxEXPAND, 5 ); @@ -802,12 +802,12 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer1772; bSizer1772 = new wxBoxSizer( wxHORIZONTAL ); - m_bpButtonSaveAs = new wxBitmapButton( m_panelConfig, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonSaveAs = new wxBitmapButton( m_panelConfig, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonSaveAs->SetToolTip( _("dummy") ); bSizer1772->Add( m_bpButtonSaveAs, 1, 0, 5 ); - m_bpButtonSaveAsBatch = new wxBitmapButton( m_panelConfig, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonSaveAsBatch = new wxBitmapButton( m_panelConfig, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonSaveAsBatch->SetToolTip( _("dummy") ); bSizer1772->Add( m_bpButtonSaveAsBatch, 1, 0, 5 ); @@ -838,7 +838,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_panelViewFilter = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); bSizerViewFilter = new wxBoxSizer( wxHORIZONTAL ); - m_bpButtonShowLog = new wxBitmapButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW ); + m_bpButtonShowLog = new wxBitmapButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowLog, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); @@ -847,10 +847,10 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer287; bSizer287 = new wxBoxSizer( wxHORIZONTAL ); - m_bpButtonViewTypeSyncAction = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonViewTypeSyncAction = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizer287->Add( m_bpButtonViewTypeSyncAction, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButtonViewContext = new wxBitmapButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonViewContext = new wxBitmapButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonViewContext->SetToolTip( _("dummy") ); bSizer287->Add( m_bpButtonViewContext, 0, wxRIGHT|wxEXPAND, 5 ); @@ -858,49 +858,49 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizerViewFilter->Add( bSizer287, 0, wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButtonShowExcluded = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowExcluded = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowExcluded, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxRIGHT, 5 ); - m_bpButtonShowDeleteLeft = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowDeleteLeft = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowDeleteLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonShowUpdateLeft = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowUpdateLeft = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowUpdateLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonShowCreateLeft = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowCreateLeft = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowCreateLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonShowLeftOnly = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowLeftOnly = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowLeftOnly, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonShowLeftNewer = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowLeftNewer = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowLeftNewer, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonShowEqual = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowEqual = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowEqual, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonShowDoNothing = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowDoNothing = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowDoNothing, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonShowDifferent = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowDifferent = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowDifferent, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonShowRightNewer = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowRightNewer = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowRightNewer, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonShowRightOnly = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowRightOnly = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowRightOnly, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonShowCreateRight = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowCreateRight = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowCreateRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonShowUpdateRight = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowUpdateRight = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowUpdateRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonShowDeleteRight = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowDeleteRight = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowDeleteRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonShowConflict = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonShowConflict = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizerViewFilter->Add( m_bpButtonShowConflict, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); @@ -910,7 +910,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_staticText96->Wrap( -1 ); bSizerViewFilter->Add( m_staticText96, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - m_panelStatistics = new wxPanel( m_panelViewFilter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxTAB_TRAVERSAL ); + m_panelStatistics = new wxPanel( m_panelViewFilter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL|wxBORDER_SUNKEN ); m_panelStatistics->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); bSizer1801 = new wxBoxSizer( wxVERTICAL ); @@ -1117,26 +1117,26 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const // Connect Events this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDialogGenerated::OnClose ) ); - this->Connect( m_menuItemNew->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigNew ) ); - this->Connect( m_menuItemLoad->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigLoad ) ); - this->Connect( m_menuItemSave->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigSave ) ); - this->Connect( m_menuItemSaveAs->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigSaveAs ) ); - this->Connect( m_menuItemSaveAsBatch->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnSaveAsBatchJob ) ); - this->Connect( m_menuItem4->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuQuit ) ); - this->Connect( m_menuItemShowLog->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnShowLog ) ); - this->Connect( m_menuItemCompare->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnCompare ) ); - this->Connect( m_menuItemCompSettings->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnCmpSettings ) ); - this->Connect( m_menuItemFilter->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigureFilter ) ); - this->Connect( m_menuItemSyncSettings->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnSyncSettings ) ); - this->Connect( m_menuItemSynchronize->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnStartSync ) ); - this->Connect( m_menuItemOptions->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuOptions ) ); - this->Connect( m_menuItemFind->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuFindItem ) ); - this->Connect( m_menuItemExportList->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuExportFileList ) ); - this->Connect( m_menuItem51->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuResetLayout ) ); - this->Connect( m_menuItemHelp->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnShowHelp ) ); - this->Connect( m_menuItemCheckVersionNow->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuCheckVersion ) ); - this->Connect( m_menuItemCheckVersionAuto->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuCheckVersionAutomatically ) ); - this->Connect( m_menuItemAbout->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuAbout ) ); + m_menuFile->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigNew ), this, m_menuItemNew->GetId()); + m_menuFile->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigLoad ), this, m_menuItemLoad->GetId()); + m_menuFile->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigSave ), this, m_menuItemSave->GetId()); + m_menuFile->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigSaveAs ), this, m_menuItemSaveAs->GetId()); + m_menuFile->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnSaveAsBatchJob ), this, m_menuItemSaveAsBatch->GetId()); + m_menuFile->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuQuit ), this, m_menuItemQuit->GetId()); + m_menu4->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnShowLog ), this, m_menuItemShowLog->GetId()); + m_menu4->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnCompare ), this, m_menuItemCompare->GetId()); + m_menu4->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnCmpSettings ), this, m_menuItemCompSettings->GetId()); + m_menu4->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigureFilter ), this, m_menuItemFilter->GetId()); + m_menu4->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnSyncSettings ), this, m_menuItemSyncSettings->GetId()); + m_menu4->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnStartSync ), this, m_menuItemSynchronize->GetId()); + m_menuTools->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuOptions ), this, m_menuItemOptions->GetId()); + m_menuTools->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuFindItem ), this, m_menuItemFind->GetId()); + m_menuTools->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuExportFileList ), this, m_menuItemExportList->GetId()); + m_menuTools->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuResetLayout ), this, m_menuItem51->GetId()); + m_menuHelp->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnShowHelp ), this, m_menuItemHelp->GetId()); + m_menuHelp->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuCheckVersion ), this, m_menuItemCheckVersionNow->GetId()); + m_menuHelp->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuCheckVersionAutomatically ), this, m_menuItemCheckVersionAuto->GetId()); + m_menuHelp->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuAbout ), this, m_menuItemAbout->GetId()); m_buttonCompare->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnCompare ), NULL, this ); m_bpButtonCmpConfig->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnCmpSettings ), NULL, this ); m_bpButtonCmpConfig->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnCompSettingsContext ), NULL, this ); @@ -1189,7 +1189,7 @@ MainDialogGenerated::~MainDialogGenerated() { } -FolderPairPanelGenerated::FolderPairPanelGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) +FolderPairPanelGenerated::FolderPairPanelGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : wxPanel( parent, id, pos, size, style, name ) { wxBoxSizer* bSizer74; bSizer74 = new wxBoxSizer( wxHORIZONTAL ); @@ -1200,12 +1200,12 @@ FolderPairPanelGenerated::FolderPairPanelGenerated( wxWindow* parent, wxWindowID wxBoxSizer* bSizer134; bSizer134 = new wxBoxSizer( wxHORIZONTAL ); - m_bpButtonFolderPairOptions = new wxBitmapButton( m_panelLeft, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonFolderPairOptions = new wxBitmapButton( m_panelLeft, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonFolderPairOptions->SetToolTip( _("Arrange folder pair") ); bSizer134->Add( m_bpButtonFolderPairOptions, 0, wxEXPAND, 5 ); - m_bpButtonRemovePair = new wxBitmapButton( m_panelLeft, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonRemovePair = new wxBitmapButton( m_panelLeft, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonRemovePair->SetToolTip( _("Remove folder pair") ); bSizer134->Add( m_bpButtonRemovePair, 0, wxEXPAND, 5 ); @@ -1218,7 +1218,7 @@ FolderPairPanelGenerated::FolderPairPanelGenerated( wxWindow* parent, wxWindowID bSizer134->Add( m_buttonSelectFolderLeft, 0, wxEXPAND, 5 ); - m_bpButtonSelectAltFolderLeft = new wxBitmapButton( m_panelLeft, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonSelectAltFolderLeft = new wxBitmapButton( m_panelLeft, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonSelectAltFolderLeft->SetToolTip( _("Access online storage") ); bSizer134->Add( m_bpButtonSelectAltFolderLeft, 0, wxEXPAND, 5 ); @@ -1233,17 +1233,17 @@ FolderPairPanelGenerated::FolderPairPanelGenerated( wxWindow* parent, wxWindowID wxBoxSizer* bSizer95; bSizer95 = new wxBoxSizer( wxHORIZONTAL ); - m_bpButtonLocalCompCfg = new wxBitmapButton( m_panel20, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonLocalCompCfg = new wxBitmapButton( m_panel20, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonLocalCompCfg->SetToolTip( _("dummy") ); bSizer95->Add( m_bpButtonLocalCompCfg, 0, wxEXPAND, 5 ); - m_bpButtonLocalFilter = new wxBitmapButton( m_panel20, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonLocalFilter = new wxBitmapButton( m_panel20, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonLocalFilter->SetToolTip( _("dummy") ); bSizer95->Add( m_bpButtonLocalFilter, 0, wxEXPAND, 5 ); - m_bpButtonLocalSyncCfg = new wxBitmapButton( m_panel20, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonLocalSyncCfg = new wxBitmapButton( m_panel20, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonLocalSyncCfg->SetToolTip( _("dummy") ); bSizer95->Add( m_bpButtonLocalSyncCfg, 0, wxEXPAND, 5 ); @@ -1268,7 +1268,7 @@ FolderPairPanelGenerated::FolderPairPanelGenerated( wxWindow* parent, wxWindowID bSizer135->Add( m_buttonSelectFolderRight, 0, wxEXPAND, 5 ); - m_bpButtonSelectAltFolderRight = new wxBitmapButton( m_panelRight, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonSelectAltFolderRight = new wxBitmapButton( m_panelRight, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonSelectAltFolderRight->SetToolTip( _("Access online storage") ); bSizer135->Add( m_bpButtonSelectAltFolderRight, 0, wxEXPAND, 5 ); @@ -1356,26 +1356,26 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w m_staticText91->Wrap( -1 ); bSizer182->Add( m_staticText91, 0, wxALL, 5 ); - wxBoxSizer* bSizer2381; - bSizer2381 = new wxBoxSizer( wxVERTICAL ); + wxGridSizer* gSizer2; + gSizer2 = new wxGridSizer( 0, 1, 5, 0 ); m_toggleBtnByTimeSize = new wxToggleButton( m_panelComparisonSettings, wxID_ANY, _("File time and size"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); m_toggleBtnByTimeSize->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); - bSizer2381->Add( m_toggleBtnByTimeSize, 0, wxEXPAND|wxBOTTOM, 5 ); + gSizer2->Add( m_toggleBtnByTimeSize, 0, wxEXPAND, 5 ); m_toggleBtnByContent = new wxToggleButton( m_panelComparisonSettings, wxID_ANY, _("File content"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); m_toggleBtnByContent->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); - bSizer2381->Add( m_toggleBtnByContent, 0, wxEXPAND|wxBOTTOM, 5 ); + gSizer2->Add( m_toggleBtnByContent, 0, wxEXPAND, 5 ); m_toggleBtnBySize = new wxToggleButton( m_panelComparisonSettings, wxID_ANY, _("File size"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); m_toggleBtnBySize->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); - bSizer2381->Add( m_toggleBtnBySize, 0, wxEXPAND, 5 ); + gSizer2->Add( m_toggleBtnBySize, 0, wxEXPAND, 5 ); - bSizer182->Add( bSizer2381, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + bSizer182->Add( gSizer2, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); bSizer178->Add( bSizer182, 0, wxALL, 5 ); @@ -1866,31 +1866,31 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w m_staticText86->Wrap( -1 ); bSizer235->Add( m_staticText86, 0, wxALL, 5 ); - wxBoxSizer* bSizer236; - bSizer236 = new wxBoxSizer( wxVERTICAL ); + wxGridSizer* gSizer1; + gSizer1 = new wxGridSizer( 0, 1, 5, 0 ); m_toggleBtnTwoWay = new wxToggleButton( m_panelSyncSettings, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); m_toggleBtnTwoWay->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); - bSizer236->Add( m_toggleBtnTwoWay, 0, wxBOTTOM|wxEXPAND, 5 ); + gSizer1->Add( m_toggleBtnTwoWay, 0, wxEXPAND, 5 ); m_toggleBtnMirror = new wxToggleButton( m_panelSyncSettings, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); m_toggleBtnMirror->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); - bSizer236->Add( m_toggleBtnMirror, 0, wxEXPAND|wxBOTTOM, 5 ); + gSizer1->Add( m_toggleBtnMirror, 0, wxEXPAND, 5 ); m_toggleBtnUpdate = new wxToggleButton( m_panelSyncSettings, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); m_toggleBtnUpdate->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); - bSizer236->Add( m_toggleBtnUpdate, 0, wxEXPAND|wxBOTTOM, 5 ); + gSizer1->Add( m_toggleBtnUpdate, 0, wxEXPAND, 5 ); m_toggleBtnCustom = new wxToggleButton( m_panelSyncSettings, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); m_toggleBtnCustom->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); - bSizer236->Add( m_toggleBtnCustom, 0, wxEXPAND, 5 ); + gSizer1->Add( m_toggleBtnCustom, 0, wxEXPAND, 5 ); - bSizer235->Add( bSizer236, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + bSizer235->Add( gSizer1, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); bSizer237->Add( bSizer235, 0, wxALL, 5 ); @@ -1946,22 +1946,22 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w ffgSizer11->Add( m_bitmapRightOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButtonLeftOnly = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonLeftOnly = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); ffgSizer11->Add( m_bpButtonLeftOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButtonLeftNewer = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonLeftNewer = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); ffgSizer11->Add( m_bpButtonLeftNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButtonDifferent = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonDifferent = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); ffgSizer11->Add( m_bpButtonDifferent, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButtonConflict = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonConflict = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); ffgSizer11->Add( m_bpButtonConflict, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButtonRightNewer = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonRightNewer = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); ffgSizer11->Add( m_bpButtonRightNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButtonRightOnly = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonRightOnly = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); ffgSizer11->Add( m_bpButtonRightOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); @@ -1974,7 +1974,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizerSyncDirHolder->Add( bSizerSyncDirections, 0, 0, 5 ); - bSizerDatabase = new wxWrapSizer( wxVERTICAL ); + bSizerDatabase = new wxBoxSizer( wxVERTICAL ); m_bitmapDatabase = new wxStaticBitmap( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), 0 ); bSizerDatabase->Add( m_bitmapDatabase, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); @@ -2133,7 +2133,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizer156->Add( m_buttonSelectVersioningFolder, 0, wxEXPAND, 5 ); - m_bpButtonSelectVersioningAltFolder = new wxBitmapButton( m_panelVersioning, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonSelectVersioningAltFolder = new wxBitmapButton( m_panelVersioning, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonSelectVersioningAltFolder->SetToolTip( _("Access online storage") ); bSizer156->Add( m_bpButtonSelectVersioningAltFolder, 0, wxEXPAND, 5 ); @@ -2280,7 +2280,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizer279->Add( m_buttonSelectLogFolder, 0, wxEXPAND, 5 ); - m_bpButtonSelectAltLogFolder = new wxBitmapButton( m_panelLogfile, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonSelectAltLogFolder = new wxBitmapButton( m_panelLogfile, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonSelectAltLogFolder->SetToolTip( _("Access online storage") ); bSizer279->Add( m_bpButtonSelectAltLogFolder, 0, wxEXPAND, 5 ); @@ -2353,6 +2353,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL ); m_buttonOkay = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonOkay->SetDefault(); m_buttonOkay->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); @@ -2889,6 +2890,7 @@ CloudSetupDlgGenerated::CloudSetupDlgGenerated( wxWindow* parent, wxWindowID id, bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL ); m_buttonOkay = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonOkay->SetDefault(); m_buttonOkay->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); @@ -2949,7 +2951,7 @@ AbstractFolderPickerGenerated::AbstractFolderPickerGenerated( wxWindow* parent, m_staticTextStatus->Wrap( -1 ); bSizer185->Add( m_staticTextStatus, 0, wxALL, 5 ); - m_treeCtrlFileSystem = new wxTreeCtrl( m_panel41, wxID_ANY, wxDefaultPosition, wxSize( -1, -1 ), wxTR_FULL_ROW_HIGHLIGHT|wxTR_HAS_BUTTONS|wxTR_LINES_AT_ROOT|wxTR_NO_LINES|wxNO_BORDER ); + m_treeCtrlFileSystem = new wxTreeCtrl( m_panel41, wxID_ANY, wxDefaultPosition, wxSize( -1, -1 ), wxTR_FULL_ROW_HIGHLIGHT|wxTR_HAS_BUTTONS|wxTR_LINES_AT_ROOT|wxTR_NO_LINES|wxBORDER_NONE ); bSizer185->Add( m_treeCtrlFileSystem, 1, wxEXPAND, 5 ); @@ -2964,6 +2966,7 @@ AbstractFolderPickerGenerated::AbstractFolderPickerGenerated( wxWindow* parent, bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL ); m_buttonOkay = new wxButton( this, wxID_OK, _("Select Folder"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonOkay->SetDefault(); m_buttonOkay->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); @@ -3185,6 +3188,7 @@ SyncConfirmationDlgGenerated::SyncConfirmationDlgGenerated( wxWindow* parent, wx bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL ); m_buttonStartSync = new wxButton( this, wxID_OK, _("Start"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonStartSync->SetDefault(); m_buttonStartSync->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); @@ -3216,7 +3220,7 @@ SyncConfirmationDlgGenerated::~SyncConfirmationDlgGenerated() { } -CompareProgressDlgGenerated::CompareProgressDlgGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) +CompareProgressDlgGenerated::CompareProgressDlgGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : wxPanel( parent, id, pos, size, style, name ) { this->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); @@ -3416,7 +3420,7 @@ CompareProgressDlgGenerated::~CompareProgressDlgGenerated() { } -SyncProgressPanelGenerated::SyncProgressPanelGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) +SyncProgressPanelGenerated::SyncProgressPanelGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : wxPanel( parent, id, pos, size, style, name ) { bSizerRoot = new wxBoxSizer( wxVERTICAL ); @@ -3443,7 +3447,7 @@ SyncProgressPanelGenerated::SyncProgressPanelGenerated( wxWindow* parent, wxWind bSizer247->Add( 0, 0, 1, 0, 5 ); - m_bpButtonMinimizeToTray = new wxBitmapButton( m_panel53, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonMinimizeToTray = new wxBitmapButton( m_panel53, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonMinimizeToTray->SetToolTip( _("Minimize to notification area") ); bSizer247->Add( m_bpButtonMinimizeToTray, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM, 5 ); @@ -3726,6 +3730,7 @@ SyncProgressPanelGenerated::SyncProgressPanelGenerated( wxWindow* parent, wxWind bSizerStdButtons->Add( 0, 0, 1, wxEXPAND, 5 ); m_buttonClose = new wxButton( this, wxID_OK, _("Close"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonClose->SetDefault(); m_buttonClose->Enable( false ); @@ -3750,7 +3755,7 @@ SyncProgressPanelGenerated::~SyncProgressPanelGenerated() { } -LogPanelGenerated::LogPanelGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) +LogPanelGenerated::LogPanelGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : wxPanel( parent, id, pos, size, style, name ) { this->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); @@ -3760,13 +3765,13 @@ LogPanelGenerated::LogPanelGenerated( wxWindow* parent, wxWindowID id, const wxP wxBoxSizer* bSizer154; bSizer154 = new wxBoxSizer( wxVERTICAL ); - m_bpButtonErrors = new zen::ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonErrors = new zen::ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizer154->Add( m_bpButtonErrors, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonWarnings = new zen::ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonWarnings = new zen::ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizer154->Add( m_bpButtonWarnings, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButtonInfo = new zen::ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonInfo = new zen::ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); bSizer154->Add( m_bpButtonInfo, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); @@ -3936,6 +3941,7 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL ); m_buttonSaveAs = new wxButton( this, wxID_SAVE, _("Save &as..."), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonSaveAs->SetDefault(); m_buttonSaveAs->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); @@ -4005,7 +4011,7 @@ DeleteDlgGenerated::DeleteDlgGenerated( wxWindow* parent, wxWindowID id, const w m_staticline42 = new wxStaticLine( m_panel31, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL ); bSizer185->Add( m_staticline42, 0, wxEXPAND, 5 ); - m_textCtrlFileList = new wxTextCtrl( m_panel31, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1, -1 ), wxTE_DONTWRAP|wxTE_MULTILINE|wxTE_READONLY|wxNO_BORDER ); + m_textCtrlFileList = new wxTextCtrl( m_panel31, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1, -1 ), wxTE_DONTWRAP|wxTE_MULTILINE|wxTE_READONLY|wxBORDER_NONE ); bSizer185->Add( m_textCtrlFileList, 1, wxEXPAND, 5 ); @@ -4026,6 +4032,7 @@ DeleteDlgGenerated::DeleteDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizerStdButtons->Add( 0, 0, 1, wxEXPAND, 5 ); m_buttonOK = new wxButton( this, wxID_OK, _("dummy"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonOK->SetDefault(); m_buttonOK->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); @@ -4094,7 +4101,7 @@ CopyToDlgGenerated::CopyToDlgGenerated( wxWindow* parent, wxWindowID id, const w m_staticline42 = new wxStaticLine( m_panel31, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL ); bSizer185->Add( m_staticline42, 0, wxEXPAND, 5 ); - m_textCtrlFileList = new wxTextCtrl( m_panel31, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1, -1 ), wxTE_DONTWRAP|wxTE_MULTILINE|wxTE_READONLY|wxNO_BORDER ); + m_textCtrlFileList = new wxTextCtrl( m_panel31, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1, -1 ), wxTE_DONTWRAP|wxTE_MULTILINE|wxTE_READONLY|wxBORDER_NONE ); bSizer185->Add( m_textCtrlFileList, 1, wxEXPAND, 5 ); @@ -4111,7 +4118,7 @@ CopyToDlgGenerated::CopyToDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizer182->Add( m_buttonSelectTargetFolder, 0, wxEXPAND, 5 ); - m_bpButtonSelectAltTargetFolder = new wxBitmapButton( m_panel31, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); + m_bpButtonSelectAltTargetFolder = new wxBitmapButton( m_panel31, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); m_bpButtonSelectAltTargetFolder->SetToolTip( _("Access online storage") ); bSizer182->Add( m_bpButtonSelectAltTargetFolder, 0, wxEXPAND, 5 ); @@ -4148,6 +4155,7 @@ CopyToDlgGenerated::CopyToDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizerStdButtons->Add( 0, 0, 1, wxEXPAND, 5 ); m_buttonOK = new wxButton( this, wxID_OK, _("Copy"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonOK->SetDefault(); m_buttonOK->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); @@ -4409,7 +4417,7 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const bSizer290->Add( m_buttonSelectSoundCompareDone, 0, wxEXPAND, 5 ); - m_bpButtonPlayCompareDone = new wxBitmapButton( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW ); + m_bpButtonPlayCompareDone = new wxBitmapButton( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 ); bSizer290->Add( m_bpButtonPlayCompareDone, 0, wxEXPAND, 5 ); @@ -4436,7 +4444,7 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const bSizer2901->Add( m_buttonSelectSoundSyncDone, 0, wxEXPAND, 5 ); - m_bpButtonPlaySyncDone = new wxBitmapButton( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW ); + m_bpButtonPlaySyncDone = new wxBitmapButton( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 ); bSizer2901->Add( m_bpButtonPlaySyncDone, 0, wxEXPAND, 5 ); @@ -4454,9 +4462,93 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer181; bSizer181 = new wxBoxSizer( wxVERTICAL ); + wxBoxSizer* bSizer289; + bSizer289 = new wxBoxSizer( wxHORIZONTAL ); + m_staticText85 = new wxStaticText( m_panel39, wxID_ANY, _("Customize context menu:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText85->Wrap( -1 ); - bSizer181->Add( m_staticText85, 0, wxBOTTOM, 5 ); + bSizer289->Add( m_staticText85, 1, wxRIGHT, 5 ); + + wxFlexGridSizer* fgSizer25; + fgSizer25 = new wxFlexGridSizer( 0, 2, 0, 10 ); + fgSizer25->SetFlexibleDirection( wxBOTH ); + fgSizer25->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_staticText174 = new wxStaticText( m_panel39, wxID_ANY, _("%item_path%"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText174->Wrap( -1 ); + m_staticText174->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) ); + m_staticText174->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); + + fgSizer25->Add( m_staticText174, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticText175 = new wxStaticText( m_panel39, wxID_ANY, _("Full file or folder path"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText175->Wrap( -1 ); + m_staticText175->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); + + fgSizer25->Add( m_staticText175, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticText178 = new wxStaticText( m_panel39, wxID_ANY, _("%local_path%"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText178->Wrap( -1 ); + m_staticText178->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) ); + m_staticText178->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); + + fgSizer25->Add( m_staticText178, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticText179 = new wxStaticText( m_panel39, wxID_ANY, _("Temporary local copy for SFTP and MTP storage"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText179->Wrap( -1 ); + m_staticText179->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); + + fgSizer25->Add( m_staticText179, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticText189 = new wxStaticText( m_panel39, wxID_ANY, _("%item_name%"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText189->Wrap( -1 ); + m_staticText189->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) ); + m_staticText189->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); + + fgSizer25->Add( m_staticText189, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticText190 = new wxStaticText( m_panel39, wxID_ANY, _("File or folder name"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText190->Wrap( -1 ); + m_staticText190->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); + + fgSizer25->Add( m_staticText190, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticText176 = new wxStaticText( m_panel39, wxID_ANY, _("%parent_path%"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText176->Wrap( -1 ); + m_staticText176->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) ); + m_staticText176->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); + + fgSizer25->Add( m_staticText176, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticText177 = new wxStaticText( m_panel39, wxID_ANY, _("Parent folder path"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText177->Wrap( -1 ); + m_staticText177->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); + + fgSizer25->Add( m_staticText177, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer289->Add( fgSizer25, 0, wxLEFT, 5 ); + + + bSizer181->Add( bSizer289, 0, wxEXPAND, 5 ); + + wxBoxSizer* bSizer193; + bSizer193 = new wxBoxSizer( wxHORIZONTAL ); + + m_bpButtonAddRow = new wxBitmapButton( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); + bSizer193->Add( m_bpButtonAddRow, 0, wxALIGN_BOTTOM, 5 ); + + m_bpButtonRemoveRow = new wxBitmapButton( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW|0 ); + bSizer193->Add( m_bpButtonRemoveRow, 0, wxALIGN_BOTTOM, 5 ); + + + bSizer193->Add( 0, 0, 1, wxEXPAND, 5 ); + + m_hyperlink17 = new wxHyperlinkCtrl( m_panel39, wxID_ANY, _("Show examples"), wxEmptyString, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); + bSizer193->Add( m_hyperlink17, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer181->Add( bSizer193, 0, wxEXPAND, 5 ); m_gridCustomCommand = new wxGrid( m_panel39, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); @@ -4473,12 +4565,12 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const m_gridCustomCommand->SetColLabelSize( -1 ); m_gridCustomCommand->SetColLabelValue( 0, _("Description") ); m_gridCustomCommand->SetColLabelValue( 1, _("Command line") ); - m_gridCustomCommand->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + m_gridCustomCommand->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER ); // Rows m_gridCustomCommand->EnableDragRowSize( false ); m_gridCustomCommand->SetRowLabelSize( 1 ); - m_gridCustomCommand->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + m_gridCustomCommand->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER ); // Label Appearance @@ -4486,24 +4578,6 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const m_gridCustomCommand->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); bSizer181->Add( m_gridCustomCommand, 1, wxEXPAND, 5 ); - wxBoxSizer* bSizer193; - bSizer193 = new wxBoxSizer( wxHORIZONTAL ); - - m_bpButtonAddRow = new wxBitmapButton( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); - bSizer193->Add( m_bpButtonAddRow, 0, wxEXPAND, 5 ); - - m_bpButtonRemoveRow = new wxBitmapButton( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW ); - bSizer193->Add( m_bpButtonRemoveRow, 0, wxEXPAND, 5 ); - - - bSizer193->Add( 0, 0, 1, wxEXPAND, 5 ); - - m_hyperlink17 = new wxHyperlinkCtrl( m_panel39, wxID_ANY, _("Show examples"), wxEmptyString, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - bSizer193->Add( m_hyperlink17, 0, wxLEFT, 5 ); - - - bSizer181->Add( bSizer193, 0, wxTOP|wxEXPAND, 5 ); - bSizer166->Add( bSizer181, 1, wxEXPAND|wxALL, 10 ); @@ -4525,6 +4599,7 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const bSizerStdButtons->Add( 0, 0, 1, 0, 5 ); m_buttonOkay = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonOkay->SetDefault(); m_buttonOkay->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); @@ -4604,10 +4679,10 @@ SelectTimespanDlgGenerated::SelectTimespanDlgGenerated( wxWindow* parent, wxWind wxBoxSizer* bSizer98; bSizer98 = new wxBoxSizer( wxHORIZONTAL ); - m_calendarFrom = new wxCalendarCtrl( m_panel35, wxID_ANY, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxCAL_SHOW_HOLIDAYS|wxNO_BORDER ); + m_calendarFrom = new wxCalendarCtrl( m_panel35, wxID_ANY, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxCAL_SHOW_HOLIDAYS|wxBORDER_NONE ); bSizer98->Add( m_calendarFrom, 0, wxTOP|wxBOTTOM|wxLEFT, 10 ); - m_calendarTo = new wxCalendarCtrl( m_panel35, wxID_ANY, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxCAL_SHOW_HOLIDAYS|wxNO_BORDER ); + m_calendarTo = new wxCalendarCtrl( m_panel35, wxID_ANY, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxCAL_SHOW_HOLIDAYS|wxBORDER_NONE ); bSizer98->Add( m_calendarTo, 0, wxALL, 10 ); @@ -4622,6 +4697,7 @@ SelectTimespanDlgGenerated::SelectTimespanDlgGenerated( wxWindow* parent, wxWind bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL ); m_buttonOkay = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonOkay->SetDefault(); m_buttonOkay->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); @@ -4666,69 +4742,29 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS wxBoxSizer* bSizer174; bSizer174 = new wxBoxSizer( wxHORIZONTAL ); + m_bitmapLogoLeft = new wxStaticBitmap( m_panel41, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + bSizer174->Add( m_bitmapLogoLeft, 0, 0, 5 ); + + m_staticline81 = new wxStaticLine( m_panel41, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL ); + bSizer174->Add( m_staticline81, 0, wxEXPAND, 5 ); + bSizerMainSection = new wxBoxSizer( wxVERTICAL ); + m_staticline82 = new wxStaticLine( m_panel41, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bSizerMainSection->Add( m_staticline82, 0, wxEXPAND, 5 ); + m_bitmapLogo = new wxStaticBitmap( m_panel41, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), 0 ); bSizerMainSection->Add( m_bitmapLogo, 0, 0, 5 ); m_staticline341 = new wxStaticLine( m_panel41, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); bSizerMainSection->Add( m_staticline341, 0, wxEXPAND, 5 ); - wxBoxSizer* bSizer186; - bSizer186 = new wxBoxSizer( wxVERTICAL ); - - m_staticText94 = new wxStaticText( m_panel41, wxID_ANY, _("Feedback and suggestions are welcome:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText94->Wrap( -1 ); - bSizer186->Add( m_staticText94, 0, wxALL, 5 ); - - ffgSizer11 = new wxFlexGridSizer( 2, 0, 5, 10 ); - ffgSizer11->SetFlexibleDirection( wxBOTH ); - ffgSizer11->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); - - m_bitmapHomepage = new wxStaticBitmap( m_panel41, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), 0 ); - m_bitmapHomepage->SetToolTip( _("Home page") ); - - ffgSizer11->Add( m_bitmapHomepage, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - - m_bitmapForum = new wxStaticBitmap( m_panel41, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), 0 ); - m_bitmapForum->SetToolTip( _("FreeFileSync Forum") ); - - ffgSizer11->Add( m_bitmapForum, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - - m_bitmapEmail = new wxStaticBitmap( m_panel41, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), 0 ); - m_bitmapEmail->SetToolTip( _("Email") ); - - ffgSizer11->Add( m_bitmapEmail, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - - m_hyperlink1 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("FreeFileSync.org"), wxT("https://freefilesync.org/"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink1->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, true, wxEmptyString ) ); - m_hyperlink1->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); - m_hyperlink1->SetToolTip( _("https://freefilesync.org") ); - - ffgSizer11->Add( m_hyperlink1, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - m_hyperlink21 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("FreeFileSync Forum"), wxT("https://freefilesync.org/forum/"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink21->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, true, wxEmptyString ) ); - m_hyperlink21->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); - m_hyperlink21->SetToolTip( _("https://freefilesync.org/forum/") ); - - ffgSizer11->Add( m_hyperlink21, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - m_hyperlink2 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("zenju@freefilesync.org"), wxT("mailto:zenju@freefilesync.org"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink2->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, true, wxEmptyString ) ); - m_hyperlink2->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); - m_hyperlink2->SetToolTip( _("mailto:zenju@freefilesync.org") ); - - ffgSizer11->Add( m_hyperlink2, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_staticTextVersion = new wxStaticText( m_panel41, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextVersion->Wrap( -1 ); + bSizerMainSection->Add( m_staticTextVersion, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 ); - - bSizer186->Add( ffgSizer11, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); - - - bSizerMainSection->Add( bSizer186, 0, wxALL|wxEXPAND, 5 ); - - m_staticline3412 = new wxStaticLine( m_panel41, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); - bSizerMainSection->Add( m_staticline3412, 0, wxEXPAND, 5 ); + m_staticline3411 = new wxStaticLine( m_panel41, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bSizerMainSection->Add( m_staticline3411, 0, wxEXPAND, 5 ); m_panelDonate = new wxPanel( m_panel41, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); m_panelDonate->SetBackgroundColour( wxColour( 153, 170, 187 ) ); @@ -4780,7 +4816,7 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_panelDonate->SetSizer( bSizer183 ); m_panelDonate->Layout(); bSizer183->Fit( m_panelDonate ); - bSizerMainSection->Add( m_panelDonate, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 10 ); + bSizerMainSection->Add( m_panelDonate, 0, wxEXPAND|wxALL, 10 ); m_panelThankYou = new wxPanel( m_panel41, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); m_panelThankYou->SetBackgroundColour( wxColour( 153, 170, 187 ) ); @@ -4831,121 +4867,68 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_panelThankYou->SetSizer( bSizer1831 ); m_panelThankYou->Layout(); bSizer1831->Fit( m_panelThankYou ); - bSizerMainSection->Add( m_panelThankYou, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 10 ); - - wxBoxSizer* bSizer187; - bSizer187 = new wxBoxSizer( wxVERTICAL ); - - m_staticText96 = new wxStaticText( m_panel41, wxID_ANY, _("Source code written in C++ using:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText96->Wrap( -1 ); - bSizer187->Add( m_staticText96, 0, wxALL, 5 ); - - wxBoxSizer* bSizer171; - bSizer171 = new wxBoxSizer( wxHORIZONTAL ); - - m_hyperlink11 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("MS Visual Studio"), wxT("https://www.visualstudio.com"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink11->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); - m_hyperlink11->SetToolTip( _("https://www.visualstudio.com") ); - - bSizer171->Add( m_hyperlink11, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); - - m_hyperlink7 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("wxWidgets"), wxT("https://www.wxwidgets.org"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink7->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); - m_hyperlink7->SetToolTip( _("https://www.wxwidgets.org") ); - - bSizer171->Add( m_hyperlink7, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); - - m_hyperlink14 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("wxFormBuilder"), wxT("https://github.com/wxFormBuilder/wxFormBuilder"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink14->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); - m_hyperlink14->SetToolTip( _("https://github.com/wxFormBuilder/wxFormBuilder") ); + bSizerMainSection->Add( m_panelThankYou, 0, wxEXPAND|wxALL, 10 ); - bSizer171->Add( m_hyperlink14, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); - - m_hyperlink16 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("Artistic Style"), wxT("http://astyle.sourceforge.net"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink16->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); - m_hyperlink16->SetToolTip( _("http://astyle.sourceforge.net") ); - - bSizer171->Add( m_hyperlink16, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - - bSizer187->Add( bSizer171, 0, wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); - - wxBoxSizer* bSizer172; - bSizer172 = new wxBoxSizer( wxHORIZONTAL ); + m_staticline3412 = new wxStaticLine( m_panel41, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bSizerMainSection->Add( m_staticline3412, 0, wxEXPAND, 5 ); - m_hyperlink15 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("zen::Xml"), wxT("http://zenxml.sourceforge.net"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink15->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); - m_hyperlink15->SetToolTip( _("http://zenxml.sourceforge.net") ); + wxBoxSizer* bSizer186; + bSizer186 = new wxBoxSizer( wxVERTICAL ); - bSizer172->Add( m_hyperlink15, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); + m_staticText94 = new wxStaticText( m_panel41, wxID_ANY, _("Feedback and suggestions are welcome:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText94->Wrap( -1 ); + bSizer186->Add( m_staticText94, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP|wxRIGHT|wxLEFT, 5 ); - m_hyperlink12 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("Google Test"), wxT("https://github.com/google/googletest"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink12->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); - m_hyperlink12->SetToolTip( _("https://github.com/google/googletest") ); + wxBoxSizer* bSizer289; + bSizer289 = new wxBoxSizer( wxHORIZONTAL ); - bSizer172->Add( m_hyperlink12, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); + m_bpButtonForum = new wxBitmapButton( m_panel41, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 ); + m_bpButtonForum->SetToolTip( _("https://freefilesync.org/forum/") ); - m_hyperlink10 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("libssh2"), wxT("https://www.libssh2.org"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink10->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); - m_hyperlink10->SetToolTip( _("https://www.libssh2.org") ); + bSizer289->Add( m_bpButtonForum, 0, wxALL|wxEXPAND, 5 ); - bSizer172->Add( m_hyperlink10, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); + wxBoxSizer* bSizer290; + bSizer290 = new wxBoxSizer( wxVERTICAL ); - m_hyperlink101 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("libcurl"), wxT("https://curl.haxx.se/libcurl"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink101->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); - m_hyperlink101->SetToolTip( _("https://curl.haxx.se/libcurl") ); + m_bpButtonHomepage = new wxBitmapButton( m_panel41, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 ); + m_bpButtonHomepage->SetToolTip( _("https://freefilesync.org") ); - bSizer172->Add( m_hyperlink101, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer290->Add( m_bpButtonHomepage, 1, wxTOP|wxRIGHT|wxEXPAND, 5 ); - m_hyperlink18 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("NSIS"), wxT("https://nsis.sourceforge.io"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink18->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); - m_hyperlink18->SetToolTip( _("https://nsis.sourceforge.io") ); - bSizer172->Add( m_hyperlink18, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); + bSizer290->Add( 0, 5, 0, 0, 5 ); - m_hyperlink9 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("Inno Setup"), wxT("http://www.jrsoftware.org/isinfo.php"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink9->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); - m_hyperlink9->SetToolTip( _("http://www.jrsoftware.org/isinfo.php") ); + m_bpButtonEmail = new wxBitmapButton( m_panel41, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 ); + m_bpButtonEmail->SetToolTip( _("mailto:zenju@freefilesync.org") ); - bSizer172->Add( m_hyperlink9, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); + bSizer290->Add( m_bpButtonEmail, 1, wxEXPAND|wxBOTTOM|wxRIGHT, 5 ); - m_hyperlink25 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("xBRZ"), wxT("https://sourceforge.net/projects/xbrz/"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink25->SetToolTip( _("https://sourceforge.net/projects/xbrz/") ); - bSizer172->Add( m_hyperlink25, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer289->Add( bSizer290, 0, wxEXPAND, 5 ); - bSizer187->Add( bSizer172, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_HORIZONTAL, 5 ); + bSizer186->Add( bSizer289, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); - bSizerMainSection->Add( bSizer187, 0, wxALL|wxEXPAND, 5 ); + bSizerMainSection->Add( bSizer186, 0, wxALL|wxEXPAND, 5 ); m_staticline34 = new wxStaticLine( m_panel41, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); bSizerMainSection->Add( m_staticline34, 0, wxEXPAND, 5 ); wxBoxSizer* bSizer185; - bSizer185 = new wxBoxSizer( wxVERTICAL ); - - m_staticText93 = new wxStaticText( m_panel41, wxID_ANY, _("Published under the GNU General Public License:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText93->Wrap( -1 ); - bSizer185->Add( m_staticText93, 0, wxALL, 5 ); - - wxBoxSizer* bSizer1671; - bSizer1671 = new wxBoxSizer( wxHORIZONTAL ); - - m_bitmapGpl = new wxStaticBitmap( m_panel41, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), 0 ); - bSizer1671->Add( m_bitmapGpl, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); - - m_hyperlink5 = new wxHyperlinkCtrl( m_panel41, wxID_ANY, _("https://www.gnu.org/licenses/gpl-3.0"), wxT("https://www.gnu.org/licenses/gpl-3.0"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - m_hyperlink5->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); + bSizer185 = new wxBoxSizer( wxHORIZONTAL ); - bSizer1671->Add( m_hyperlink5, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_staticTextGpl = new wxStaticText( m_panel41, wxID_ANY, _("Published under the GNU General Public License:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextGpl->Wrap( -1 ); + bSizer185->Add( m_staticTextGpl, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + m_bpButtonGpl = new wxBitmapButton( m_panel41, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 ); + m_bpButtonGpl->SetToolTip( _("https://www.gnu.org/licenses/gpl-3.0") ); - bSizer185->Add( bSizer1671, 0, wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + bSizer185->Add( m_bpButtonGpl, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 ); - bSizerMainSection->Add( bSizer185, 0, wxALL|wxEXPAND, 5 ); + bSizerMainSection->Add( bSizer185, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 ); bSizer174->Add( bSizerMainSection, 0, 0, 5 ); @@ -4956,17 +4939,9 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS wxBoxSizer* bSizer177; bSizer177 = new wxBoxSizer( wxVERTICAL ); - m_staticline74 = new wxStaticLine( m_panel41, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); - bSizer177->Add( m_staticline74, 0, wxEXPAND, 5 ); - - m_staticTextThanksForLoc = new wxStaticText( m_panel41, wxID_ANY, _("Many thanks for localization:"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_staticTextThanksForLoc = new wxStaticText( m_panel41, wxID_ANY, _("Many thanks for localization:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextThanksForLoc->Wrap( -1 ); - m_staticTextThanksForLoc->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); - - bSizer177->Add( m_staticTextThanksForLoc, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP|wxRIGHT|wxLEFT, 10 ); - - - bSizer177->Add( 0, 5, 0, 0, 5 ); + bSizer177->Add( m_staticTextThanksForLoc, 0, wxALL, 5 ); m_scrolledWindowTranslators = new wxScrolledWindow( m_panel41, wxID_ANY, wxDefaultPosition, wxSize( -1, -1 ), wxVSCROLL ); m_scrolledWindowTranslators->SetScrollRate( 10, 10 ); @@ -4980,10 +4955,10 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_scrolledWindowTranslators->SetSizer( fgSizerTranslators ); m_scrolledWindowTranslators->Layout(); fgSizerTranslators->Fit( m_scrolledWindowTranslators ); - bSizer177->Add( m_scrolledWindowTranslators, 1, wxLEFT|wxEXPAND, 10 ); + bSizer177->Add( m_scrolledWindowTranslators, 1, wxEXPAND|wxLEFT, 5 ); - bSizer174->Add( bSizer177, 0, wxEXPAND, 5 ); + bSizer174->Add( bSizer177, 0, wxEXPAND|wxLEFT, 5 ); m_panel41->SetSizer( bSizer174 ); @@ -4997,6 +4972,7 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL ); m_buttonClose = new wxButton( this, wxID_OK, _("Close"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonClose->SetDefault(); bSizerStdButtons->Add( m_buttonClose, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); @@ -5014,6 +4990,10 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( AboutDlgGenerated::OnClose ) ); m_buttonDonate->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AboutDlgGenerated::OnDonate ), NULL, this ); m_buttonShowDonationDetails->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AboutDlgGenerated::OnShowDonationDetails ), NULL, this ); + m_bpButtonForum->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AboutDlgGenerated::OnOpenForum ), NULL, this ); + m_bpButtonHomepage->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AboutDlgGenerated::OnOpenHomepage ), NULL, this ); + m_bpButtonEmail->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AboutDlgGenerated::OnSendEmail ), NULL, this ); + m_bpButtonGpl->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AboutDlgGenerated::OnShowGpl ), NULL, this ); m_buttonClose->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AboutDlgGenerated::OnOK ), NULL, this ); } @@ -5064,6 +5044,7 @@ DownloadProgressDlgGenerated::DownloadProgressDlgGenerated( wxWindow* parent, wx bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL ); m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonCancel->SetDefault(); bSizerStdButtons->Add( m_buttonCancel, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); @@ -5112,7 +5093,7 @@ ActivationDlgGenerated::ActivationDlgGenerated( wxWindow* parent, wxWindowID id, bSizer16->Add( 0, 10, 0, 0, 5 ); - m_textCtrlLastError = new wxTextCtrl( m_panel35, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxNO_BORDER ); + m_textCtrlLastError = new wxTextCtrl( m_panel35, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxBORDER_NONE ); bSizer16->Add( m_textCtrlLastError, 1, wxEXPAND, 5 ); @@ -5158,6 +5139,7 @@ ActivationDlgGenerated::ActivationDlgGenerated( wxWindow* parent, wxWindowID id, bSizer234->Add( m_staticText136, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); m_buttonActivateOnline = new wxButton( m_panel3511, wxID_ANY, _("Activate online"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonActivateOnline->SetDefault(); m_buttonActivateOnline->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); @@ -5306,6 +5288,7 @@ CfgHighlightDlgGenerated::CfgHighlightDlgGenerated( wxWindow* parent, wxWindowID bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL ); m_buttonOkay = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonOkay->SetDefault(); m_buttonOkay->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); @@ -5416,6 +5399,7 @@ WarnAccessRightsMissingDlgGenerated::WarnAccessRightsMissingDlgGenerated( wxWind bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL ); m_buttonClose = new wxButton( this, wxID_OK, _("Close"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonClose->SetDefault(); bSizerStdButtons->Add( m_buttonClose, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); diff --git a/FreeFileSync/Source/ui/gui_generated.h b/FreeFileSync/Source/ui/gui_generated.h index 15653910..2a966144 100644 --- a/FreeFileSync/Source/ui/gui_generated.h +++ b/FreeFileSync/Source/ui/gui_generated.h @@ -1,12 +1,11 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version May 29 2018) +// C++ code generated with wxFormBuilder (version Oct 26 2018) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// -#ifndef __GUI_GENERATED_H__ -#define __GUI_GENERATED_H__ +#pragma once #include #include @@ -45,7 +44,6 @@ #include #include #include -#include #include #include #include @@ -73,6 +71,7 @@ protected: wxMenuItem* m_menuItemSave; wxMenuItem* m_menuItemSaveAs; wxMenuItem* m_menuItemSaveAsBatch; + wxMenuItem* m_menuItemQuit; wxMenu* m_menu4; wxMenuItem* m_menuItemShowLog; wxMenuItem* m_menuItemCompare; @@ -308,7 +307,7 @@ public: fff::FolderHistoryBox* m_folderPathRight; wxBitmapButton* m_bpButtonSelectAltFolderRight; - FolderPairPanelGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0 ); + FolderPairPanelGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = wxEmptyString ); ~FolderPairPanelGenerated(); }; @@ -428,7 +427,7 @@ protected: wxBitmapButton* m_bpButtonRightNewer; wxBitmapButton* m_bpButtonRightOnly; wxStaticText* m_staticText120; - wxWrapSizer* bSizerDatabase; + wxBoxSizer* bSizerDatabase; wxStaticBitmap* m_bitmapDatabase; wxStaticText* m_staticText145; wxStaticText* m_staticTextSyncVarDescription; @@ -772,7 +771,7 @@ public: wxBoxSizer* bSizerErrorsIgnore; wxStaticBitmap* m_bitmapIgnoreErrors; - CompareProgressDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = wxRAISED_BORDER ); + CompareProgressDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = wxBORDER_RAISED, const wxString& name = wxEmptyString ); ~CompareProgressDlgGenerated(); }; @@ -834,7 +833,7 @@ public: wxButton* m_buttonPause; wxButton* m_buttonStop; - SyncProgressPanelGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = wxTAB_TRAVERSAL ); + SyncProgressPanelGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString ); ~SyncProgressPanelGenerated(); }; @@ -861,7 +860,7 @@ protected: public: zen::Grid* m_gridMessages; - LogPanelGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL ); + LogPanelGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString ); ~LogPanelGenerated(); }; @@ -1039,10 +1038,18 @@ protected: wxBitmapButton* m_bpButtonPlaySyncDone; wxStaticLine* m_staticline3611; wxStaticText* m_staticText85; - wxGrid* m_gridCustomCommand; + wxStaticText* m_staticText174; + wxStaticText* m_staticText175; + wxStaticText* m_staticText178; + wxStaticText* m_staticText179; + wxStaticText* m_staticText189; + wxStaticText* m_staticText190; + wxStaticText* m_staticText176; + wxStaticText* m_staticText177; wxBitmapButton* m_bpButtonAddRow; wxBitmapButton* m_bpButtonRemoveRow; wxHyperlinkCtrl* m_hyperlink17; + wxGrid* m_gridCustomCommand; wxStaticLine* m_staticline36; wxBoxSizer* bSizerStdButtons; wxButton* m_buttonDefault; @@ -1132,18 +1139,14 @@ private: protected: wxPanel* m_panel41; + wxStaticBitmap* m_bitmapLogoLeft; + wxStaticLine* m_staticline81; wxBoxSizer* bSizerMainSection; + wxStaticLine* m_staticline82; wxStaticBitmap* m_bitmapLogo; wxStaticLine* m_staticline341; - wxStaticText* m_staticText94; - wxFlexGridSizer* ffgSizer11; - wxStaticBitmap* m_bitmapHomepage; - wxStaticBitmap* m_bitmapForum; - wxStaticBitmap* m_bitmapEmail; - wxHyperlinkCtrl* m_hyperlink1; - wxHyperlinkCtrl* m_hyperlink21; - wxHyperlinkCtrl* m_hyperlink2; - wxStaticLine* m_staticline3412; + wxStaticText* m_staticTextVersion; + wxStaticLine* m_staticline3411; wxPanel* m_panelDonate; wxPanel* m_panel39; wxStaticBitmap* m_bitmapDonate; @@ -1155,24 +1158,15 @@ protected: wxStaticText* m_staticTextThanks; wxStaticText* m_staticTextNoAutoUpdate; wxButton* m_buttonShowDonationDetails; - wxStaticText* m_staticText96; - wxHyperlinkCtrl* m_hyperlink11; - wxHyperlinkCtrl* m_hyperlink7; - wxHyperlinkCtrl* m_hyperlink14; - wxHyperlinkCtrl* m_hyperlink16; - wxHyperlinkCtrl* m_hyperlink15; - wxHyperlinkCtrl* m_hyperlink12; - wxHyperlinkCtrl* m_hyperlink10; - wxHyperlinkCtrl* m_hyperlink101; - wxHyperlinkCtrl* m_hyperlink18; - wxHyperlinkCtrl* m_hyperlink9; - wxHyperlinkCtrl* m_hyperlink25; + wxStaticLine* m_staticline3412; + wxStaticText* m_staticText94; + wxBitmapButton* m_bpButtonForum; + wxBitmapButton* m_bpButtonHomepage; + wxBitmapButton* m_bpButtonEmail; wxStaticLine* m_staticline34; - wxStaticText* m_staticText93; - wxStaticBitmap* m_bitmapGpl; - wxHyperlinkCtrl* m_hyperlink5; + wxStaticText* m_staticTextGpl; + wxBitmapButton* m_bpButtonGpl; wxStaticLine* m_staticline37; - wxStaticLine* m_staticline74; wxStaticText* m_staticTextThanksForLoc; wxScrolledWindow* m_scrolledWindowTranslators; wxFlexGridSizer* fgSizerTranslators; @@ -1184,6 +1178,10 @@ protected: virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } virtual void OnDonate( wxCommandEvent& event ) { event.Skip(); } virtual void OnShowDonationDetails( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOpenForum( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOpenHomepage( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSendEmail( wxCommandEvent& event ) { event.Skip(); } + virtual void OnShowGpl( wxCommandEvent& event ) { event.Skip(); } virtual void OnOK( wxCommandEvent& event ) { event.Skip(); } @@ -1339,4 +1337,3 @@ public: }; -#endif //__GUI_GENERATED_H__ diff --git a/FreeFileSync/Source/ui/log_panel.cpp b/FreeFileSync/Source/ui/log_panel.cpp index 8e770d43..51cfa703 100644 --- a/FreeFileSync/Source/ui/log_panel.cpp +++ b/FreeFileSync/Source/ui/log_panel.cpp @@ -190,6 +190,11 @@ public: return std::wstring(); } + void renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected) override + { + GridData::renderRowBackgound(dc, rect, row, true /*enabled*/, enabled && selected); + } + void renderCell(wxDC& dc, const wxRect& rect, size_t row, ColumnType colType, bool enabled, bool selected, HoverArea rowHover) override { wxRect rectTmp = rect; @@ -249,11 +254,6 @@ public: } } - void renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected) override - { - GridData::renderRowBackgound(dc, rect, row, true /*enabled*/, enabled && selected); - } - int getBestSize(wxDC& dc, size_t row, ColumnType colType) override { // -> synchronize renderCell() <-> getBestSize() diff --git a/FreeFileSync/Source/ui/main_dlg.cpp b/FreeFileSync/Source/ui/main_dlg.cpp index b77a2a7e..5fbaea53 100644 --- a/FreeFileSync/Source/ui/main_dlg.cpp +++ b/FreeFileSync/Source/ui/main_dlg.cpp @@ -57,7 +57,7 @@ using namespace fff; namespace { const size_t EXT_APP_MASS_INVOKE_THRESHOLD = 10; //more is likely a user mistake (Explorer uses limit of 15) -const int TOP_BUTTON_OPTIMAL_WIDTH_DIP = 180; +const int TOP_BUTTON_OPTIMAL_WIDTH_DIP = 170; const std::chrono::milliseconds LAST_USED_CFG_EXISTENCE_CHECK_TIME_MAX(500); const std::chrono::milliseconds FILE_GRID_POST_UPDATE_DELAY(400); @@ -243,14 +243,14 @@ void updateTopButton(wxBitmapButton& btn, const wxBitmap& bmp, const wxString& v wxImage variantImage = createImageFromText(variantName, wxFont(wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD), wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT)); - wxImage descrImage = stackImages(labelImage, variantImage, ImageStackLayout::VERTICAL, ImageStackAlignment::CENTER); + wxImage descrImage = stackImages(labelImage, variantImage, ImageStackLayout::vertical, ImageStackAlignment::center); const wxImage& iconImage = makeGrey ? greyScale(bmp.ConvertToImage()) : bmp.ConvertToImage(); wxImage dynImage = btn.GetLayoutDirection() != wxLayout_RightToLeft ? - stackImages(iconImage, descrImage, ImageStackLayout::HORIZONTAL, ImageStackAlignment::CENTER, fastFromDIP(5)) : - stackImages(descrImage, iconImage, ImageStackLayout::HORIZONTAL, ImageStackAlignment::CENTER, fastFromDIP(5)); + stackImages(iconImage, descrImage, ImageStackLayout::horizontal, ImageStackAlignment::center, fastFromDIP(5)) : + stackImages(descrImage, iconImage, ImageStackLayout::horizontal, ImageStackAlignment::center, fastFromDIP(5)); - wxSize btnSize = dynImage.GetSize() + wxSize(fastFromDIP(16), fastFromDIP(16)); //add border space + wxSize btnSize = dynImage.GetSize() + wxSize(fastFromDIP(10), fastFromDIP(10)); //add border space btnSize.x = std::max(btnSize.x, fastFromDIP(TOP_BUTTON_OPTIMAL_WIDTH_DIP)); dynImage.Resize(btnSize, wxPoint() + (btnSize - dynImage.GetSize()) / 2); @@ -424,8 +424,8 @@ MainDialog::MainDialog(const Zstring& globalConfigFilePath, m_bpButtonHideSearch ->SetBitmapLabel(getResourceImage(L"close_panel")); m_bpButtonShowLog ->SetBitmapLabel(getResourceImage(L"log_file")); - m_bpButtonFilter ->SetMinSize(wxSize(getResourceImage(L"cfg_filter").GetWidth() + fastFromDIP(27), -1)); //make the filter button wider - m_textCtrlSearchTxt->SetMinSize(wxSize(fastFromDIP(220), -1)); + m_bpButtonFilter ->SetMinSize({getResourceImage(L"cfg_filter").GetWidth() + fastFromDIP(27), -1}); //make the filter button wider + m_textCtrlSearchTxt->SetMinSize({fastFromDIP(220), -1}); //---------------------------------------------------------------------------------------- wxImage labelImage = createImageFromText(_("Select view:"), m_bpButtonViewTypeSyncAction->GetFont(), wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT)); @@ -435,7 +435,7 @@ MainDialog::MainDialog(const Zstring& globalConfigFilePath, auto generateViewTypeImage = [&](const wxString& imgName) { - return stackImages(labelImage, mirrorIfRtl(getResourceImage(imgName).ConvertToImage()), ImageStackLayout::VERTICAL, ImageStackAlignment::CENTER); + return stackImages(labelImage, mirrorIfRtl(getResourceImage(imgName).ConvertToImage()), ImageStackLayout::vertical, ImageStackAlignment::center); }; m_bpButtonViewTypeSyncAction->init(generateViewTypeImage(L"viewtype_sync_action"), generateViewTypeImage(L"viewtype_cmp_result")); @@ -465,8 +465,11 @@ MainDialog::MainDialog(const Zstring& globalConfigFilePath, //init log panel setRelativeFontSize(*m_staticTextLogStatus, 1.5); + const wxBitmap& bmpTime = getResourceImage(L"cmp_file_time_sicon"); m_bitmapItemStat->SetBitmap(bmpFile); - m_bitmapTimeStat->SetBitmap(getResourceImage(L"cmp_file_time_sicon")); + m_bitmapTimeStat->SetBitmap(bmpTime); + m_bitmapItemStat->SetMinSize({-1, std::max(IconBuffer::getSize(IconBuffer::SIZE_SMALL), bmpTime.GetHeight())}); + m_bitmapTimeStat->SetMinSize({-1, std::max(IconBuffer::getSize(IconBuffer::SIZE_SMALL), bmpTime.GetHeight())}); logPanel_ = new LogPanel(m_panelLog); //pass ownership bSizerLog->Add(logPanel_, 1, wxEXPAND); @@ -511,8 +514,8 @@ MainDialog::MainDialog(const Zstring& globalConfigFilePath, m_panelTopButtons->GetSizer()->SetSizeHints(m_panelTopButtons); //~=Fit() + SetMinSize() m_buttonCancel->SetBitmap(getTransparentPixel()); //set dummy image (can't be empty!): text-only buttons are rendered smaller on OS X! - m_buttonCancel->SetMinSize(wxSize(std::max(m_buttonCancel->GetSize().x, fastFromDIP(TOP_BUTTON_OPTIMAL_WIDTH_DIP)), - std::max(m_buttonCancel->GetSize().y, m_buttonCompare->GetSize().y))); + m_buttonCancel->SetMinSize({std::max(m_buttonCancel->GetSize().x, fastFromDIP(TOP_BUTTON_OPTIMAL_WIDTH_DIP)), + std::max(m_buttonCancel->GetSize().y, m_buttonCompare->GetSize().y)}); auiMgr_.AddPane(m_panelTopButtons, wxAuiPaneInfo().Name(L"TopPanel").Layer(2).Top().Row(1).Caption(_("Main Bar")).CaptionVisible(false). @@ -608,6 +611,7 @@ MainDialog::MainDialog(const Zstring& globalConfigFilePath, m_panelSearch->Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(MainDialog::OnSearchPanelKeyPressed), nullptr, this); + //set tool tips with (non-translated!) short cut hint m_bpButtonNew ->SetToolTip(replaceCpy(_("&New"), L"&", L"") + L" (Ctrl+N)"); // m_bpButtonOpen ->SetToolTip(replaceCpy(_("&Open..."), L"&", L"") + L" (Ctrl+O)"); // @@ -1014,19 +1018,28 @@ void MainDialog::setGlobalCfgOnInit(const XmlGlobalSettings& globalSettings) paneCaptions.emplace_back(&paneArray[i], paneArray[i].caption); //compare progress dialog minimum sizes are layout-dependent + can't be changed by user => don't load stale values from config + std::vector> paneConstraints; + auto preserveConstraint = [&paneConstraints](wxAuiPaneInfo& pane) { paneConstraints.emplace_back(&pane, pane.min_size, pane.best_size); }; + wxAuiPaneInfo& progPane = auiMgr_.GetPane(compareStatus_->getAsWindow()); - wxAuiPaneInfo& viewPane = auiMgr_.GetPane(m_panelViewFilter); //same goes for view filter - const std::pair progPaneSizeOrig(progPane.min_size, progPane.best_size); - const std::pair viewPaneSizeOrig(viewPane.min_size, viewPane.best_size); + preserveConstraint(auiMgr_.GetPane(m_panelTopButtons)); + preserveConstraint(progPane); + preserveConstraint(auiMgr_.GetPane(m_panelSearch)); + preserveConstraint(auiMgr_.GetPane(m_panelViewFilter)); + preserveConstraint(auiMgr_.GetPane(m_panelConfig)); - auiMgr_.LoadPerspective(globalSettings.gui.mainDlg.guiPerspectiveLast); + auiMgr_.LoadPerspective(globalSettings.gui.mainDlg.guiPerspectiveLast, false /*don't call wxAuiManager::Update() yet*/); //restore original captions for (const auto& [paneInfo, caption] : paneCaptions) paneInfo->Caption(caption); - std::tie(progPane.min_size, progPane.best_size) = progPaneSizeOrig; - std::tie(viewPane.min_size, viewPane.best_size) = viewPaneSizeOrig; + //restore pane layout constraints + for (auto& [pane, minSize, bestSize] : paneConstraints) + { + pane->min_size = minSize; + pane->best_size = bestSize; + } //-------------------------------------------------------------------------------- //if MainDialog::onQueryEndSession() is called while comparison is active, this panel is saved and restored as "visible" @@ -1464,9 +1477,11 @@ void invokeCommandLine(const Zstring& commandLinePhrase, //throw FileError const AbstractPath basePath = fsObj->base().getAbstractPath(); const AbstractPath basePath2 = fsObj->base().getAbstractPath(); - //full path, even if item is not (yet) existing: - const Zstring itemPath = AFS::isNullPath(basePath ) ? Zstr("") : utfTo(AFS::getDisplayPath(fsObj-> getAbstractPath())); - const Zstring itemPath2 = AFS::isNullPath(basePath2) ? Zstr("") : utfTo(AFS::getDisplayPath(fsObj-> getAbstractPath())); + //return paths, even if item is not (yet) existing: + const Zstring itemPath = AFS::isNullPath(basePath ) ? Zstr("") : utfTo(AFS::getDisplayPath(fsObj-> getAbstractPath())); + const Zstring itemPath2 = AFS::isNullPath(basePath2) ? Zstr("") : utfTo(AFS::getDisplayPath(fsObj-> getAbstractPath())); + const Zstring itemName = AFS::isNullPath(basePath ) ? Zstr("") : AFS::getItemName (fsObj-> getAbstractPath()); + const Zstring itemName2 = AFS::isNullPath(basePath2) ? Zstr("") : AFS::getItemName (fsObj-> getAbstractPath()); const Zstring folderPath = AFS::isNullPath(basePath ) ? Zstr("") : utfTo(AFS::getDisplayPath(fsObj->parent().getAbstractPath())); const Zstring folderPath2 = AFS::isNullPath(basePath2) ? Zstr("") : utfTo(AFS::getDisplayPath(fsObj->parent().getAbstractPath())); @@ -1489,10 +1504,12 @@ void invokeCommandLine(const Zstring& commandLinePhrase, //throw FileError Zstring command = commandLinePhrase; replace(command, Zstr("%item_path%"), itemPath); replace(command, Zstr("%item_path2%"), itemPath2); - replace(command, Zstr("%folder_path%"), folderPath); - replace(command, Zstr("%folder_path2%"), folderPath2); replace(command, Zstr("%local_path%"), localPath); replace(command, Zstr("%local_path2%"), localPath2); + replace(command, Zstr("%item_name%"), itemName); + replace(command, Zstr("%item_name2%"), itemName2); + replace(command, Zstr("%parent_path%"), folderPath); + replace(command, Zstr("%parent_path2%"), folderPath2); shellExecute(command, selection.size() > EXT_APP_MASS_INVOKE_THRESHOLD ? ExecutionType::SYNC : ExecutionType::ASYNC, false/*hideConsole*/); //throw FileError } @@ -1813,7 +1830,7 @@ void MainDialog::OnResizeLeftFolderWidth(wxEvent& event) //adapt left-shift display distortion caused by scrollbars for multiple folder pairs const int width = m_panelTopLeft->GetSize().GetWidth(); for (FolderPairPanel* panel : additionalFolderPairs_) - panel->m_panelLeft->SetMinSize(wxSize(width, -1)); + panel->m_panelLeft->SetMinSize({width, -1}); event.Skip(); } @@ -2665,7 +2682,7 @@ void MainDialog::resetLayout() { m_splitterMain->setSashOffset(0); - auiMgr_.LoadPerspective(defaultPerspective_); + auiMgr_.LoadPerspective(defaultPerspective_, false /*don't call wxAuiManager::Update() => already done in updateGuiForFolderPair() */); updateGuiForFolderPair(); } @@ -2725,8 +2742,8 @@ void MainDialog::OnCompSettingsContext(wxEvent& event) menu.addItem(getVariantName(cmpVar), [&setVariant, cmpVar] { setVariant(cmpVar); }, activeCmpVar == cmpVar ? &iconNormal : &iconGrey); }; addVariantItem(CompareVariant::timeSize, L"cmp_file_time_sicon"); - addVariantItem(CompareVariant::content, L"cmp_file_content_sicon"); - addVariantItem(CompareVariant::size, L"cmp_file_size_sicon"); + addVariantItem(CompareVariant::content, L"cmp_file_content_sicon"); + addVariantItem(CompareVariant::size, L"cmp_file_size_sicon"); //menu.addRadio(getVariantName(CompareVariant::timeSize), [&] { setVariant(CompareVariant::timeSize); }, activeCmpVar == CompareVariant::timeSize); //menu.addRadio(getVariantName(CompareVariant::content ), [&] { setVariant(CompareVariant::content); }, activeCmpVar == CompareVariant::content); @@ -4614,8 +4631,8 @@ void MainDialog::updateGridViewData() wxImage imgIconReleased = imgCategory.ConvertToGreyscale(1.0/3, 1.0/3, 1.0/3); //treat all channels equally! brighten(imgIconReleased, 80); - wxImage imgButtonPressed = stackImages(imgCategory, imgCountPressed, ImageStackLayout::HORIZONTAL, ImageStackAlignment::BOTTOM); - wxImage imgButtonReleased = stackImages(imgIconReleased, imgCountReleased, ImageStackLayout::HORIZONTAL, ImageStackAlignment::BOTTOM); + wxImage imgButtonPressed = stackImages(imgCategory, imgCountPressed, ImageStackLayout::horizontal, ImageStackAlignment::bottom); + wxImage imgButtonReleased = stackImages(imgIconReleased, imgCountReleased, ImageStackLayout::horizontal, ImageStackAlignment::bottom); wxBitmap bmpBorderRect(imgButtonPressed.GetWidth(), imgButtonPressed.GetHeight()); //seems we don't need to pass 24-bit depth here even for high-contrast color schemes { @@ -5214,7 +5231,7 @@ void MainDialog::insertAddFolderPair(const std::vector& newPair //set width of left folder panel const int width = m_panelTopLeft->GetSize().GetWidth(); - newPair->m_panelLeft->SetMinSize(wxSize(width, -1)); + newPair->m_panelLeft->SetMinSize({width, -1}); //register events newPair->m_bpButtonFolderPairOptions->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxEventHandler(MainDialog::OnShowFolderPairOptions), nullptr, this); diff --git a/FreeFileSync/Source/ui/progress_indicator.cpp b/FreeFileSync/Source/ui/progress_indicator.cpp index 7a3e48a9..7f2ac3df 100644 --- a/FreeFileSync/Source/ui/progress_indicator.cpp +++ b/FreeFileSync/Source/ui/progress_indicator.cpp @@ -181,8 +181,11 @@ CompareProgressPanel::Impl::Impl(wxFrame& parentWindow) : CompareProgressDlgGenerated(&parentWindow), parentWindow_(parentWindow) { + const wxBitmap& bmpTime = getResourceImage(L"cmp_file_time_sicon"); m_bitmapItemStat->SetBitmap(IconBuffer::genericFileIcon(IconBuffer::SIZE_SMALL)); - m_bitmapTimeStat->SetBitmap(getResourceImage(L"cmp_file_time_sicon")); + m_bitmapTimeStat->SetBitmap(bmpTime); + m_bitmapItemStat->SetMinSize({-1, std::max(IconBuffer::getSize(IconBuffer::SIZE_SMALL), bmpTime.GetHeight())}); + m_bitmapTimeStat->SetMinSize({-1, std::max(IconBuffer::getSize(IconBuffer::SIZE_SMALL), bmpTime.GetHeight())}); m_bitmapIgnoreErrors->SetBitmap(getResourceImage(L"error_ignore_active")); m_bitmapRetryErrors ->SetBitmap(getResourceImage(L"error_retry")); @@ -767,7 +770,7 @@ SyncProgressDialogImpl::SyncProgressDialogImpl(long style, //wxF assert((std::is_same_v == !parentFrame)); //finish construction of this dialog: - this->pnl_.m_panelProgress->SetMinSize(wxSize(fastFromDIP(550), fastFromDIP(340))); + this->pnl_.m_panelProgress->SetMinSize({fastFromDIP(550), fastFromDIP(340)}); wxBoxSizer* bSizer170 = new wxBoxSizer(wxVERTICAL); bSizer170->Add(&pnl_, 1, wxEXPAND); @@ -815,8 +818,11 @@ SyncProgressDialogImpl::SyncProgressDialogImpl(long style, //wxF pnl_.m_bpButtonMinimizeToTray->SetBitmapLabel(getResourceImage(L"minimize_to_tray")); + const wxBitmap& bmpTime = getResourceImage(L"cmp_file_time_sicon"); pnl_.m_bitmapItemStat->SetBitmap(IconBuffer::genericFileIcon(IconBuffer::SIZE_SMALL)); - pnl_.m_bitmapTimeStat->SetBitmap(getResourceImage(L"cmp_file_time_sicon")); + pnl_.m_bitmapTimeStat->SetBitmap(bmpTime); + pnl_.m_bitmapItemStat->SetMinSize({-1, std::max(IconBuffer::getSize(IconBuffer::SIZE_SMALL), bmpTime.GetHeight())}); + pnl_.m_bitmapTimeStat->SetMinSize({-1, std::max(IconBuffer::getSize(IconBuffer::SIZE_SMALL), bmpTime.GetHeight())}); pnl_.m_bitmapIgnoreErrors->SetBitmap(getResourceImage(L"error_ignore_active")); pnl_.m_bitmapRetryErrors ->SetBitmap(getResourceImage(L"error_retry")); diff --git a/FreeFileSync/Source/ui/small_dlgs.cpp b/FreeFileSync/Source/ui/small_dlgs.cpp index 256100fd..867711ae 100644 --- a/FreeFileSync/Source/ui/small_dlgs.cpp +++ b/FreeFileSync/Source/ui/small_dlgs.cpp @@ -60,6 +60,11 @@ private: void OnOK (wxCommandEvent& event) override { EndModal(ReturnSmallDlg::BUTTON_OKAY); } void OnClose (wxCloseEvent& event) override { EndModal(ReturnSmallDlg::BUTTON_CANCEL); } void OnDonate(wxCommandEvent& event) override { wxLaunchDefaultBrowser(L"https://freefilesync.org/donate.php"); } + void OnOpenHomepage(wxCommandEvent& event) override { wxLaunchDefaultBrowser(L"https://freefilesync.org/"); } + void OnOpenForum (wxCommandEvent& event) override { wxLaunchDefaultBrowser(L"https://freefilesync.org/forum/"); } + void OnSendEmail (wxCommandEvent& event) override { wxLaunchDefaultBrowser(L"mailto:zenju@freefilesync.org"); } + void OnShowGpl (wxCommandEvent& event) override { wxLaunchDefaultBrowser(L"https://www.gnu.org/licenses/gpl-3.0"); } + void onLocalKeyEvent(wxKeyEvent& event); }; @@ -70,11 +75,32 @@ AboutDlg::AboutDlg(wxWindow* parent) : AboutDlgGenerated(parent) assert(m_buttonClose->GetId() == wxID_OK); //we cannot use wxID_CLOSE else Esc key won't work: yet another wxWidgets bug?? - m_bitmapHomepage->SetBitmap(getResourceImage(L"website")); - m_bitmapForum ->SetBitmap(getResourceImage(L"forum")); - m_bitmapEmail ->SetBitmap(getResourceImage(L"email")); - m_bitmapGpl ->SetBitmap(getResourceImage(L"gpl")); + m_bitmapLogo ->SetBitmap(getResourceImage(L"logo")); + m_bitmapLogoLeft->SetBitmap(getResourceImage(L"logo-left")); + + + //------------------------------------ + wxString build = utfTo(ffsVersion); +#ifndef wxUSE_UNICODE +#error what is going on? +#endif + + const wchar_t* const SPACED_BULLET = L" \u2022 "; + build += SPACED_BULLET; + + build += LTR_MARK; //fix Arabic +#if ZEN_BUILD_ARCH == ZEN_ARCH_32BIT + build += L"32 Bit"; +#else + build += L"64 Bit"; +#endif + + build += SPACED_BULLET; + build += formatTime(FORMAT_DATE, getCompileTime()); + m_staticTextVersion->SetLabel(replaceCpy(_("Version: %x"), L"%x", build)); + + //------------------------------------ { m_panelThankYou->Hide(); m_bitmapDonate->SetBitmap(getResourceImage(L"ffs_heart")); @@ -82,16 +108,31 @@ AboutDlg::AboutDlg(wxWindow* parent) : AboutDlgGenerated(parent) setRelativeFontSize(*m_buttonDonate, 1.25); } - //m_animCtrlWink->SetAnimation(getResourceAnimation(L"wink")); - //m_animCtrlWink->Play(); + //------------------------------------ + wxImage forumImage = stackImages(getResourceImage(L"forum").ConvertToImage(), + createImageFromText(L"FreeFileSync Forum", *wxNORMAL_FONT, m_bpButtonForum->GetForegroundColour()), + ImageStackLayout::vertical, ImageStackAlignment::center, fastFromDIP(5)); + m_bpButtonForum->SetBitmapLabel(wxBitmap(forumImage)); + + setBitmapTextLabel(*m_bpButtonHomepage, getResourceImage(L"homepage").ConvertToImage(), L"FreeFileSync.org"); + setBitmapTextLabel(*m_bpButtonEmail, getResourceImage(L"email" ).ConvertToImage(), L"zenju@freefilesync.org"); - m_staticTextThanksForLoc->SetMinSize(wxSize(fastFromDIP(200), -1)); + //------------------------------------ + m_bpButtonGpl->SetBitmapLabel(getResourceImage(L"gpl")); + + //have the GPL text wrap to two lines: + wxMemoryDC dc; + dc.SetFont(m_staticTextGpl->GetFont()); + const wxSize gplExt = dc.GetTextExtent(m_staticTextGpl->GetLabelText()); + m_staticTextGpl->Wrap(gplExt.GetWidth() * 6 / 10); + + //------------------------------------ + m_staticTextThanksForLoc->SetMinSize({fastFromDIP(200), -1}); m_staticTextThanksForLoc->Wrap(fastFromDIP(200)); - //create language credits for (const TranslationInfo& ti : getExistingTranslations()) { - //flag + //country flag wxStaticBitmap* staticBitmapFlag = new wxStaticBitmap(m_scrolledWindowTranslators, wxID_ANY, getResourceImage(ti.languageFlag)); fgSizerTranslators->Add(staticBitmapFlag, 0, wxALIGN_CENTER); @@ -104,54 +145,7 @@ AboutDlg::AboutDlg(wxWindow* parent) : AboutDlgGenerated(parent) } fgSizerTranslators->Fit(m_scrolledWindowTranslators); - - std::wstring build = formatTime(FORMAT_DATE, getCompileTime()) + SPACED_DASH + L"Unicode"; -#ifndef wxUSE_UNICODE -#error what is going on? -#endif - - build += -#if ZEN_BUILD_ARCH == ZEN_ARCH_32BIT - L" x86"; -#else - L" x64"; -#endif - - - GetSizer()->SetSizeHints(this); //~=Fit() + SetMinSize() - - //generate logo: put *after* first Fit() - Layout(); //make sure m_panelLogo has final width (required by wxGTK) - - wxImage appnameImg = createImageFromText(wxString(L"FreeFileSync ") + ffsVersion, - wxFont(wxNORMAL_FONT->GetPointSize() * 1.8, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, L"Tahoma"), - *wxBLACK); //accessibility: align foreground/background colors! - wxImage buildImg = createImageFromText(replaceCpy(_("Build: %x"), L"%x", build), - *wxNORMAL_FONT, - *wxBLACK, - ImageStackAlignment::CENTER); - wxImage versionImage = stackImages(appnameImg, buildImg, ImageStackLayout::VERTICAL, ImageStackAlignment::CENTER, 0); - - const int borderSize = fastFromDIP(5); - wxBitmap headerBmp(bSizerMainSection->GetSize().x, versionImage.GetHeight() + 2 * borderSize, 24); - //attention: *must* pass 24 bits, auto-determination fails on Windows high-contrast colors schemes!!! - //problem only shows when calling wxDC::DrawBitmap - { - wxMemoryDC dc(headerBmp); - dc.SetBackground(*wxWHITE_BRUSH); - dc.Clear(); - - const wxBitmap& bmpGradient = getResourceImage(L"logo_gradient"); - dc.DrawBitmap(bmpGradient, wxPoint(0, (headerBmp.GetHeight() - bmpGradient.GetHeight()) / 2)); - - const int logoSize = versionImage.GetHeight(); - const wxBitmap logoBmp = getResourceImage(L"FreeFileSync").ConvertToImage().Scale(logoSize, logoSize, wxIMAGE_QUALITY_HIGH); //looks smooth unlike wxIMAGE_QUALITY_BILINEAR! - dc.DrawBitmap(logoBmp, wxPoint(2 * borderSize, (headerBmp.GetHeight() - logoBmp.GetHeight()) / 2)); - - dc.DrawBitmap(versionImage, wxPoint((headerBmp.GetWidth () - versionImage.GetWidth ()) / 2, - (headerBmp.GetHeight() - versionImage.GetHeight()) / 2)); - } - m_bitmapLogo->SetBitmap(headerBmp); + //------------------------------------ //enable dialog-specific key events Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(AboutDlg::onLocalKeyEvent), nullptr, this); @@ -263,12 +257,12 @@ CloudSetupDlg::CloudSetupDlg(wxWindow* parent, Zstring& folderPathPhrase, size_t m_checkBoxShowPassword->SetValue(false); m_textCtrlServer->SetHint(_("Example:") + L" website.com 66.198.240.22"); - m_textCtrlServer->SetMinSize(wxSize(fastFromDIP(260), -1)); + m_textCtrlServer->SetMinSize({fastFromDIP(260), -1}); - m_textCtrlPort ->SetMinSize(wxSize(fastFromDIP(60), -1)); // - m_spinCtrlConnectionCount ->SetMinSize(wxSize(fastFromDIP(70), -1)); //Hack: set size (why does wxWindow::Size() not work?) - m_spinCtrlChannelCountSftp->SetMinSize(wxSize(fastFromDIP(70), -1)); // - m_spinCtrlTimeout ->SetMinSize(wxSize(fastFromDIP(70), -1)); // + m_textCtrlPort ->SetMinSize({fastFromDIP(60), -1}); // + m_spinCtrlConnectionCount ->SetMinSize({fastFromDIP(70), -1}); //Hack: set size (why does wxWindow::Size() not work?) + m_spinCtrlChannelCountSftp->SetMinSize({fastFromDIP(70), -1}); // + m_spinCtrlTimeout ->SetMinSize({fastFromDIP(70), -1}); // setupFileDrop(*m_panelAuth); m_panelAuth->Connect(EVENT_DROP_FILE, FileDropEventHandler(CloudSetupDlg::onKeyFileDropped), nullptr, this); @@ -395,6 +389,7 @@ void CloudSetupDlg::OnGdriveUserAdd(wxCommandEvent& event) else { const wxString googleUser = utfTo(std::get(result)); + int selIdx = m_listBoxGdriveUsers->FindString(googleUser, false /*caseSensitive*/); if (selIdx == wxNOT_FOUND) selIdx = m_listBoxGdriveUsers->Append(googleUser); @@ -735,7 +730,7 @@ CopyToDialog::CopyToDialog(wxWindow* parent, m_targetFolderPath->init(folderHistory_); - m_textCtrlFileList->SetMinSize(wxSize(fastFromDIP(500), fastFromDIP(200))); + m_textCtrlFileList->SetMinSize({fastFromDIP(500), fastFromDIP(200)}); /* There is a nasty bug on wxGTK under Ubuntu: If a multi-line wxTextCtrl contains so many lines that scrollbars are shown, @@ -862,7 +857,7 @@ DeleteDialog::DeleteDialog(wxWindow* parent, setMainInstructionFont(*m_staticTextHeader); - m_textCtrlFileList->SetMinSize(wxSize(fastFromDIP(500), fastFromDIP(200))); + m_textCtrlFileList->SetMinSize({fastFromDIP(500), fastFromDIP(200)}); m_checkBoxUseRecycler->SetValue(useRecycleBin); @@ -1113,7 +1108,7 @@ OptionsDlg::OptionsDlg(wxWindow* parent, XmlGlobalSettings& globalSettings) : //setMainInstructionFont(*m_staticTextHeader); m_gridCustomCommand->SetTabBehaviour(wxGrid::Tab_Leave); - m_spinCtrlLogFilesMaxAge->SetMinSize(wxSize(fastFromDIP(70), -1)); //Hack: set size (why does wxWindow::Size() not work?) + m_spinCtrlLogFilesMaxAge->SetMinSize({fastFromDIP(70), -1}); //Hack: set size (why does wxWindow::Size() not work?) m_hyperlinkLogFolder->SetLabel(utfTo(getDefaultLogFolderPath())); setRelativeFontSize(*m_hyperlinkLogFolder, 1.2); @@ -1146,16 +1141,6 @@ OptionsDlg::OptionsDlg(wxWindow* parent, XmlGlobalSettings& globalSettings) : updateGui(); bSizerLockedFiles->Show(false); - - const wxString toolTip = wxString(_("Integrate external applications into context menu. The following macros are available:")) + L"\n\n" + - L"%item_path% \t" + _("Full file or folder path") + L"\n" + - L"%folder_path% \t" + _("Parent folder path") + L"\n" + - L"%local_path% \t" + _("Temporary local copy for SFTP and MTP storage") + L"\n" + - L"\n" + - L"%item_path2%, %folder_path2%, %local_path2% \t" + _("Parameters for opposite side"); - - m_gridCustomCommand->GetGridWindow() ->SetToolTip(toolTip); - m_gridCustomCommand->GetGridColLabelWindow()->SetToolTip(toolTip); m_gridCustomCommand->SetMargins(0, 0); //temporarily set dummy value for window height calculations: @@ -1499,7 +1484,7 @@ CfgHighlightDlg::CfgHighlightDlg(wxWindow* parent, int& cfgHistSyncOverdueDays) m_staticTextHighlight->Wrap(fastFromDIP(300)); - m_spinCtrlOverdueDays->SetMinSize(wxSize(fastFromDIP(70), -1)); //Hack: set size (why does wxWindow::Size() not work?) + m_spinCtrlOverdueDays->SetMinSize({fastFromDIP(70), -1}); //Hack: set size (why does wxWindow::Size() not work?) setStandardButtonLayout(*bSizerStdButtons, StdButtons().setAffirmative(m_buttonOkay).setCancel(m_buttonCancel)); @@ -1560,7 +1545,7 @@ ActivationDlg::ActivationDlg(wxWindow* parent, //setMainInstructionFont(*m_staticTextMain); - m_bitmapActivation->SetBitmap(getResourceImage(L"website")); + m_bitmapActivation->SetBitmap(getResourceImage(L"internet")); m_textCtrlOfflineActivationKey->ForceUpper(); m_textCtrlLastError ->ChangeValue(lastErrorMsg); @@ -1662,9 +1647,9 @@ DownloadProgressWindow::Impl::Impl(wxWindow* parent, int64_t fileSizeTotal) : setMainInstructionFont(*m_staticTextHeader); m_staticTextHeader->Wrap(fastFromDIP(460)); //*after* font change! - m_staticTextDetails->SetMinSize(wxSize(fastFromDIP(550), -1)); + m_staticTextDetails->SetMinSize({fastFromDIP(550), -1}); - m_bitmapDownloading->SetBitmap(getResourceImage(L"website")); + m_bitmapDownloading->SetBitmap(getResourceImage(L"internet")); m_gaugeProgress->SetRange(GAUGE_FULL_RANGE); diff --git a/FreeFileSync/Source/ui/sync_cfg.cpp b/FreeFileSync/Source/ui/sync_cfg.cpp index 1711f382..a4ce9809 100644 --- a/FreeFileSync/Source/ui/sync_cfg.cpp +++ b/FreeFileSync/Source/ui/sync_cfg.cpp @@ -304,14 +304,14 @@ commandHistItemsMax_(commandHistItemsMax) m_toggleBtnByContent ->SetToolTip(getCompVariantDescription(CompareVariant::content)); m_toggleBtnBySize ->SetToolTip(getCompVariantDescription(CompareVariant::size)); - m_staticTextCompVarDescription->SetMinSize(wxSize(fastFromDIP(CFG_DESCRIPTION_WIDTH_DIP), -1)); + m_staticTextCompVarDescription->SetMinSize({fastFromDIP(CFG_DESCRIPTION_WIDTH_DIP), -1}); - m_scrolledWindowPerf->SetMinSize(wxSize(fastFromDIP(220), -1)); + m_scrolledWindowPerf->SetMinSize({fastFromDIP(220), -1}); m_bitmapPerf->SetBitmap(perfPanelActive_ ? getResourceImage(L"speed") : greyScale(getResourceImage(L"speed"))); m_panelPerfHeader ->Enable(perfPanelActive_); - m_spinCtrlAutoRetryCount->SetMinSize(wxSize(fastFromDIP(60), -1)); //Hack: set size (why does wxWindow::Size() not work?) - m_spinCtrlAutoRetryDelay->SetMinSize(wxSize(fastFromDIP(60), -1)); // + m_spinCtrlAutoRetryCount->SetMinSize({fastFromDIP(60), -1}); //Hack: set size (why does wxWindow::Size() not work?) + m_spinCtrlAutoRetryDelay->SetMinSize({fastFromDIP(60), -1}); // //ignore invalid input for time shift control: wxTextValidator inputValidator(wxFILTER_DIGITS | wxFILTER_INCLUDE_CHAR_LIST); @@ -319,7 +319,7 @@ commandHistItemsMax_(commandHistItemsMax) m_textCtrlTimeShift->SetValidator(inputValidator); //------------- filter panel -------------------------- - m_textCtrlInclude->SetMinSize(wxSize(fastFromDIP(280), -1)); + m_textCtrlInclude->SetMinSize({fastFromDIP(280), -1}); assert(!contains(m_buttonClear->GetLabel(), L"&C") && !contains(m_buttonClear->GetLabel(), L"&c")); //gazillionth wxWidgets bug on OS X: Command + C mistakenly hits "&C" access key! @@ -365,7 +365,7 @@ commandHistItemsMax_(commandHistItemsMax) setRelativeFontSize(*m_toggleBtnUpdate, 1.25); setRelativeFontSize(*m_toggleBtnCustom, 1.25); - m_staticTextSyncVarDescription->SetMinSize(wxSize(fastFromDIP(CFG_DESCRIPTION_WIDTH_DIP), -1)); + m_staticTextSyncVarDescription->SetMinSize({fastFromDIP(CFG_DESCRIPTION_WIDTH_DIP), -1}); m_toggleBtnRecycler ->SetToolTip(_("Retain deleted and overwritten files in the recycle bin")); m_toggleBtnPermanent ->SetToolTip(_("Delete and overwrite files permanently")); @@ -376,11 +376,11 @@ commandHistItemsMax_(commandHistItemsMax) add(VersioningStyle::timestampFolder, _("Time stamp") + L" [" + _("Folder") + L"]", _("Move files into a time-stamped subfolder")). add(VersioningStyle::timestampFile, _("Time stamp") + L" [" + _("File") + L"]", _("Append a time stamp to each file name")); - m_spinCtrlVersionMaxDays ->SetMinSize(wxSize(fastFromDIP(60), -1)); // - m_spinCtrlVersionCountMin->SetMinSize(wxSize(fastFromDIP(60), -1)); //Hack: set size (why does wxWindow::Size() not work?) - m_spinCtrlVersionCountMax->SetMinSize(wxSize(fastFromDIP(60), -1)); // + m_spinCtrlVersionMaxDays ->SetMinSize({fastFromDIP(60), -1}); // + m_spinCtrlVersionCountMin->SetMinSize({fastFromDIP(60), -1}); //Hack: set size (why does wxWindow::Size() not work?) + m_spinCtrlVersionCountMax->SetMinSize({fastFromDIP(60), -1}); // - m_staticTextPostSync->SetMinSize(wxSize(fastFromDIP(180), -1)); + m_staticTextPostSync->SetMinSize({fastFromDIP(180), -1}); enumPostSyncCondition_. add(PostSyncCondition::COMPLETION, _("On completion:")). @@ -1205,7 +1205,7 @@ void ConfigDialog::setMiscSyncOptions(const MiscSyncConfig& miscCfg) for (int i = 0; i < rowsToCreate; ++i) { wxSpinCtrl* spinCtrlParallelOps = new wxSpinCtrl(m_scrolledWindowPerf, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 2000000000, 1); - spinCtrlParallelOps->SetMinSize(wxSize(fastFromDIP(60), -1)); //Hack: set size (why does wxWindow::Size() not work?) + spinCtrlParallelOps->SetMinSize({fastFromDIP(60), -1}); //Hack: set size (why does wxWindow::Size() not work?) spinCtrlParallelOps->Enable(perfPanelActive_); fgSizerPerf->Add(spinCtrlParallelOps, 0, wxALIGN_CENTER_VERTICAL); diff --git a/FreeFileSync/Source/ui/tree_grid.cpp b/FreeFileSync/Source/ui/tree_grid.cpp index f6ebc8f5..963ebdd0 100644 --- a/FreeFileSync/Source/ui/tree_grid.cpp +++ b/FreeFileSync/Source/ui/tree_grid.cpp @@ -771,7 +771,7 @@ private: return std::wstring(); } - void renderColumnLabel(Grid& tree, wxDC& dc, const wxRect& rect, ColumnType colType, bool highlighted) override + void renderColumnLabel(wxDC& dc, const wxRect& rect, ColumnType colType, bool enabled, bool highlighted) override { const auto colTypeTree = static_cast(colType); @@ -780,7 +780,7 @@ private: rectRemain.x += getColumnGapLeft(); rectRemain.width -= getColumnGapLeft(); - drawColumnLabelText(dc, rectRemain, getColumnLabel(colType)); + drawColumnLabelText(dc, rectRemain, getColumnLabel(colType), enabled); const auto [sortCol, ascending] = treeDataView_.getSortDirection(); if (colTypeTree == sortCol) @@ -790,25 +790,13 @@ private: } } + //void renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected) override => GridData default is fine + enum class HoverAreaTree { NODE, }; - void renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row, bool enabled, bool selected) override - { - if (enabled) - { - if (selected) - dc.GradientFillLinear(rect, getColorSelectionGradientFrom(), getColorSelectionGradientTo(), wxEAST); - //ignore focus - else - clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); - } - else - clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); - } - void renderCell(wxDC& dc, const wxRect& rect, size_t row, ColumnType colType, bool enabled, bool selected, HoverArea rowHover) override { //wxRect rectTmp= drawCellBorder(dc, rect); diff --git a/FreeFileSync/Source/version/version.h b/FreeFileSync/Source/version/version.h index a13ee197..af47b93d 100644 --- a/FreeFileSync/Source/version/version.h +++ b/FreeFileSync/Source/version/version.h @@ -3,7 +3,7 @@ namespace fff { -const char ffsVersion[] = "10.18"; //internal linkage! +const char ffsVersion[] = "10.19"; //internal linkage! const char FFS_VERSION_SEPARATOR = '.'; } diff --git a/wx+/bitmap_button.h b/wx+/bitmap_button.h index bcbc7328..b40d8dd3 100644 --- a/wx+/bitmap_button.h +++ b/wx+/bitmap_button.h @@ -56,13 +56,13 @@ void setBitmapTextLabel(wxBitmapButton& btn, const wxImage& img, const wxString& wxImage dynImage = createImageFromText(text, btn.GetFont(), btn.GetForegroundColour()); if (img.IsOk()) dynImage = btn.GetLayoutDirection() != wxLayout_RightToLeft ? - stackImages(img, dynImage, ImageStackLayout::HORIZONTAL, ImageStackAlignment::CENTER, gap) : - stackImages(dynImage, img, ImageStackLayout::HORIZONTAL, ImageStackAlignment::CENTER, gap); + stackImages(img, dynImage, ImageStackLayout::horizontal, ImageStackAlignment::center, gap) : + stackImages(dynImage, img, ImageStackLayout::horizontal, ImageStackAlignment::center, gap); - //SetMinSize() instead of SetSize() is needed here for wxWindows layout determination to work corretly + //SetMinSize() instead of SetSize() is needed here for wxWindows layout determination to work correctly const int defaultHeight = wxButton::GetDefaultSize().GetHeight(); - btn.SetMinSize(wxSize(dynImage.GetWidth () + 2 * border, - std::max(dynImage.GetHeight() + 2 * border, defaultHeight))); + btn.SetMinSize({dynImage.GetWidth () + 2 * border, + std::max(dynImage.GetHeight() + 2 * border, defaultHeight)}); btn.SetBitmapLabel(wxBitmap(dynImage)); //SetLabel() calls confuse wxBitmapButton in the disabled state and it won't show the image! workaround: @@ -73,7 +73,7 @@ void setBitmapTextLabel(wxBitmapButton& btn, const wxImage& img, const wxString& inline void setImage(wxBitmapButton& button, const wxBitmap& bmp) { - if (!isEqual(button.GetBitmapLabel(), bmp)) + if (!button.GetBitmapLabel().IsSameAs(bmp)) { button.SetBitmapLabel(bmp); diff --git a/wx+/file_drop.h b/wx+/file_drop.h index ee5393b7..9826bf27 100644 --- a/wx+/file_drop.h +++ b/wx+/file_drop.h @@ -60,8 +60,6 @@ using FileDropEventFunction = void (wxEvtHandler::*)(FileDropEvent&); void setupFileDrop(wxWindow& wnd); - - } #endif //FILE_DROP_H_09457802957842560325626 diff --git a/wx+/graph.cpp b/wx+/graph.cpp index a6d0f19d..ec338e99 100644 --- a/wx+/graph.cpp +++ b/wx+/graph.cpp @@ -226,11 +226,11 @@ void drawCornerText(wxDC& dc, const wxRect& graphArea, const wxString& txt, Grap break; } - //add text shadow to improve readability: - wxDCTextColourChanger textColor(dc, colorBack); - dc.DrawText(txt, drawPos + border + wxSize(fastFromDIP(1), fastFromDIP(1))); + //add text shadow to improve readability: + wxDCTextColourChanger textColor(dc, colorBack); + dc.DrawText(txt, drawPos + border + wxSize(fastFromDIP(1), fastFromDIP(1))); - textColor.Set(colorText); + textColor.Set(colorText); dc.DrawText(txt, drawPos + border); } diff --git a/wx+/grid.cpp b/wx+/grid.cpp index 0613e14f..fe168df6 100644 --- a/wx+/grid.cpp +++ b/wx+/grid.cpp @@ -35,7 +35,7 @@ int GridData::getColumnGapLeft() { return fastFromDIP(4); } namespace { //------------------------------ Grid Parameters -------------------------------- -inline wxColor getColorLabelText() { return wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); } +inline wxColor getColorLabelText(bool enabled) { return wxSystemSettings::GetColour(enabled ? wxSYS_COLOUR_WINDOWTEXT : wxSYS_COLOUR_GRAYTEXT); } inline wxColor getColorGridLine() { return { 192, 192, 192 }; } //light grey inline wxColor getColorLabelGradientFrom() { return wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); } @@ -213,13 +213,13 @@ wxSize GridData::drawCellText(wxDC& dc, const wxRect& rect, const std::wstring& } -void GridData::renderColumnLabel(Grid& grid, wxDC& dc, const wxRect& rect, ColumnType colType, bool highlighted) +void GridData::renderColumnLabel(wxDC& dc, const wxRect& rect, ColumnType colType, bool enabled, bool highlighted) { wxRect rectRemain = drawColumnLabelBackground(dc, rect, highlighted); rectRemain.x += getColumnGapLeft(); rectRemain.width -= getColumnGapLeft(); - drawColumnLabelText(dc, rectRemain, getColumnLabel(colType)); + drawColumnLabelText(dc, rectRemain, getColumnLabel(colType), enabled); } @@ -247,9 +247,9 @@ wxRect GridData::drawColumnLabelBackground(wxDC& dc, const wxRect& rect, bool hi } -void GridData::drawColumnLabelText(wxDC& dc, const wxRect& rect, const std::wstring& text) +void GridData::drawColumnLabelText(wxDC& dc, const wxRect& rect, const std::wstring& text, bool enabled) { - wxDCTextColourChanger textColor(dc, getColorLabelText()); //accessibility: always set both foreground AND background colors! + wxDCTextColourChanger textColor(dc, getColorLabelText(enabled)); //accessibility: always set both foreground AND background colors! drawCellText(dc, rect, text, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); } @@ -500,7 +500,8 @@ private: void render(wxDC& dc, const wxRect& rect) override { - clearArea(dc, rect, wxSystemSettings::GetColour(/*!renderAsEnabled(*this) ? wxSYS_COLOUR_BTNFACE :*/wxSYS_COLOUR_WINDOW)); + const bool enabled = renderAsEnabled(*this); + clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); dc.SetFont(GetFont()); //harmonize with RowLabelWin::getBestWidth()! @@ -511,16 +512,16 @@ private: if (singleLabelArea.height > 0) { singleLabelArea.y = refParent().CalcScrolledPosition(singleLabelArea.GetTopLeft()).y; - drawRowLabel(dc, singleLabelArea, row); + drawRowLabel(dc, singleLabelArea, row, enabled); } } } - void drawRowLabel(wxDC& dc, const wxRect& rect, size_t row) + void drawRowLabel(wxDC& dc, const wxRect& rect, size_t row, bool enabled) { //clearArea(dc, rect, getColorRowLabel()); dc.GradientFillLinear(rect, getColorLabelGradientFrom(), getColorLabelGradientTo(), wxEAST); //clear overlapping cells - wxDCTextColourChanger textColor(dc, getColorLabelText()); //accessibility: always set both foreground AND background colors! + wxDCTextColourChanger textColor(dc, getColorLabelText(enabled)); //accessibility: always set both foreground AND background colors! //label text wxRect textRect = rect; @@ -615,7 +616,8 @@ private: void render(wxDC& dc, const wxRect& rect) override { - clearArea(dc, rect, wxSystemSettings::GetColour(/*!renderAsEnabled(*this) ? wxSYS_COLOUR_BTNFACE :*/wxSYS_COLOUR_WINDOW)); + const bool enabled = renderAsEnabled(*this); + clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); //coordinate with "colLabelHeight" in Grid constructor: wxFont labelFont = GetFont(); @@ -637,7 +639,7 @@ private: if (labelAreaTL.x > rect.GetRight()) return; //done, rect is fully covered if (labelAreaTL.x + width > rect.x) - drawColumnLabel(dc, wxRect(labelAreaTL, wxSize(width, colLabelHeight)), col, it->type); + drawColumnLabel(dc, wxRect(labelAreaTL, wxSize(width, colLabelHeight)), col, it->type, enabled); labelAreaTL.x += width; } if (labelAreaTL.x > rect.GetRight()) @@ -652,11 +654,11 @@ private: const int clientWidth = GetClientSize().GetWidth(); //need reliable, stable width in contrast to rect.width if (totalWidth < clientWidth) - drawColumnLabel(dc, wxRect(labelAreaTL, wxSize(clientWidth - totalWidth, colLabelHeight)), absWidths.size(), ColumnType::NONE); + drawColumnLabel(dc, wxRect(labelAreaTL, wxSize(clientWidth - totalWidth, colLabelHeight)), absWidths.size(), ColumnType::NONE, enabled); } } - void drawColumnLabel(wxDC& dc, const wxRect& rect, size_t col, ColumnType colType) + void drawColumnLabel(wxDC& dc, const wxRect& rect, size_t col, ColumnType colType, bool enabled) { if (auto dataView = refParent().getDataProvider()) { @@ -666,7 +668,7 @@ private: false; RecursiveDcClipper clip(dc, rect); - dataView->renderColumnLabel(refParent(), dc, rect, colType, isHighlighted); + dataView->renderColumnLabel(dc, rect, colType, enabled, isHighlighted); //draw move target location if (refParent().allowColumnMove_) @@ -885,7 +887,8 @@ public: private: void render(wxDC& dc, const wxRect& rect) override { - clearArea(dc, rect, wxSystemSettings::GetColour(/*!renderAsEnabled(*this) ? wxSYS_COLOUR_BTNFACE :*/wxSYS_COLOUR_WINDOW)); + const bool enabled = renderAsEnabled(*this); + clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); dc.SetFont(GetFont()); //harmonize with Grid::getBestColumnSize() @@ -914,7 +917,7 @@ private: { const wxRect rowRect(cellAreaTL + wxPoint(0, row * rowHeight), wxSize(totalRowWidth, rowHeight)); RecursiveDcClipper dummy3(dc, rowRect); - prov->renderRowBackgound(dc, rowRect, row, renderAsEnabled(*this), drawAsSelected(row)); + prov->renderRowBackgound(dc, rowRect, row, enabled, drawAsSelected(row)); } //draw single cells, column by column @@ -928,7 +931,7 @@ private: { const wxRect cellRect(cellAreaTL.x, cellAreaTL.y + row * rowHeight, cw.width, rowHeight); RecursiveDcClipper dummy3(dc, cellRect); - prov->renderCell(dc, cellRect, row, cw.type, renderAsEnabled(*this), drawAsSelected(row), getRowHoverToDraw(row)); + prov->renderCell(dc, cellRect, row, cw.type, enabled, drawAsSelected(row), getRowHoverToDraw(row)); } cellAreaTL.x += cw.width; } @@ -1488,10 +1491,10 @@ wxSize Grid::GetSizeAvailableForScrollTarget(const wxSize& size) //2. try(!) to determine scrollbar sizes: #if GTK_MAJOR_VERSION == 2 - /* Ubuntu 19.10: "scrollbar-spacing" has a default value of 3: https://developer.gnome.org/gtk2/stable/GtkScrolledWindow.html#GtkScrolledWindow--s-scrollbar-spacing - => the default Ubuntu theme (but also our Gtk2Styles.rc) set it to 0, but still the first call to gtk_widget_style_get() returns 3: why? - => maybe styles are applied asynchronously? GetClientSize() is affected by this, so can't use! - => always ignore spacing to get consistent scrollbar dimensions! */ + /* Ubuntu 19.10: "scrollbar-spacing" has a default value of 3: https://developer.gnome.org/gtk2/stable/GtkScrolledWindow.html#GtkScrolledWindow--s-scrollbar-spacing + => the default Ubuntu theme (but also our Gtk2Styles.rc) set it to 0, but still the first call to gtk_widget_style_get() returns 3: why? + => maybe styles are applied asynchronously? GetClientSize() is affected by this, so can't use! + => always ignore spacing to get consistent scrollbar dimensions! */ GtkScrolledWindow* scrollWin = GTK_SCROLLED_WINDOW(wxWindow::m_widget); assert(scrollWin); GtkWidget* rangeH = ::gtk_scrolled_window_get_hscrollbar(scrollWin); @@ -1509,9 +1512,9 @@ wxSize Grid::GetSizeAvailableForScrollTarget(const wxSize& size) assert(scrollBarWidthV_ == 0 || scrollBarWidthV_ == scrollBarSizeTmp.x); #elif GTK_MAJOR_VERSION == 3 - //scrollbar size increases dynamically on mouse-hover! - //see "overlay scrolling": https://developer.gnome.org/gtk3/stable/GtkScrolledWindow.html#gtk-scrolled-window-set-overlay-scrolling - //luckily "scrollbar-spacing" is stable on GTK3 + //scrollbar size increases dynamically on mouse-hover! + //see "overlay scrolling": https://developer.gnome.org/gtk3/stable/GtkScrolledWindow.html#gtk-scrolled-window-set-overlay-scrolling + //luckily "scrollbar-spacing" is stable on GTK3 const wxSize scrollBarSizeTmp = GetSize() - GetClientSize(); assert(scrollBarSizeTmp.x == 0 || scrollBarSizeTmp.x == 6 || scrollBarSizeTmp.x == 13); //lame hard-coded numbers (from Ubuntu 19.10) @@ -1522,7 +1525,7 @@ wxSize Grid::GetSizeAvailableForScrollTarget(const wxSize& size) scrollBarHeightH_ = std::max(scrollBarHeightH_, scrollBarSizeTmp.y); scrollBarWidthV_ = std::max(scrollBarWidthV_, scrollBarSizeTmp.x); //this function is called again by wxScrollHelper::AdjustScrollbars() if SB_SHOW_ALWAYS-scrollbars are not yet shown => scrollbar size > 0 eventually! - + //----------------------------------------------------------------------------- //harmonize with Grid::updateWindowSizes()! wxSize sizeAvail = size - wxSize(rowLabelWidth, colLabelHeight_); @@ -1904,7 +1907,7 @@ void Grid::showScrollBars(Grid::ScrollBarStatus horizontal, Grid::ScrollBarStatu assert(false); return GTK_POLICY_AUTOMATIC; }; - + GtkScrolledWindow* scrollWin = GTK_SCROLLED_WINDOW(wxWindow::m_widget); assert(scrollWin); ::gtk_scrolled_window_set_policy(scrollWin, diff --git a/wx+/grid.h b/wx+/grid.h index 74dc25b2..662c4fc1 100644 --- a/wx+/grid.h +++ b/wx+/grid.h @@ -115,7 +115,7 @@ public: //label area: virtual std::wstring getColumnLabel(ColumnType colType) const = 0; - virtual void renderColumnLabel(Grid& grid, wxDC& dc, const wxRect& rect, ColumnType colType, bool highlighted); //default implementation + virtual void renderColumnLabel(wxDC& dc, const wxRect& rect, ColumnType colType, bool enabled, bool highlighted); //default implementation virtual std::wstring getToolTip(ColumnType colType) const { return std::wstring(); } static int getColumnGapLeft(); //for left-aligned text @@ -128,7 +128,7 @@ public: static void drawCellBackground(wxDC& dc, const wxRect& rect, bool enabled, bool selected, const wxColor& backgroundColor); static wxRect drawColumnLabelBackground(wxDC& dc, const wxRect& rect, bool highlighted); //returns inner rectangle - static void drawColumnLabelText (wxDC& dc, const wxRect& rect, const std::wstring& text); + static void drawColumnLabelText (wxDC& dc, const wxRect& rect, const std::wstring& text, bool enabled); }; diff --git a/wx+/image_resources.cpp b/wx+/image_resources.cpp index 91189ba6..2a3b7039 100644 --- a/wx+/image_resources.cpp +++ b/wx+/image_resources.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -182,63 +183,81 @@ private: }; -void GlobalBitmaps::init(const Zstring& filePath) +void GlobalBitmaps::init(const Zstring& zipPath) { assert(bitmaps_.empty() && anims_.empty()); - //wxFFileInputStream/wxZipInputStream loads in junks of 512 bytes => WTF!!! => implement sane file loading: - try + std::vector> streams; + + try //to load from ZIP first: + { + //wxFFileInputStream/wxZipInputStream loads in junks of 512 bytes => WTF!!! => implement sane file loading: + const std::string rawStream = loadBinContainer(zipPath, nullptr /*notifyUnbufferedIO*/); //throw FileError + wxMemoryInputStream memStream(rawStream.c_str(), rawStream.size()); //does not take ownership + wxZipInputStream zipStream(memStream, wxConvUTF8); + //do NOT rely on wxConvLocal! On failure shows unhelpful popup "Cannot convert from the charset 'Unknown encoding (-1)'!" + + while (const auto& entry = std::unique_ptr(zipStream.GetNextEntry())) //take ownership! + if (std::string stream(entry->GetSize(), '\0'); !stream.empty() && zipStream.ReadAll(&stream[0], stream.size())) + streams.emplace_back(utfTo(entry->GetName()), std::move(stream)); + else + assert(false); + } + catch (FileError&) //fall back to folder + { + traverseFolder(beforeLast(zipPath, Zstr(".zip"), IF_MISSING_RETURN_NONE), [&](const FileInfo& fi) + { + if (endsWith(fi.fullPath, Zstr(".png"))) + try + { + std::string stream = loadBinContainer(fi.fullPath, nullptr /*notifyUnbufferedIO*/); //throw FileError + streams.emplace_back(fi.itemName, std::move(stream)); + } + catch (FileError&) { assert(false); } + }, nullptr, nullptr, [](const std::wstring& errorMsg) { assert(false); }); //errors are not really critical in this context + } + //-------------------------------------------------------------------- + + //activate support for .png files + wxImage::AddHandler(new wxPNGHandler); //ownership passed + + //do we need xBRZ scaling for high quality DPI images? + const int hqScale = std::clamp(std::ceil(fastFromDIP(1000) / 1000.0), 1, xbrz::SCALE_FACTOR_MAX); + //even for 125% DPI scaling, "2xBRZ + bilinear downscale" gives a better result than mere "125% bilinear upscale"! + if (hqScale > 1) + dpiScaler_ = std::make_unique(hqScale); + + for (const auto& [fileName, stream] : streams) { - const std::string rawStream = loadBinContainer(filePath, nullptr /*notifyUnbufferedIO*/); //throw FileError - wxMemoryInputStream memStream(rawStream.c_str(), rawStream.size()); //does not take ownership - wxZipInputStream zipStream(memStream, wxConvUTF8); - //do NOT rely on wxConvLocal! On failure shows unhelpful popup "Cannot convert from the charset 'Unknown encoding (-1)'!" - - //activate support for .png files - wxImage::AddHandler(new wxPNGHandler); //ownership passed - - //do we need xBRZ scaling for high quality DPI images? - const int hqScale = std::clamp(std::ceil(fastFromDIP(1000) / 1000.0), 1, xbrz::SCALE_FACTOR_MAX); - //even for 125% DPI scaling, "2xBRZ + bilinear downscale" gives a better result than mere "125% bilinear upscale"! - if (hqScale > 1) - dpiScaler_ = std::make_unique(hqScale); - - while (const auto& entry = std::unique_ptr(zipStream.GetNextEntry())) //take ownership!) - { - const wxString name = entry->GetName(); - - if (endsWith(name, L".png")) - { - wxImage img(zipStream, wxBITMAP_TYPE_PNG); - assert(img.IsOk()); - - //end this alpha/no-alpha/mask/wxDC::DrawBitmap/RTL/high-contrast-scheme interoperability nightmare here and now!!!! - //=> there's only one type of wxImage: with alpha channel, no mask!!! - convertToVanillaImage(img); - - if (dpiScaler_) - dpiScaler_->add(name, img); //scale in parallel! - else - bitmaps_.emplace(name, img); - } - else if (endsWith(name, L".gif")) - { - //work around wxWidgets bug: wxAnimation::Load() requires seekable input stream (zip-input stream is not seekable) - std::string stream(entry->GetSize(), '\0'); - if (!stream.empty() && zipStream.ReadAll(&stream[0], stream.size())) - { - wxMemoryInputStream seekAbleStream(stream.c_str(), stream.size()); //stream does not take ownership of data - [[maybe_unused]] const bool loadSuccess = anims_[name].Load(seekAbleStream, wxANIMATION_TYPE_GIF); - assert(loadSuccess); - } - else - assert(false); - } - else - assert(false); - } + const wxString& name = utfTo(afterLast(fileName, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL)); + + wxMemoryInputStream wxstream(stream.c_str(), stream.size()); //stream does not take ownership of data + //bonus: work around wxWidgets bug: wxAnimation::Load() requires seekable input stream (zip-input stream is not seekable) + + if (endsWith(name, L".png")) + { + wxImage img(wxstream, wxBITMAP_TYPE_PNG); + assert(img.IsOk()); + + //end this alpha/no-alpha/mask/wxDC::DrawBitmap/RTL/high-contrast-scheme interoperability nightmare here and now!!!! + //=> there's only one type of wxImage: with alpha channel, no mask!!! + convertToVanillaImage(img); + + if (dpiScaler_) + dpiScaler_->add(name, img); //scale in parallel! + else + bitmaps_.emplace(name, img); + } +#if 0 + else if (endsWith(name, L".gif")) + { + [[maybe_unused]] const bool loadSuccess = anims_[name].Load(wxstream, wxANIMATION_TYPE_GIF); + assert(loadSuccess); + } +#endif + else + assert(false); } - catch (FileError&) { assert(false); } } @@ -272,10 +291,10 @@ const wxAnimation& GlobalBitmaps::getAnimation(const wxString& name) const } -void zen::initResourceImages(const Zstring& filepath) +void zen::initResourceImages(const Zstring& zipPath) { if (std::shared_ptr inst = GlobalBitmaps::instance()) - inst->init(filepath); + inst->init(zipPath); else assert(false); } diff --git a/wx+/image_resources.h b/wx+/image_resources.h index 5ea56679..ff1d5648 100644 --- a/wx+/image_resources.h +++ b/wx+/image_resources.h @@ -14,7 +14,7 @@ namespace zen { -void initResourceImages(const Zstring& filePath); //pass resources .zip file at application startup +void initResourceImages(const Zstring& zipPath); //pass resources .zip file at application startup void cleanupResourceImages(); const wxBitmap& getResourceImage (const wxString& name); diff --git a/wx+/image_tools.cpp b/wx+/image_tools.cpp index 0f248057..8f94d1bc 100644 --- a/wx+/image_tools.cpp +++ b/wx+/image_tools.cpp @@ -72,7 +72,7 @@ wxImage zen::stackImages(const wxImage& img1, const wxImage& img2, ImageStackLay int width = std::max(img1Width, img2Width); int height = std::max(img1Height, img2Height); - if (dir == ImageStackLayout::HORIZONTAL) + if (dir == ImageStackLayout::horizontal) width = img1Width + gap + img2Width; else height = img1Height + gap + img2Height; @@ -85,11 +85,11 @@ wxImage zen::stackImages(const wxImage& img1, const wxImage& img2, ImageStackLay { switch (align) { - case ImageStackAlignment::CENTER: + case ImageStackAlignment::center: return static_cast(std::floor((totalExtent - imageExtent) / 2.0)); //consistency: round down negative values, too! - case ImageStackAlignment::LEFT: + case ImageStackAlignment::left: return 0; - case ImageStackAlignment::RIGHT: + case ImageStackAlignment::right: return totalExtent - imageExtent; } assert(false); @@ -98,12 +98,12 @@ wxImage zen::stackImages(const wxImage& img1, const wxImage& img2, ImageStackLay switch (dir) { - case ImageStackLayout::HORIZONTAL: + case ImageStackLayout::horizontal: writeToImage(output, img1, wxPoint(0, calcPos(img1Height, height))); writeToImage(output, img2, wxPoint(img1Width + gap, calcPos(img2Height, height))); break; - case ImageStackLayout::VERTICAL: + case ImageStackLayout::vertical: writeToImage(output, img1, wxPoint(calcPos(img1Width, width), 0)); writeToImage(output, img2, wxPoint(calcPos(img2Width, width), img1Height + gap)); break; @@ -165,13 +165,13 @@ wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const if (!lineText.empty()) switch (textAlign) { - case ImageStackAlignment::LEFT: + case ImageStackAlignment::left: dc.DrawText(lineText, wxPoint(0, posY)); break; - case ImageStackAlignment::RIGHT: + case ImageStackAlignment::right: dc.DrawText(lineText, wxPoint(maxWidth - lineSize.GetWidth(), posY)); break; - case ImageStackAlignment::CENTER: + case ImageStackAlignment::center: dc.DrawText(lineText, wxPoint((maxWidth - lineSize.GetWidth()) / 2, posY)); break; } @@ -191,7 +191,7 @@ wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const for (int i = 0; i < pixelCount; ++i) { //black(0,0,0) becomes wxIMAGE_ALPHA_OPAQUE(255), while white(255,255,255) becomes wxIMAGE_ALPHA_TRANSPARENT(0) - *alpha++ = static_cast((255 - rgb[0] + 255 - rgb[1] + 255 - rgb[2]) / 3); //mixed mode arithmetics! + *alpha++ = static_cast((255 - rgb[0] + 255 - rgb[1] + 255 - rgb[2]) / 3); //mixed-mode arithmetics! rgb[0] = col.Red (); // rgb[1] = col.Green(); //apply actual text color @@ -211,7 +211,7 @@ wxImage zen::layOver(const wxImage& back, const wxImage& front, int alignment) const int width = std::max(back.GetWidth(), front.GetWidth()); const int height = std::max(back.GetHeight(), front.GetHeight()); - const int offsetX = [&] + const int offsetX = [&] { if (alignment & wxALIGN_RIGHT) return back.GetWidth() - front.GetWidth(); @@ -239,7 +239,7 @@ wxImage zen::layOver(const wxImage& back, const wxImage& front, int alignment) ::memset(output.GetAlpha(), wxIMAGE_ALPHA_TRANSPARENT, width * height); const wxPoint posBack(std::max(-offsetX, 0), std::max(-offsetY, 0)); - writeToImage(output, back , posBack); + writeToImage(output, back, posBack); writeToImage(output, front, posBack + wxPoint(offsetX, offsetY)); return output; } diff --git a/wx+/image_tools.h b/wx+/image_tools.h index d72597ef..e2d42fb0 100644 --- a/wx+/image_tools.h +++ b/wx+/image_tools.h @@ -18,25 +18,25 @@ namespace zen { enum class ImageStackLayout { - HORIZONTAL, - VERTICAL + horizontal, + vertical }; enum class ImageStackAlignment //one-dimensional unlike wxAlignment { - CENTER, - LEFT, - RIGHT, - TOP = LEFT, - BOTTOM = RIGHT, + center, + left, + right, + top = left, + bottom = right, }; wxImage stackImages(const wxImage& img1, const wxImage& img2, ImageStackLayout dir, ImageStackAlignment align, int gap = 0); -wxImage createImageFromText(const wxString& text, const wxFont& font, const wxColor& col, ImageStackAlignment textAlign = ImageStackAlignment::LEFT); //CENTER/LEFT/RIGHT +wxImage createImageFromText(const wxString& text, const wxFont& font, const wxColor& col, ImageStackAlignment textAlign = ImageStackAlignment::left); //center/left/right wxImage layOver(const wxImage& back, const wxImage& front, int alignment = wxALIGN_CENTER); -wxImage greyScale(const wxImage& img); //greyscale + brightness adaption +wxImage greyScale(const wxImage& img); //greyscale + brightness adaption wxBitmap greyScale(const wxBitmap& bmp); // //void moveImage(wxImage& img, int right, int up); @@ -44,8 +44,6 @@ void adjustBrightness(wxImage& img, int targetLevel); double getAvgBrightness(const wxImage& img); //in [0, 255] void brighten(wxImage& img, int level); //level: delta per channel in points -bool isEqual(const wxBitmap& lhs, const wxBitmap& rhs); //pixel-wise equality (respecting alpha channel) - void convertToVanillaImage(wxImage& img); //add alpha channel if missing + remove mask if existing //wxColor gradient(const wxColor& from, const wxColor& to, double fraction); //maps fraction within [0, 1] to an intermediate color @@ -152,36 +150,6 @@ void adjustBrightness(wxImage& img, int targetLevel) } -inline -bool isEqual(const wxBitmap& lhs, const wxBitmap& rhs) -{ - if (lhs.IsOk() != rhs.IsOk()) - return false; - if (!lhs.IsOk()) - return true; - - if (lhs.GetSize() != rhs.GetSize()) - return false; - - wxImage imLhs = lhs.ConvertToImage(); - wxImage imRhs = rhs.ConvertToImage(); - - if (imLhs.HasAlpha() != imRhs.HasAlpha()) - return false; - - const int pixelCount = lhs.GetWidth() * lhs.GetHeight(); - - if (!std::equal(imLhs.GetData(), imLhs.GetData() + pixelCount * 3, imRhs.GetData())) - return false; - - if (imLhs.HasAlpha()) - if (!std::equal(imLhs.GetAlpha(), imLhs.GetAlpha() + pixelCount, imRhs.GetAlpha())) - return false; - - return true; -} - - inline wxImage shrinkImage(const wxImage& img, int requestedSize) { diff --git a/wx+/popup_dlg_generated.cpp b/wx+/popup_dlg_generated.cpp index 3e490757..af43c85b 100644 --- a/wx+/popup_dlg_generated.cpp +++ b/wx+/popup_dlg_generated.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version May 29 2018) +// C++ code generated with wxFormBuilder (version Oct 26 2018) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -39,7 +39,7 @@ PopupDialogGenerated::PopupDialogGenerated( wxWindow* parent, wxWindowID id, con bSizer16->Add( 0, 5, 0, 0, 5 ); - m_textCtrlTextDetail = new wxTextCtrl( m_panel33, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxNO_BORDER ); + m_textCtrlTextDetail = new wxTextCtrl( m_panel33, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxBORDER_NONE ); bSizer16->Add( m_textCtrlTextDetail, 1, wxEXPAND, 5 ); @@ -63,6 +63,7 @@ PopupDialogGenerated::PopupDialogGenerated( wxWindow* parent, wxWindowID id, con bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL ); m_buttonAccept = new wxButton( this, wxID_YES, _("dummy"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_buttonAccept->SetDefault(); bSizerStdButtons->Add( m_buttonAccept, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); diff --git a/wx+/popup_dlg_generated.h b/wx+/popup_dlg_generated.h index 9d9bc3f8..2b09289b 100644 --- a/wx+/popup_dlg_generated.h +++ b/wx+/popup_dlg_generated.h @@ -1,12 +1,11 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version May 29 2018) +// C++ code generated with wxFormBuilder (version Oct 26 2018) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// -#ifndef __POPUP_DLG_GENERATED_H__ -#define __POPUP_DLG_GENERATED_H__ +#pragma once #include #include @@ -70,4 +69,3 @@ public: }; -#endif //__POPUP_DLG_GENERATED_H__ diff --git a/wx+/rtl.h b/wx+/rtl.h index 0adb6037..3ab701a7 100644 --- a/wx+/rtl.h +++ b/wx+/rtl.h @@ -94,13 +94,14 @@ void drawBitmapRtlNoMirror(wxDC& dc, const wxBitmap& bmp, const wxRect& rect, in } -inline +inline wxImage mirrorIfRtl(const wxImage& bmp) { if (wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft) return bmp.Mirror(); else - return bmp;} + return bmp; +} inline diff --git a/wx+/std_button_layout.h b/wx+/std_button_layout.h index cf0152de..d2c5fc32 100644 --- a/wx+/std_button_layout.h +++ b/wx+/std_button_layout.h @@ -83,7 +83,7 @@ void setStandardButtonLayout(wxBoxSizer& sizer, const StdButtons& buttons) { assert(btn->GetMinSize().GetHeight() == -1); //let OS or this routine do the sizing! note: OS X does not allow changing the (visible!) button height! const int defaultHeight = wxButton::GetDefaultSize().GetHeight(); //buffered by wxWidgets - btn->SetMinSize(wxSize(-1, std::max(defaultHeight, fastFromDIP(30)))); //default button height is much too small => increase! + btn->SetMinSize({-1, std::max(defaultHeight, fastFromDIP(31))}); //default button height is much too small => increase! if (settingFirstButton) settingFirstButton = false; diff --git a/wx+/tooltip.cpp b/wx+/tooltip.cpp index 42fb058a..0beef0bf 100644 --- a/wx+/tooltip.cpp +++ b/wx+/tooltip.cpp @@ -61,7 +61,7 @@ void Tooltip::show(const wxString& text, wxPoint mousePos, const wxBitmap* bmp) const wxBitmap& newBmp = bmp ? *bmp : wxNullBitmap; - if (!isEqual(tipWindow_->bitmapLeft_->GetBitmap(), newBmp)) + if (!tipWindow_->bitmapLeft_->GetBitmap().IsSameAs(newBmp)) { tipWindow_->bitmapLeft_->SetBitmap(newBmp); tipWindow_->Refresh(); //needed if bitmap size changed! diff --git a/xBRZ/src/xbrz.cpp b/xBRZ/src/xbrz.cpp index 0bf9db17..5228073f 100644 --- a/xBRZ/src/xbrz.cpp +++ b/xBRZ/src/xbrz.cpp @@ -246,24 +246,32 @@ struct BlendResult }; +struct Kernel_3x3 +{ + uint32_t + a, b, c, + d, e, f, + g, h, i; +}; + struct Kernel_4x4 //kernel for preprocessing step { uint32_t - /**/a, b, c, d, - /**/e, f, g, h, - /**/i, j, k, l, - /**/m, n, o, p; + a, b, c, // + e, f, g, // support reinterpret_cast from Kernel_4x4 => Kernel_3x3 + i, j, k, // + m, n, o, + d, h, l, p; }; -/* -input kernel area naming convention: +/* input kernel area naming convention: ----------------- | A | B | C | D | -----|---|---|---| -| E | F | G | H | //evaluate the four corners between F, G, J, K -----|---|---|---| //input pixel is at position F +|---|---|---|---| +| E | F | G | H | evaluate the four corners between F, G, J, K +|---|---|---|---| input pixel is at position F | I | J | K | L | -----|---|---|---| +|---|---|---|---| | M | N | O | P | ----------------- */ @@ -306,14 +314,6 @@ BlendResult preProcessCorners(const Kernel_4x4& ker, const xbrz::ScalerCfg& cfg) return result; } -struct Kernel_3x3 -{ - uint32_t - /**/a, b, c, - /**/d, e, f, - /**/g, h, i; -}; - #define DEF_GETTER(x) template uint32_t inline get_##x(const Kernel_3x3& ker) { return ker.x; } //we cannot and NEED NOT write "ker.##x" since ## concatenates preprocessor tokens but "." is not a token DEF_GETTER(a) DEF_GETTER(b) DEF_GETTER(c) @@ -346,12 +346,16 @@ inline BlendType getTopR (unsigned char b) { return static_cast(0x3 inline BlendType getBottomR(unsigned char b) { return static_cast(0x3 & (b >> 4)); } inline BlendType getBottomL(unsigned char b) { return static_cast(0x3 & (b >> 6)); } -inline void setTopL (unsigned char& b, BlendType bt) { b |= bt; } //buffer is assumed to be initialized before preprocessing! -inline void setTopR (unsigned char& b, BlendType bt) { b |= (bt << 2); } -inline void setBottomR(unsigned char& b, BlendType bt) { b |= (bt << 4); } -inline void setBottomL(unsigned char& b, BlendType bt) { b |= (bt << 6); } +inline void clearAddTopL(unsigned char& b, BlendType bt) { b = static_cast(bt); } +inline void addTopR (unsigned char& b, BlendType bt) { b |= (bt << 2); } //buffer is assumed to be initialized before preprocessing! +inline void addBottomR (unsigned char& b, BlendType bt) { b |= (bt << 4); } //e.g. via clearAddTopL() +inline void addBottomL (unsigned char& b, BlendType bt) { b |= (bt << 6); } // -inline bool blendingNeeded(unsigned char b) { return b != 0; } +inline bool blendingNeeded(unsigned char b) +{ + static_assert(BLEND_NONE == 0); + return b != 0; +} template inline unsigned char rotateBlendInfo(unsigned char b) { return b; } @@ -360,13 +364,12 @@ template <> inline unsigned char rotateBlendInfo(unsigned char b) { ret template <> inline unsigned char rotateBlendInfo(unsigned char b) { return ((b << 6) | (b >> 2)) & 0xff; } -/* -input kernel area naming convention: +/* input kernel area naming convention: ------------- | A | B | C | -----|---|---| -| D | E | F | //input pixel is at position E -----|---|---| +|---|---|---| +| D | E | F | input pixel is at position E +|---|---|---| | G | H | I | ------------- */ @@ -456,7 +459,72 @@ void blendPixel(const Kernel_3x3& ker, } -template //scaler policy: see "Scaler2x" reference implementation +class OobReaderTransparent +{ +public: + OobReaderTransparent(const uint32_t* src, int srcWidth, int srcHeight, int y) : + s_m1(0 <= y - 1 && y - 1 < srcHeight ? src + srcWidth * (y - 1) : nullptr), + s_0 (0 <= y && y < srcHeight ? src + srcWidth * y : nullptr), + s_p1(0 <= y + 1 && y + 1 < srcHeight ? src + srcWidth * (y + 1) : nullptr), + s_p2(0 <= y + 2 && y + 2 < srcHeight ? src + srcWidth * (y + 2) : nullptr), + srcWidth_(srcWidth) {} + + void readDhlp(Kernel_4x4& ker, int x) const //(x, y) is at kernel position F + { + [[likely]] if (const int x_p2 = x + 2; 0 <= x_p2 && x_p2 < srcWidth_) + { + ker.d = s_m1 ? s_m1[x_p2] : 0; + ker.h = s_0 ? s_0 [x_p2] : 0; + ker.l = s_p1 ? s_p1[x_p2] : 0; + ker.p = s_p2 ? s_p2[x_p2] : 0; + } + else + { + ker.d = 0; + ker.h = 0; + ker.l = 0; + ker.p = 0; + } + } + +private: + const uint32_t* const s_m1; + const uint32_t* const s_0; + const uint32_t* const s_p1; + const uint32_t* const s_p2; + const int srcWidth_; +}; + + +class OobReaderDuplicate +{ +public: + OobReaderDuplicate(const uint32_t* src, int srcWidth, int srcHeight, int y) : + s_m1(src + srcWidth * std::clamp(y - 1, 0, srcHeight - 1)), + s_0 (src + srcWidth * std::clamp(y, 0, srcHeight - 1)), + s_p1(src + srcWidth * std::clamp(y + 1, 0, srcHeight - 1)), + s_p2(src + srcWidth * std::clamp(y + 2, 0, srcHeight - 1)), + srcWidth_(srcWidth) {} + + void readDhlp(Kernel_4x4& ker, int x) const //(x, y) is at kernel position F + { + const int x_p2 = std::clamp(x + 2, 0, srcWidth_ - 1); + ker.d = s_m1[x_p2]; + ker.h = s_0 [x_p2]; + ker.l = s_p1[x_p2]; + ker.p = s_p2[x_p2]; + } + +private: + const uint32_t* const s_m1; + const uint32_t* const s_0; + const uint32_t* const s_p1; + const uint32_t* const s_p2; + const int srcWidth_; +}; + + +template //scaler policy: see "Scaler2x" reference implementation void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, const xbrz::ScalerCfg& cfg, int yFirst, int yLast) { yFirst = std::max(yFirst, 0); @@ -466,64 +534,72 @@ void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, const int trgWidth = srcWidth * Scaler::scale; - //"use" space at the end of the image as temporary buffer for "on the fly preprocessing": we even could use larger area of - //"sizeof(uint32_t) * srcWidth * (yLast - yFirst)" bytes without risk of accidental overwriting before accessing - const int bufferSize = srcWidth; - unsigned char* preProcBuffer = reinterpret_cast(trg + yLast * Scaler::scale * trgWidth) - bufferSize; - std::fill(preProcBuffer, preProcBuffer + bufferSize, '\0'); - static_assert(BLEND_NONE == 0); + //(ab)use space of "sizeof(uint32_t) * srcWidth * Scaler::scale" at the end of the image as temporary + //buffer for "on the fly preprocessing" without risk of accidental overwriting before accessing + unsigned char* const preProcBuf = reinterpret_cast(trg + yLast * Scaler::scale * trgWidth) - srcWidth; //initialize preprocessing buffer for first row of current stripe: detect upper left and right corner blending //this cannot be optimized for adjacent processing stripes; we must not allow for a memory race condition! - if (yFirst > 0) { - const int y = yFirst - 1; + const OobReader oobReader(src, srcWidth, srcHeight, yFirst - 1); + + //initialize at position x = -1 + Kernel_4x4 ker4 = {}; + oobReader.readDhlp(ker4, -4); //hack: read a, e, i, m at x = -1 + ker4.a = ker4.d; + ker4.e = ker4.h; + ker4.i = ker4.l; + ker4.m = ker4.p; + + oobReader.readDhlp(ker4, -3); + ker4.b = ker4.d; + ker4.f = ker4.h; + ker4.j = ker4.l; + ker4.n = ker4.p; + + oobReader.readDhlp(ker4, -2); + ker4.c = ker4.d; + ker4.g = ker4.h; + ker4.k = ker4.l; + ker4.o = ker4.p; + + oobReader.readDhlp(ker4, -1); - const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0); - const uint32_t* s_0 = src + srcWidth * y; //center line - const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1); - const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1); + { + const BlendResult res = preProcessCorners(ker4, cfg); + clearAddTopL(preProcBuf[0], res.blend_k); //set 1st known corner for (0, yFirst) + } for (int x = 0; x < srcWidth; ++x) { - const int x_m1 = std::max(x - 1, 0); - const int x_p1 = std::min(x + 1, srcWidth - 1); - const int x_p2 = std::min(x + 2, srcWidth - 1); - - Kernel_4x4 ker = {}; //perf: initialization is negligible - ker.a = s_m1[x_m1]; //read sequentially from memory as far as possible - ker.b = s_m1[x]; - ker.c = s_m1[x_p1]; - ker.d = s_m1[x_p2]; - - ker.e = s_0[x_m1]; - ker.f = s_0[x]; - ker.g = s_0[x_p1]; - ker.h = s_0[x_p2]; - - ker.i = s_p1[x_m1]; - ker.j = s_p1[x]; - ker.k = s_p1[x_p1]; - ker.l = s_p1[x_p2]; - - ker.m = s_p2[x_m1]; - ker.n = s_p2[x]; - ker.o = s_p2[x_p1]; - ker.p = s_p2[x_p2]; - - const BlendResult res = preProcessCorners(ker, cfg); - /* - preprocessing blend result: - --------- - | F | G | //evalute corner between F, G, J, K - ----|---| //input pixel is at position F - | J | K | - --------- - */ - setTopR(preProcBuffer[x], res.blend_j); + ker4.a = ker4.b; //shift previous kernel to the left + ker4.e = ker4.f; // ----------------- + ker4.i = ker4.j; // | A | B | C | D | + ker4.m = ker4.n; // |---|---|---|---| + /**/ // | E | F | G | H | (x, yFirst - 1) is at position F + ker4.b = ker4.c; // |---|---|---|---| + ker4.f = ker4.g; // | I | J | K | L | + ker4.j = ker4.k; // |---|---|---|---| + ker4.n = ker4.o; // | M | N | O | P | + /**/ // ----------------- + ker4.c = ker4.d; + ker4.g = ker4.h; + ker4.k = ker4.l; + ker4.o = ker4.p; + + oobReader.readDhlp(ker4, x); + + /* preprocessing blend result: + --------- + | F | G | evaluate corner between F, G, J, K + |---+---| current input pixel is at position F + | J | K | + --------- */ + const BlendResult res = preProcessCorners(ker4, cfg); + addTopR(preProcBuf[x], res.blend_j); //set 2nd known corner for (x, yFirst) - if (x + 1 < bufferSize) - setTopL(preProcBuffer[x + 1], res.blend_k); + if (x + 1 < srcWidth) + clearAddTopL(preProcBuf[x + 1], res.blend_k); //set 1st known corner for (x + 1, yFirst) } } //------------------------------------------------------------------------------------ @@ -532,88 +608,89 @@ void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, { uint32_t* out = trg + Scaler::scale * y * trgWidth; //consider MT "striped" access - const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0); - const uint32_t* s_0 = src + srcWidth * y; //center line - const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1); - const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1); + const OobReader oobReader(src, srcWidth, srcHeight, y); - unsigned char blend_xy1 = 0; //corner blending for current (x, y + 1) position + //initialize at position x = -1 + Kernel_4x4 ker4 = {}; + oobReader.readDhlp(ker4, -4); //hack: read a, e, i, m at x = -1 + ker4.a = ker4.d; + ker4.e = ker4.h; + ker4.i = ker4.l; + ker4.m = ker4.p; - for (int x = 0; x < srcWidth; ++x, out += Scaler::scale) - { - //all those bounds checks have only insignificant impact on performance! - const int x_m1 = std::max(x - 1, 0); //perf: prefer array indexing to additional pointers! - const int x_p1 = std::min(x + 1, srcWidth - 1); - const int x_p2 = std::min(x + 2, srcWidth - 1); + oobReader.readDhlp(ker4, -3); + ker4.b = ker4.d; + ker4.f = ker4.h; + ker4.j = ker4.l; + ker4.n = ker4.p; - Kernel_4x4 ker4 = {}; //perf: initialization is negligible + oobReader.readDhlp(ker4, -2); + ker4.c = ker4.d; + ker4.g = ker4.h; + ker4.k = ker4.l; + ker4.o = ker4.p; - ker4.a = s_m1[x_m1]; //read sequentially from memory as far as possible - ker4.b = s_m1[x]; - ker4.c = s_m1[x_p1]; - ker4.d = s_m1[x_p2]; + oobReader.readDhlp(ker4, -1); - ker4.e = s_0[x_m1]; - ker4.f = s_0[x]; - ker4.g = s_0[x_p1]; - ker4.h = s_0[x_p2]; + unsigned char blend_xy1 = 0; //corner blending for current (x, y + 1) position + { + const BlendResult res = preProcessCorners(ker4, cfg); + clearAddTopL(blend_xy1, res.blend_k); //set 1st known corner for (0, y + 1) and buffer for use on next column - ker4.i = s_p1[x_m1]; - ker4.j = s_p1[x]; - ker4.k = s_p1[x_p1]; - ker4.l = s_p1[x_p2]; + addBottomL(preProcBuf[0], res.blend_g); //set 3rd known corner for (0, y) + } - ker4.m = s_p2[x_m1]; - ker4.n = s_p2[x]; - ker4.o = s_p2[x_p1]; - ker4.p = s_p2[x_p2]; + for (int x = 0; x < srcWidth; ++x, out += Scaler::scale) + { + ker4.a = ker4.b; //shift previous kernel to the left + ker4.e = ker4.f; // ----------------- + ker4.i = ker4.j; // | A | B | C | D | + ker4.m = ker4.n; // |---|---|---|---| + /**/ // | E | F | G | H | (x, y) is at position F + ker4.b = ker4.c; // |---|---|---|---| + ker4.f = ker4.g; // | I | J | K | L | + ker4.j = ker4.k; // |---|---|---|---| + ker4.n = ker4.o; // | M | N | O | P | + /**/ // ----------------- + ker4.c = ker4.d; + ker4.g = ker4.h; + ker4.k = ker4.l; + ker4.o = ker4.p; + + oobReader.readDhlp(ker4, x); //evaluate the four corners on bottom-right of current pixel - unsigned char blend_xy = 0; //for current (x, y) position + unsigned char blend_xy = preProcBuf[x]; //for current (x, y) position { + /* preprocessing blend result: + --------- + | F | G | evaluate corner between F, G, J, K + |---+---| current input pixel is at position F + | J | K | + --------- */ const BlendResult res = preProcessCorners(ker4, cfg); - /* - preprocessing blend result: - --------- - | F | G | //evalute corner between F, G, J, K - ----|---| //current input pixel is at position F - | J | K | - --------- - */ - blend_xy = preProcBuffer[x]; - setBottomR(blend_xy, res.blend_f); //all four corners of (x, y) have been determined at this point due to processing sequence! + addBottomR(blend_xy, res.blend_f); //all four corners of (x, y) have been determined at this point due to processing sequence! - setTopR(blend_xy1, res.blend_j); //set 2nd known corner for (x, y + 1) - preProcBuffer[x] = blend_xy1; //store on current buffer position for use on next row + addTopR(blend_xy1, res.blend_j); //set 2nd known corner for (x, y + 1) + preProcBuf[x] = blend_xy1; //store on current buffer position for use on next row - blend_xy1 = 0; - setTopL(blend_xy1, res.blend_k); //set 1st known corner for (x + 1, y + 1) and buffer for use on next column + [[likely]] if (x + 1 < srcWidth) + { + //blend_xy1 -> blend_x1y1 + clearAddTopL(blend_xy1, res.blend_k); //set 1st known corner for (x + 1, y + 1) and buffer for use on next column - if (x + 1 < bufferSize) //set 3rd known corner for (x + 1, y) - setBottomL(preProcBuffer[x + 1], res.blend_g); + addBottomL(preProcBuf[x + 1], res.blend_g); //set 3rd known corner for (x + 1, y) + } } //fill block of size scale * scale with the given color fillBlock(out, trgWidth * sizeof(uint32_t), ker4.f, Scaler::scale, Scaler::scale); - //place *after* preprocessing step, to not overwrite the results while processing the the last pixel! + //place *after* preprocessing step, to not overwrite the results while processing the last pixel! - //blend four corners of current pixel - if (blendingNeeded(blend_xy)) //good 5% perf-improvement + //blend all four corners of current pixel + if (blendingNeeded(blend_xy)) { - Kernel_3x3 ker3 = {}; //perf: initialization is negligible - - ker3.a = ker4.a; - ker3.b = ker4.b; - ker3.c = ker4.c; - - ker3.d = ker4.e; - ker3.e = ker4.f; - ker3.f = ker4.g; - - ker3.g = ker4.i; - ker3.h = ker4.j; - ker3.i = ker4.k; - + const auto& ker3 = reinterpret_cast(ker4); //"The Things We Do for Perf" blendPixel(ker3, out, trgWidth, blend_xy, cfg); blendPixel(ker3, out, trgWidth, blend_xy, cfg); blendPixel(ker3, out, trgWidth, blend_xy, cfg); @@ -1076,15 +1153,15 @@ void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth switch (factor) { case 2: - return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); case 3: - return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); case 4: - return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); case 5: - return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); case 6: - return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); } break; @@ -1092,15 +1169,15 @@ void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth switch (factor) { case 2: - return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); case 3: - return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); case 4: - return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); case 5: - return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); case 6: - return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); } break; @@ -1108,15 +1185,15 @@ void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth switch (factor) { case 2: - return scaleImage, ColorDistanceUnbufferedARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); case 3: - return scaleImage, ColorDistanceUnbufferedARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); case 4: - return scaleImage, ColorDistanceUnbufferedARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); case 5: - return scaleImage, ColorDistanceUnbufferedARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); case 6: - return scaleImage, ColorDistanceUnbufferedARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + return scaleImage, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); } break; } diff --git a/xBRZ/src/xbrz.h b/xBRZ/src/xbrz.h index f7f7169a..492fb43a 100644 --- a/xBRZ/src/xbrz.h +++ b/xBRZ/src/xbrz.h @@ -51,7 +51,6 @@ const int SCALE_FACTOR_MAX = 6; /* -> map source (srcWidth * srcHeight) to target (scale * width x scale * height) image, optionally processing a half-open slice of rows [yFirst, yLast) only --> support for source/target pitch in bytes! -> if your emulator changes only a few image slices during each cycle (e.g. DOSBox) then there's no need to run xBRZ on the complete image: Just make sure you enlarge the source image slice by 2 rows on top and 2 on bottom (this is the additional range the xBRZ algorithm is using during analysis) CAVEAT: If there are multiple changed slices, make sure they do not overlap after adding these additional rows in order to avoid a memory race condition diff --git a/xBRZ/src/xbrz_tools.h b/xBRZ/src/xbrz_tools.h index 15bea025..b8bb8aa0 100644 --- a/xBRZ/src/xbrz_tools.h +++ b/xBRZ/src/xbrz_tools.h @@ -56,7 +56,7 @@ Pix* byteAdvance(Pix* ptr, int bytes) //fill block with the given color template inline -void fillBlock(Pix* trg, int pitch, Pix col, int blockWidth, int blockHeight) +void fillBlock(Pix* trg, int pitch /*[bytes]*/, Pix col, int blockWidth, int blockHeight) { //for (int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch)) // std::fill(trg, trg + blockWidth, col); @@ -69,8 +69,8 @@ void fillBlock(Pix* trg, int pitch, Pix col, int blockWidth, int blockHeight) //nearest-neighbor (going over target image - slow for upscaling, since source is read multiple times missing out on cache! Fast for similar image sizes!) template -void nearestNeighborScale(const PixSrc* src, int srcWidth, int srcHeight, int srcPitch, - /**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch, +void nearestNeighborScale(const PixSrc* src, int srcWidth, int srcHeight, int srcPitch /*[bytes]*/, + /**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch /*[bytes]*/, int yFirst, int yLast, PixConverter pixCvrt /*convert PixSrc to PixTrg*/) { static_assert(std::is_integral::value, "PixSrc* is expected to be cast-able to char*"); @@ -106,8 +106,8 @@ void nearestNeighborScale(const PixSrc* src, int srcWidth, int srcHeight, int sr //nearest-neighbor (going over source image - fast for upscaling, since source is read only once template -void nearestNeighborScaleOverSource(const PixSrc* src, int srcWidth, int srcHeight, int srcPitch, - /**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch, +void nearestNeighborScaleOverSource(const PixSrc* src, int srcWidth, int srcHeight, int srcPitch /*[bytes]*/, + /**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch /*[bytes]*/, int yFirst, int yLast, PixConverter pixCvrt /*convert PixSrc to PixTrg*/) { static_assert(std::is_integral::value, "PixSrc* is expected to be cast-able to char*"); diff --git a/zen/globals.h b/zen/globals.h index e59d64c1..4c1453a2 100644 --- a/zen/globals.h +++ b/zen/globals.h @@ -206,7 +206,7 @@ void registerGlobalForDestruction(CleanUpEntry& entry) //------------------------------------------------------------------------------------------ #if __cpp_lib_atomic_wait -#error implement + rewiew improvements + #error implement + rewiew improvements #endif diff --git a/zen/legacy_compiler.h b/zen/legacy_compiler.h index 6ce1d765..54dd7f59 100644 --- a/zen/legacy_compiler.h +++ b/zen/legacy_compiler.h @@ -9,9 +9,9 @@ #if !__cpp_lib_erase_if -#include -#include -#include + #include + #include + #include #endif diff --git a/zen/serialize.h b/zen/serialize.h index 5a38303c..bdeec858 100644 --- a/zen/serialize.h +++ b/zen/serialize.h @@ -9,6 +9,7 @@ #include #include +#include #include "string_base.h" //keep header clean from specific stream implementations! (e.g.file_io.h)! used by abstract.h! diff --git a/zen/stl_tools.h b/zen/stl_tools.h index d09010ad..8856ce84 100644 --- a/zen/stl_tools.h +++ b/zen/stl_tools.h @@ -96,7 +96,7 @@ public: /**/ T& ref() { return *ref_; }; const T& ref() const { return *ref_; }; - std::shared_ptr< T> ptr() { return ref_; }; + std::shared_ptr< T> ptr() { return ref_; }; std::shared_ptr ptr() const { return ref_; }; private: @@ -207,9 +207,9 @@ BidirectionalIterator1 searchLast(const BidirectionalIterator1 first1, Bid //http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0458r2.html template >> inline -bool contains(const Container& c, const ValueType& val, int dummy = 0 /*overload string_tools.h contains()*/) + bool contains(const Container& c, const ValueType& val, int dummy = 0 /*overload string_tools.h contains()*/) { - return c.find(val) != c.end(); + return c.find(val) != c.end(); } //--------------------------------------------------------------------------------------- diff --git a/zen/string_tools.h b/zen/string_tools.h index 7f9a07ff..47271bc7 100644 --- a/zen/string_tools.h +++ b/zen/string_tools.h @@ -34,19 +34,19 @@ template Char asciiToUpper(Char c); //both S and T can be strings or char/wchar_t arrays or single char/wchar_t template >> bool contains(const S& str, const T& term); -template bool startsWith (const S& str, const T& prefix); -template bool startsWithAsciiNoCase(const S& str, const T& prefix); + template bool startsWith (const S& str, const T& prefix); + template bool startsWithAsciiNoCase(const S& str, const T& prefix); -template bool endsWith (const S& str, const T& postfix); -template bool endsWithAsciiNoCase(const S& str, const T& postfix); + template bool endsWith (const S& str, const T& postfix); + template bool endsWithAsciiNoCase(const S& str, const T& postfix); -template bool equalString (const S& lhs, const T& rhs); -template bool equalAsciiNoCase(const S& lhs, const T& rhs); + template bool equalString (const S& lhs, const T& rhs); + template bool equalAsciiNoCase(const S& lhs, const T& rhs); -template int compareString (const S& lhs, const T& rhs); -template int compareAsciiNoCase(const S& lhs, const T& rhs); //basic case-insensitive comparison (considering A-Z only!) + template int compareString (const S& lhs, const T& rhs); + template int compareAsciiNoCase(const S& lhs, const T& rhs); //basic case-insensitive comparison (considering A-Z only!) -struct LessAsciiNoCase //STL container predicate + struct LessAsciiNoCase //STL container predicate { template bool operator()(const S& lhs, const S& rhs) const { return compareAsciiNoCase(lhs, rhs) < 0; } }; @@ -165,21 +165,21 @@ template inline Char asciiToLower(Char c) { if (static_cast('A') <= c && c <= static_cast('Z')) - return static_cast(c - static_cast('A') + static_cast('a')); - return c; + return static_cast(c - static_cast('A') + static_cast('a')); + return c; } -template inline -Char asciiToUpper(Char c) + template inline + Char asciiToUpper(Char c) { if (static_cast('a') <= c && c <= static_cast('z')) - return static_cast(c - static_cast('a') + static_cast('A')); - return c; + return static_cast(c - static_cast('a') + static_cast('A')); + return c; } -namespace impl + namespace impl { inline int strcmpWithNulls(const char* ptr1, const char* ptr2, size_t num) { return std:: memcmp(ptr1, ptr2, num); } //support embedded 0, unlike strncmp/wcsncmp! inline int strcmpWithNulls(const wchar_t* ptr1, const wchar_t* ptr2, size_t num) { return std::wmemcmp(ptr1, ptr2, num); } // @@ -793,10 +793,10 @@ template inline S numberTo(const Num& number) { using TypeTag = std::integral_constant::value ? impl::NumberType::SIGNED_INT : - IsUnsignedInt::value ? impl::NumberType::UNSIGNED_INT : - IsFloat ::value ? impl::NumberType::FLOATING_POINT : - impl::NumberType::OTHER>; + IsSignedInt ::value ? impl::NumberType::SIGNED_INT : + IsUnsignedInt::value ? impl::NumberType::UNSIGNED_INT : + IsFloat ::value ? impl::NumberType::FLOATING_POINT : + impl::NumberType::OTHER>; return impl::numberTo(number, TypeTag()); } @@ -806,10 +806,10 @@ template inline Num stringTo(const S& str) { using TypeTag = std::integral_constant::value ? impl::NumberType::SIGNED_INT : - IsUnsignedInt::value ? impl::NumberType::UNSIGNED_INT : - IsFloat ::value ? impl::NumberType::FLOATING_POINT : - impl::NumberType::OTHER>; + IsSignedInt ::value ? impl::NumberType::SIGNED_INT : + IsUnsignedInt::value ? impl::NumberType::UNSIGNED_INT : + IsFloat ::value ? impl::NumberType::FLOATING_POINT : + impl::NumberType::OTHER>; return impl::stringTo(str, TypeTag()); } diff --git a/zen/sys_error.h b/zen/sys_error.h index f3b38250..57503732 100644 --- a/zen/sys_error.h +++ b/zen/sys_error.h @@ -85,7 +85,7 @@ std::wstring formatSystemError(const std::wstring& functionName, long long lastE inline std::wstring formatSystemError(const std::wstring& functionName, ErrorCode ec) { - const std::wstring errorDescr = formatSystemErrorRaw(ec); + const std::wstring errorDescr = formatSystemErrorRaw(ec); const std::wstring errorCode = numberTo(ec); //const std::wstring errorCode = printNumber(L"0x%08x", static_cast(ec)); -- cgit