diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 4ec388c14..88e4745d1 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -7,7 +7,6 @@ use File::Basename qw(basename); use FindBin; use List::Util qw(first); use Slic3r::GUI::2DBed; -use Slic3r::GUI::AboutDialog; use Slic3r::GUI::BedShapeDialog; use Slic3r::GUI::ConfigWizard; use Slic3r::GUI::Controller; @@ -191,13 +190,6 @@ sub recreate_GUI{ } } -sub about { - my ($self) = @_; - my $about = Slic3r::GUI::AboutDialog->new(undef); - $about->ShowModal; - $about->Destroy; -} - sub system_info { my ($self) = @_; my $slic3r_info = Slic3r::slic3r_info(format => 'html'); diff --git a/lib/Slic3r/GUI/AboutDialog.pm b/lib/Slic3r/GUI/AboutDialog.pm deleted file mode 100644 index 0879ea35b..000000000 --- a/lib/Slic3r/GUI/AboutDialog.pm +++ /dev/null @@ -1,122 +0,0 @@ -package Slic3r::GUI::AboutDialog; -use strict; -use warnings; -use utf8; - -use Wx qw(:font :html :misc :dialog :sizer :systemsettings :frame :id); -use Wx::Event qw(EVT_HTML_LINK_CLICKED EVT_LEFT_DOWN EVT_BUTTON); -use Wx::Print; -use Wx::Html; -use base 'Wx::Dialog'; - -sub new { - my $class = shift; - my ($parent) = @_; - my $self = $class->SUPER::new($parent, -1, 'About Slic3r', wxDefaultPosition, [600, 340], wxCAPTION); - - $self->SetBackgroundColour(Wx::wxWHITE); - my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL); - $self->SetSizer($hsizer); - - # logo - my $logo = Slic3r::GUI::AboutDialog::Logo->new($self, -1, wxDefaultPosition, wxDefaultSize); - $logo->SetBackgroundColour(Wx::wxWHITE); - $hsizer->Add($logo, 0, wxEXPAND | wxLEFT | wxRIGHT, 30); - - my $vsizer = Wx::BoxSizer->new(wxVERTICAL); - $hsizer->Add($vsizer, 1, wxEXPAND, 0); - - # title - my $title = Wx::StaticText->new($self, -1, $Slic3r::FORK_NAME, wxDefaultPosition, wxDefaultSize); - my $title_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - $title_font->SetWeight(wxFONTWEIGHT_BOLD); - $title_font->SetFamily(wxFONTFAMILY_ROMAN); - $title_font->SetPointSize(24); - $title->SetFont($title_font); - $vsizer->Add($title, 0, wxALIGN_LEFT | wxTOP, 30); - - # version - my $version = Wx::StaticText->new($self, -1, "Version $Slic3r::VERSION", wxDefaultPosition, wxDefaultSize); - my $version_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - $version_font->SetPointSize(&Wx::wxMSW ? 9 : 11); - $version->SetFont($version_font); - $vsizer->Add($version, 0, wxALIGN_LEFT | wxBOTTOM, 10); - - # text - my $text = - '' . - '' . - '' . - 'Copyright © 2016 Vojtech Bubnik, Prusa Research.
' . - 'Copyright © 2011-2016 Alessandro Ranellucci.
' . - 'Slic3r is licensed under the ' . - 'GNU Affero General Public License, version 3.' . - '


' . - 'Contributions by Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, Petr Ledvina, Y. Sapir, Mike Sheldrake and numerous others. ' . - 'Manual by Gary Hodgson. Inspired by the RepRap community.
' . - 'Slic3r logo designed by Corey Daniels, Silk Icon Set designed by Mark James. ' . - '
' . - '' . - ''; - my $html = Wx::HtmlWindow->new($self, -1, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_NEVER); - my $font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - my $size = &Wx::wxMSW ? 8 : 10; - $html->SetFonts($font->GetFaceName, $font->GetFaceName, [$size, $size, $size, $size, $size, $size, $size]); - $html->SetBorders(2); - $html->SetPage($text); - $vsizer->Add($html, 1, wxEXPAND | wxALIGN_LEFT | wxRIGHT | wxBOTTOM, 20); - EVT_HTML_LINK_CLICKED($self, $html, \&link_clicked); - - my $buttons = $self->CreateStdDialogButtonSizer(wxOK); - $self->SetEscapeId(wxID_CLOSE); - EVT_BUTTON($self, wxID_CLOSE, sub { - $self->EndModal(wxID_CLOSE); - $self->Close; - }); - $vsizer->Add($buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 3); - - EVT_LEFT_DOWN($self, sub { $self->Close }); - EVT_LEFT_DOWN($logo, sub { $self->Close }); - - return $self; -} - -sub link_clicked { - my ($self, $event) = @_; - - Wx::LaunchDefaultBrowser($event->GetLinkInfo->GetHref); - $event->Skip(0); -} - -package Slic3r::GUI::AboutDialog::Logo; -use Wx qw(:bitmap :dc); -use Wx::Event qw(EVT_PAINT); -use base 'Wx::Panel'; - -sub new { - my $class = shift; - my $self = $class->SUPER::new(@_); - - $self->{logo} = Wx::Bitmap->new(Slic3r::var("Slic3r_192px.png"), wxBITMAP_TYPE_PNG); - $self->SetMinSize(Wx::Size->new($self->{logo}->GetWidth, $self->{logo}->GetHeight)); - - EVT_PAINT($self, \&repaint); - - return $self; -} - -sub repaint { - my ($self, $event) = @_; - - my $dc = Wx::PaintDC->new($self); - $dc->SetBackgroundMode(wxTRANSPARENT); - - my $size = $self->GetSize; - my $logo_w = $self->{logo}->GetWidth; - my $logo_h = $self->{logo}->GetHeight; - $dc->DrawBitmap($self->{logo}, ($size->GetWidth - $logo_w) / 2, ($size->GetHeight - $logo_h) / 2, 1); - - $event->Skip; -} - -1; diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index b2f51b9e1..31124e432 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -237,12 +237,6 @@ sub _init_menubar { $self->repair_stl; }, undef, 'wrench.png'); $fileMenu->AppendSeparator(); - # Cmd+, is standard on OS X - what about other operating systems? - $self->_append_menu_item($fileMenu, L("Preferences…\tCtrl+,"), L('Application preferences'), sub { - # Opening the C++ preferences dialog. - Slic3r::GUI::open_preferences_dialog($self->{preferences_event}); - }, wxID_PREFERENCES); - $fileMenu->AppendSeparator(); $self->_append_menu_item($fileMenu, L("&Quit"), L('Quit Slic3r'), sub { $self->Close(0); }, wxID_EXIT); @@ -348,7 +342,7 @@ sub _init_menubar { Wx::LaunchDefaultBrowser('http://github.com/prusa3d/slic3r/issues/new'); }); $self->_append_menu_item($helpMenu, L("&About Slic3r"), L('Show about dialog'), sub { - wxTheApp->about; + Slic3r::GUI::about; }); } @@ -362,11 +356,9 @@ sub _init_menubar { $menubar->Append($self->{object_menu}, L("&Object")) if $self->{object_menu}; $menubar->Append($windowMenu, L("&Window")); $menubar->Append($self->{viewMenu}, L("&View")) if $self->{viewMenu}; - # Add an optional debug menu - # (Select application language from the list of installed languages) - Slic3r::GUI::add_debug_menu($menubar, $self->{lang_ch_event}); + # Add a configuration menu. + Slic3r::GUI::add_config_menu($menubar, $self->{preferences_event}, $self->{lang_ch_event}); $menubar->Append($helpMenu, L("&Help")); - # Add an optional debug menu. In production code, the add_debug_menu() call should do nothing. $self->SetMenuBar($menubar); } } diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index 84f169e57..b9a6dbfee 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -170,6 +170,8 @@ add_library(libslic3r STATIC ) add_library(libslic3r_gui STATIC + ${LIBDIR}/slic3r/GUI/AboutDialog.cpp + ${LIBDIR}/slic3r/GUI/AboutDialog.hpp ${LIBDIR}/slic3r/GUI/AppConfig.cpp ${LIBDIR}/slic3r/GUI/AppConfig.hpp ${LIBDIR}/slic3r/GUI/BitmapCache.cpp @@ -533,13 +535,13 @@ if (SLIC3R_PRUSACONTROL) set(wxWidgets_UseAlienWx 1) if (wxWidgets_UseAlienWx) set(AlienWx_DEBUG 1) - find_package(AlienWx REQUIRED COMPONENTS base core adv) + find_package(AlienWx REQUIRED COMPONENTS base core adv html) include_directories(${AlienWx_INCLUDE_DIRS}) #add_compile_options(${AlienWx_CXX_FLAGS}) add_definitions(${AlienWx_DEFINITIONS}) set(wxWidgets_LIBRARIES ${AlienWx_LIBRARIES}) else () - find_package(wxWidgets REQUIRED COMPONENTS base core adv) + find_package(wxWidgets REQUIRED COMPONENTS base core adv html) include(${wxWidgets_USE_FILE}) endif () add_definitions(-DSLIC3R_GUI -DSLIC3R_PRUS) diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index 47a584343..06eb041df 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -12,7 +12,7 @@ our $VERSION = '0.01'; BEGIN { if ($^O eq 'MSWin32') { eval "use Wx"; -# eval "use Wx::Html"; + eval "use Wx::Html"; eval "use Wx::Print"; # because of some Wx bug, thread creation fails if we don't have this (looks like Wx::Printout is hard-coded in some thread cleanup code) } } diff --git a/xs/src/libslic3r/FileParserError.hpp b/xs/src/libslic3r/FileParserError.hpp index 82a6b328e..3f560fa4f 100644 --- a/xs/src/libslic3r/FileParserError.hpp +++ b/xs/src/libslic3r/FileParserError.hpp @@ -4,6 +4,7 @@ #include "libslic3r.h" #include +#include #include namespace Slic3r { @@ -15,6 +16,9 @@ public: file_parser_error(const std::string &msg, const std::string &file, unsigned long line = 0) : std::runtime_error(format_what(msg, file, line)), m_message(msg), m_filename(file), m_line(line) {} + file_parser_error(const std::string &msg, const boost::filesystem::path &file, unsigned long line = 0) : + std::runtime_error(format_what(msg, file.string(), line)), + m_message(msg), m_filename(file.string()), m_line(line) {} // gcc 3.4.2 complains about lack of throw specifier on compiler // generated dtor ~file_parser_error() throw() {} diff --git a/xs/src/slic3r/Config/Snapshot.cpp b/xs/src/slic3r/Config/Snapshot.cpp index 559e4c63c..91f02ab25 100644 --- a/xs/src/slic3r/Config/Snapshot.cpp +++ b/xs/src/slic3r/Config/Snapshot.cpp @@ -205,6 +205,22 @@ size_t SnapshotDB::load_db() return m_snapshots.size(); } +void SnapshotDB::update_slic3r_versions(std::vector &index_db) +{ + for (Snapshot &snapshot : m_snapshots) { + for (Snapshot::VendorConfig &vendor_config : snapshot.vendor_configs) { + auto it = std::find_if(index_db.begin(), index_db.end(), [&vendor_config](const Index &idx) { return idx.vendor() == vendor_config.name; }); + if (it != index_db.end()) { + Index::const_iterator it_version = it->find(vendor_config.version); + if (it_version != it->end()) { + vendor_config.min_slic3r_version = it_version->min_slic3r_version; + vendor_config.max_slic3r_version = it_version->max_slic3r_version; + } + } + } + } +} + static void copy_config_dir_single_level(const boost::filesystem::path &path_src, const boost::filesystem::path &path_dst) { if (! boost::filesystem::is_directory(path_dst) && @@ -303,6 +319,26 @@ boost::filesystem::path SnapshotDB::create_db_dir() return snapshots_dir; } +SnapshotDB& SnapshotDB::singleton() +{ + static SnapshotDB instance; + bool loaded = false; + if (! loaded) { + try { + loaded = true; + // Load the snapshot database. + instance.load_db(); + // Load the vendor specific configuration indices. + std::vector index_db = Index::load_db(); + // Update the min / max slic3r versions compatible with the configurations stored inside the snapshots + // based on the min / max slic3r versions defined by the vendor specific config indices. + instance.update_slic3r_versions(index_db); + } catch (std::exception &ex) { + } + } + return instance; +} + } // namespace Config } // namespace GUI } // namespace Slic3r diff --git a/xs/src/slic3r/Config/Snapshot.hpp b/xs/src/slic3r/Config/Snapshot.hpp index 358797bf7..1d02c8650 100644 --- a/xs/src/slic3r/Config/Snapshot.hpp +++ b/xs/src/slic3r/Config/Snapshot.hpp @@ -6,6 +6,7 @@ #include +#include "Version.hpp" #include "../Utils/Semver.hpp" namespace Slic3r { @@ -15,6 +16,8 @@ class AppConfig; namespace GUI { namespace Config { +class Version; + // A snapshot contains: // Slic3r.ini // vendor/ @@ -75,12 +78,16 @@ public: class SnapshotDB { public: + // Initialize the SnapshotDB singleton instance. Load the database if it has not been loaded yet. + static SnapshotDB& singleton(); + typedef std::vector::const_iterator const_iterator; // Load the snapshot database from the snapshots directory. // If the snapshot directory or its parent does not exist yet, it will be created. // Returns a number of snapshots loaded. size_t load_db(); + void update_slic3r_versions(std::vector &index_db); // Create a snapshot directory, copy the vendor config bundles, user print/filament/printer profiles, // create an index. diff --git a/xs/src/slic3r/Config/Version.cpp b/xs/src/slic3r/Config/Version.cpp index 1102f3149..cc961829d 100644 --- a/xs/src/slic3r/Config/Version.cpp +++ b/xs/src/slic3r/Config/Version.cpp @@ -6,6 +6,8 @@ #include "../../libslic3r/libslic3r.h" #include "../../libslic3r/Config.hpp" +#include "../../libslic3r/FileParserError.hpp" +#include "../../libslic3r/Utils.hpp" namespace Slic3r { namespace GUI { @@ -62,11 +64,12 @@ inline std::string unquote_version_comment(char *value, char *end, const std::st return svalue; } -size_t Index::load(const std::string &path) +size_t Index::load(const boost::filesystem::path &path) { m_configs.clear(); + m_vendor = path.stem().string(); - boost::nowide::ifstream ifs(path); + boost::nowide::ifstream ifs(path.string()); std::string line; size_t idx_line = 0; Version ver; @@ -96,7 +99,7 @@ size_t Index::load(const std::string &path) if (semver) throw file_parser_error("Key cannot be a semantic version", path, idx_line); // Verify validity of the key / value pair. - std::string svalue = unquote_value(left_trim(++ value), end, path, idx_line); + std::string svalue = unquote_value(left_trim(++ value), end, path.string(), idx_line); if (key == "min_sic3r_version" || key == "max_slic3r_version") { if (! svalue.empty()) semver = Semver::parse(key); @@ -113,13 +116,24 @@ size_t Index::load(const std::string &path) if (! semver) throw file_parser_error("Invalid semantic version", path, idx_line); ver.config_version = *semver; - ver.comment = (end <= key_end) ? "" : unquote_version_comment(value, end, path, idx_line); + ver.comment = (end <= key_end) ? "" : unquote_version_comment(value, end, path.string(), idx_line); m_configs.emplace_back(ver); } + // Sort the configs by their version. + std::sort(m_configs.begin(), m_configs.end(), [](const Version &v1, const Version &v2) { return v1.config_version < v2.config_version; }); return m_configs.size(); } +Index::const_iterator Index::find(const Semver &ver) +{ + Version key; + key.config_version = ver; + auto it = std::lower_bound(m_configs.begin(), m_configs.end(), key, + [](const Version &v1, const Version &v2) { return v1.config_version < v2.config_version; }); + return (it == m_configs.end() || it->config_version == ver) ? it : m_configs.end(); +} + Index::const_iterator Index::recommended() const { int idx = -1; @@ -131,6 +145,31 @@ Index::const_iterator Index::recommended() const return highest; } +std::vector Index::load_db() +{ + boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir()); + boost::filesystem::path vendor_dir = data_dir / "vendor"; + + std::vector index_db; + std::string errors_cummulative; + for (auto &dir_entry : boost::filesystem::directory_iterator(vendor_dir)) + if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".idx")) { + Index idx; + try { + idx.load(dir_entry.path()); + } catch (const std::runtime_error &err) { + errors_cummulative += err.what(); + errors_cummulative += "\n"; + continue; + } + index_db.emplace_back(std::move(idx)); + } + + if (! errors_cummulative.empty()) + throw std::runtime_error(errors_cummulative); + return index_db; +} + } // namespace Config } // namespace GUI } // namespace Slic3r diff --git a/xs/src/slic3r/Config/Version.hpp b/xs/src/slic3r/Config/Version.hpp index 7af1d4b5b..43512e82f 100644 --- a/xs/src/slic3r/Config/Version.hpp +++ b/xs/src/slic3r/Config/Version.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include "../../libslic3r/FileParserError.hpp" #include "../Utils/Semver.hpp" @@ -54,17 +56,25 @@ public: typedef std::vector::const_iterator const_iterator; // Read a config index file in the simple format described in the Index class comment. // Throws Slic3r::file_parser_error and the standard std file access exceptions. - size_t load(const std::string &path); + size_t load(const boost::filesystem::path &path); + + const std::string& vendor() const { return m_vendor; } const_iterator begin() const { return m_configs.begin(); } const_iterator end() const { return m_configs.end(); } + const_iterator find(const Semver &ver); const std::vector& configs() const { return m_configs; } // Finds a recommended config to be installed for the current Slic3r version. // Returns configs().end() if such version does not exist in the index. This shall never happen // if the index is valid. const_iterator recommended() const; + // Load all vendor specific indices. + // Throws Slic3r::file_parser_error and the standard std file access exceptions. + static std::vector load_db(); + private: + std::string m_vendor; std::vector m_configs; }; diff --git a/xs/src/slic3r/GUI/AboutDialog.cpp b/xs/src/slic3r/GUI/AboutDialog.cpp new file mode 100644 index 000000000..49cfff2bd --- /dev/null +++ b/xs/src/slic3r/GUI/AboutDialog.cpp @@ -0,0 +1,125 @@ +#include "AboutDialog.hpp" + +#include "../../libslic3r/Utils.hpp" + +namespace Slic3r { +namespace GUI { + +AboutDialogLogo::AboutDialogLogo(wxWindow* parent) + : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize) +{ + this->SetBackgroundColour(*wxWHITE); + this->logo = wxBitmap(from_u8(Slic3r::var("Slic3r_192px.png")), wxBITMAP_TYPE_PNG); + this->SetMinSize(this->logo.GetSize()); + + this->Bind(wxEVT_PAINT, &AboutDialogLogo::onRepaint, this); +} + +void AboutDialogLogo::onRepaint(wxEvent &event) +{ + wxPaintDC dc(this); + dc.SetBackgroundMode(wxTRANSPARENT); + + wxSize size = this->GetSize(); + int logo_w = this->logo.GetWidth(); + int logo_h = this->logo.GetHeight(); + dc.DrawBitmap(this->logo, (size.GetWidth() - logo_w)/2, (size.GetHeight() - logo_h)/2, true); + + event.Skip(); +} + +AboutDialog::AboutDialog() + : wxDialog(NULL, wxID_ANY, _(L("About Slic3r")), wxDefaultPosition, wxSize(600, 340), wxCAPTION) +{ + this->SetBackgroundColour(*wxWHITE); + + wxBoxSizer* hsizer = new wxBoxSizer(wxHORIZONTAL); + this->SetSizer(hsizer); + + // logo + AboutDialogLogo* logo = new AboutDialogLogo(this); + hsizer->Add(logo, 0, wxEXPAND | wxLEFT | wxRIGHT, 30); + + wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL); + hsizer->Add(vsizer, 1, wxEXPAND, 0); + + // title + { + wxStaticText* title = new wxStaticText(this, wxID_ANY, "Slic3r Prusa Edition", wxDefaultPosition, wxDefaultSize); + wxFont title_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + title_font.SetWeight(wxFONTWEIGHT_BOLD); + title_font.SetFamily(wxFONTFAMILY_ROMAN); + title_font.SetPointSize(24); + title->SetFont(title_font); + vsizer->Add(title, 0, wxALIGN_LEFT | wxTOP, 30); + } + + // version + { + std::string version_string = _(L("Version ")) + std::string(SLIC3R_VERSION); + wxStaticText* version = new wxStaticText(this, wxID_ANY, version_string.c_str(), wxDefaultPosition, wxDefaultSize); + wxFont version_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + #ifdef __WXMSW__ + version_font.SetPointSize(9); + #else + version_font.SetPointSize(11); + #endif + version->SetFont(version_font); + vsizer->Add(version, 0, wxALIGN_LEFT | wxBOTTOM, 10); + } + + // text + wxHtmlWindow* html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_NEVER); + { + wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + #ifdef __WXMSW__ + int size[] = {8,8,8,8,8,8,8}; + #else + int size[] = {11,11,11,11,11,11,11}; + #endif + html->SetFonts(font.GetFaceName(), font.GetFaceName(), size); + html->SetBorders(2); + const char* text = + "" + "" + "" + "Copyright © 2016-2018 Prusa Research.
" + "Copyright © 2011-2017 Alessandro Ranellucci.
" + "Slic3r is licensed under the " + "GNU Affero General Public License, version 3." + "


" + "Contributions by Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, Petr Ledvina, Joseph Lenox, Y. Sapir, Mike Sheldrake, Vojtech Bubnik and numerous others. " + "Manual by Gary Hodgson. Inspired by the RepRap community.
" + "Slic3r logo designed by Corey Daniels, Silk Icon Set designed by Mark James. " + "
" + "" + ""; + html->SetPage(text); + vsizer->Add(html, 1, wxEXPAND | wxALIGN_LEFT | wxRIGHT | wxBOTTOM, 20); + html->Bind(wxEVT_HTML_LINK_CLICKED, &AboutDialog::onLinkClicked, this); + } + + wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxCLOSE); + this->SetEscapeId(wxID_CLOSE); + this->Bind(wxEVT_BUTTON, &AboutDialog::onCloseDialog, this, wxID_CLOSE); + vsizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 3); + + this->Bind(wxEVT_LEFT_DOWN, &AboutDialog::onCloseDialog, this); + logo->Bind(wxEVT_LEFT_DOWN, &AboutDialog::onCloseDialog, this); + html->Bind(wxEVT_LEFT_DOWN, &AboutDialog::onCloseDialog, this); +} + +void AboutDialog::onLinkClicked(wxHtmlLinkEvent &event) +{ + wxLaunchDefaultBrowser(event.GetLinkInfo().GetHref()); + event.Skip(false); +} + +void AboutDialog::onCloseDialog(wxEvent &) +{ + this->EndModal(wxID_CLOSE); + this->Close(); +} + +} // namespace GUI +} // namespace Slic3r diff --git a/xs/src/slic3r/GUI/AboutDialog.hpp b/xs/src/slic3r/GUI/AboutDialog.hpp new file mode 100644 index 000000000..01f7564c5 --- /dev/null +++ b/xs/src/slic3r/GUI/AboutDialog.hpp @@ -0,0 +1,36 @@ +#ifndef slic3r_GUI_AboutDialog_hpp_ +#define slic3r_GUI_AboutDialog_hpp_ + +#include "GUI.hpp" + +#include +#include +#include + +namespace Slic3r { +namespace GUI { + +class AboutDialogLogo : public wxPanel +{ +public: + AboutDialogLogo(wxWindow* parent); + +private: + wxBitmap logo; + void onRepaint(wxEvent &event); +}; + +class AboutDialog : public wxDialog +{ +public: + AboutDialog(); + +private: + void onLinkClicked(wxHtmlLinkEvent &event); + void onCloseDialog(wxEvent &); +}; + +} // namespace GUI +} // namespace Slic3r + +#endif diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 3eca4e707..48d56ff11 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -42,6 +42,7 @@ #include "Tab.hpp" #include "TabIface.hpp" +#include "AboutDialog.hpp" #include "AppConfig.hpp" #include "Utils.hpp" #include "Preferences.hpp" @@ -330,32 +331,56 @@ void get_installed_languages(wxArrayString & names, } } -void add_debug_menu(wxMenuBar *menu, int event_language_change) +enum ConfigMenuIDs { + ConfigMenuWizard, + ConfigMenuSnapshots, + ConfigMenuTakeSnapshot, + ConfigMenuUpdate, + ConfigMenuPreferences, + ConfigMenuLanguage, + ConfigMenuCnt, +}; + +void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_language_change) { -//#if 0 auto local_menu = new wxMenu(); - local_menu->Append(wxWindow::NewControlId(1), _(L("Change Application Language"))); - local_menu->Bind(wxEVT_MENU, [event_language_change](wxEvent&){ - wxArrayString names; - wxArrayLong identifiers; - get_installed_languages(names, identifiers); - if (select_language(names, identifiers)){ - save_language(); - show_info(g_wxTabPanel, _(L("Application will be restarted")), _(L("Attention!"))); - if (event_language_change > 0) { - wxCommandEvent event(event_language_change); - g_wxApp->ProcessEvent(event); + wxWindowID config_id_base = wxWindow::NewControlId((int)ConfigMenuCnt); + + // Cmd+, is standard on OS X - what about other operating systems? + local_menu->Append(config_id_base + ConfigMenuWizard, _(L("Configuration Wizard\u2026")), _(L("Run configuration wizard"))); + local_menu->Append(config_id_base + ConfigMenuSnapshots, _(L("Configuration Snapshots\u2026")), _(L("Inspect / activate configuration snapshots"))); + local_menu->Append(config_id_base + ConfigMenuTakeSnapshot, _(L("Take Configuration Snapshot")), _(L("Capture a configuration snapshot"))); + local_menu->Append(config_id_base + ConfigMenuUpdate, _(L("Check for updates")), _(L("Check for configuration updates"))); + local_menu->AppendSeparator(); + local_menu->Append(config_id_base + ConfigMenuPreferences, _(L("Preferences\u2026\tCtrl+,")), _(L("Application preferences"))); + local_menu->AppendSeparator(); + local_menu->Append(config_id_base + ConfigMenuLanguage, _(L("Change Application Language"))); + local_menu->Bind(wxEVT_MENU, [config_id_base, event_language_change, event_preferences_changed](wxEvent &event){ + switch (event.GetId() - config_id_base) { + case ConfigMenuPreferences: + { + auto dlg = new PreferencesDialog(g_wxMainFrame, event_preferences_changed); + dlg->ShowModal(); + break; + } + case ConfigMenuLanguage: + { + wxArrayString names; + wxArrayLong identifiers; + get_installed_languages(names, identifiers); + if (select_language(names, identifiers)) { + save_language(); + show_info(g_wxTabPanel, _(L("Application will be restarted")), _(L("Attention!"))); + if (event_language_change > 0) { + wxCommandEvent event(event_language_change); + g_wxApp->ProcessEvent(event); + } } + break; + } } }); - menu->Append(local_menu, _(L("&Localization"))); -//#endif -} - -void open_preferences_dialog(int event_preferences) -{ - auto dlg = new PreferencesDialog(g_wxMainFrame, event_preferences); - dlg->ShowModal(); + menu->Append(local_menu, _(L("&Configuration"))); } void create_preset_tabs(bool no_controller, int event_value_change, int event_presets_changed) @@ -737,4 +762,11 @@ int get_export_option(wxFileDialog* dlg) return 0; } +void about() +{ + AboutDialog dlg; + dlg.ShowModal(); + dlg.Destroy(); +} + } } diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index 362b15307..0cbdf8729 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -82,10 +82,7 @@ wxApp* get_app(); wxColour* get_modified_label_clr(); wxColour* get_sys_label_clr(); -void add_debug_menu(wxMenuBar *menu, int event_language_change); - -// Create "Preferences" dialog after selecting menu "Preferences" in Perl part -void open_preferences_dialog(int event_preferences); +void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_language_change); // Create a new preset tab (print, filament and printer), void create_preset_tabs(bool no_controller, int event_value_change, int event_presets_changed); @@ -134,7 +131,11 @@ ConfigOptionsGroup* get_optgroup(); void add_export_option(wxFileDialog* dlg, const std::string& format); int get_export_option(wxFileDialog* dlg); -} -} + +// Display an About dialog +void about(); + +} // namespace GUI +} // namespace Slic3r #endif diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp index 1376ff164..c8d76adba 100644 --- a/xs/xsp/GUI.xsp +++ b/xs/xsp/GUI.xsp @@ -9,6 +9,9 @@ %package{Slic3r::GUI}; +void about() + %code{% Slic3r::GUI::about(); %}; + void disable_screensaver() %code{% Slic3r::GUI::disable_screensaver(); %}; @@ -32,9 +35,9 @@ void set_main_frame(SV *ui) void set_tab_panel(SV *ui) %code%{ Slic3r::GUI::set_tab_panel((wxNotebook*)wxPli_sv_2_object(aTHX_ ui, "Wx::Notebook")); %}; - -void add_debug_menu(SV *ui, int event_language_change) - %code%{ Slic3r::GUI::add_debug_menu((wxMenuBar*)wxPli_sv_2_object(aTHX_ ui, "Wx::MenuBar"), event_language_change); %}; + +void add_config_menu(SV *ui, int event_preferences_changed, int event_language_change) + %code%{ Slic3r::GUI::add_config_menu((wxMenuBar*)wxPli_sv_2_object(aTHX_ ui, "Wx::MenuBar"), event_preferences_changed, event_language_change); %}; void create_preset_tabs(bool no_controller, int event_value_change, int event_presets_changed) %code%{ Slic3r::GUI::create_preset_tabs(no_controller, event_value_change, event_presets_changed); %}; @@ -54,9 +57,6 @@ int combochecklist_get_flags(SV *ui) void set_app_config(AppConfig *app_config) %code%{ Slic3r::GUI::set_app_config(app_config); %}; -void open_preferences_dialog(int preferences_event) - %code%{ Slic3r::GUI::open_preferences_dialog(preferences_event); %}; - void set_preset_bundle(PresetBundle *preset_bundle) %code%{ Slic3r::GUI::set_preset_bundle(preset_bundle); %};