Implemented UIManager and ManageUpdatesDialog

This commit is contained in:
YuSanka 2024-04-30 17:00:41 +02:00 committed by David Kocik
parent f6724ea0bd
commit 12395e2173
6 changed files with 403 additions and 0 deletions

View File

@ -87,6 +87,7 @@ src/slic3r/GUI/Jobs/SLAImportDialog.hpp
src/slic3r/GUI/Jobs/SLAImportJob.cpp
src/slic3r/GUI/KBShortcutsDialog.cpp
src/slic3r/GUI/MainFrame.cpp
src/slic3r/GUI/UpdatesUIManager.cpp
src/slic3r/GUI/Mouse3DController.cpp
src/slic3r/GUI/MsgDialog.cpp
src/slic3r/GUI/NotificationManager.hpp

View File

@ -126,6 +126,8 @@ set(SLIC3R_GUI_SOURCES
GUI/IconManager.hpp
GUI/MainFrame.cpp
GUI/MainFrame.hpp
GUI/UpdatesUIManager.cpp
GUI/UpdatesUIManager.hpp
GUI/FrequentlyChangedParameters.cpp
GUI/FrequentlyChangedParameters.hpp
GUI/Sidebar.cpp

View File

@ -13,6 +13,7 @@
#include "GUI_ObjectManipulation.hpp"
#include "GUI_Factories.hpp"
#include "TopBar.hpp"
#include "UpdatesUIManager.hpp"
#include "format.hpp"
// Localization headers: include libslic3r version first so everything in this file
@ -2499,6 +2500,7 @@ wxMenu* GUI_App::get_config_menu()
local_menu->Append(config_id_base + ConfigMenuWizard, config_wizard_name + dots, config_wizard_tooltip);
local_menu->Append(config_id_base + ConfigMenuSnapshots, _L("&Configuration Snapshots") + dots, _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 + ConfigMenuManageUpdateConf, _L("Manage Configuration Updates"), _L("Manage Configuration Updates"));
local_menu->Append(config_id_base + ConfigMenuUpdateConf, _L("Check for Configuration Updates"), _L("Check for configuration updates"));
local_menu->Append(config_id_base + ConfigMenuUpdateApp, _L("Check for Application Updates"), _L("Check for new version of application"));
#if defined(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION)
@ -2530,6 +2532,9 @@ wxMenu* GUI_App::get_config_menu()
case ConfigMenuWizard:
run_wizard(ConfigWizard::RR_USER);
break;
case ConfigMenuManageUpdateConf:
manage_updates();
break;
case ConfigMenuUpdateConf:
check_updates(true);
break;
@ -3387,6 +3392,12 @@ bool GUI_App::config_wizard_startup()
return false;
}
void GUI_App::manage_updates()
{
ManageUpdatesDialog dlg(plater()->get_preset_archive_database());
dlg.ShowModal();
}
bool GUI_App::check_updates(const bool verbose)
{
PresetUpdater::UpdateResult updater_result;

View File

@ -96,6 +96,7 @@ enum ConfigMenuIDs {
ConfigMenuWizard,
ConfigMenuSnapshots,
ConfigMenuTakeSnapshot,
ConfigMenuManageUpdateConf,
ConfigMenuUpdateConf,
ConfigMenuUpdateApp,
ConfigMenuDesktopIntegration,
@ -441,6 +442,7 @@ private:
bool select_language();
bool config_wizard_startup();
void manage_updates();
// Returns true if the configuration is fine.
// Returns true if the configuration is not compatible and the user decided to rather close the slicer instead of reconfiguring.
bool check_updates(const bool verbose);

View File

@ -0,0 +1,294 @@
///|/ Copyright (c) Prusa Research 2018 - 2023 Oleksandra Iushchenko @YuSanka
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
#include "UpdatesUIManager.hpp"
#include "I18N.hpp"
#include "wxExtensions.hpp"
#include "PresetArchiveDatabase.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "MainFrame.hpp"
#include "format.hpp"
#include "Widgets/CheckBox.hpp"
namespace fs = boost::filesystem;
namespace Slic3r {
namespace GUI {
UIManager::UIManager(wxWindow* parent, PresetArchiveDatabase* pad, int em) :
m_parent(parent)
,m_pad(pad)
,m_main_sizer(new wxBoxSizer(wxVERTICAL))
{
auto online_label = new wxStaticText(m_parent, wxID_ANY, _L("Online Repositories"));
online_label->SetFont(wxGetApp().bold_font());
m_main_sizer->Add(online_label, 0, wxTOP | wxLEFT, 2 * em);
m_online_sizer = new wxFlexGridSizer(4, 0.75 * em, 1.5 * em);
m_online_sizer->AddGrowableCol(2);
m_online_sizer->AddGrowableCol(3);
m_online_sizer->SetFlexibleDirection(/*wxHORIZONTAL*/wxBOTH);
m_main_sizer->Add(m_online_sizer, 0, wxALL, 2 * em);
m_main_sizer->AddSpacer(em);
auto offline_label = new wxStaticText(m_parent, wxID_ANY, _L("Offline Repositories"));
offline_label->SetFont(wxGetApp().bold_font());
m_main_sizer->Add(offline_label, 0, wxTOP | wxLEFT, 2 * em);
m_offline_sizer = new wxFlexGridSizer(6, 0.75 * em, 1.5 * em);
m_offline_sizer->AddGrowableCol(1);
m_offline_sizer->AddGrowableCol(2);
m_offline_sizer->AddGrowableCol(4);
m_offline_sizer->SetFlexibleDirection(wxHORIZONTAL);
m_main_sizer->Add(m_offline_sizer, 0, wxALL, 2 * em);
fill_entries();
fill_grids();
}
void UIManager::fill_entries()
{
m_online_entries.clear();
m_offline_entries.clear();
const ArchiveRepositoryVector& archs = m_pad->get_archives();
const std::vector<std::string>& used_archs = m_pad->get_used_archives();
for (const auto& archive : archs) {
const auto& data = archive->get_manifest();
if (data.local_path.empty()) {
// online repo
bool is_used = std::find(used_archs.begin(), used_archs.end(), data.id) != used_archs.end();
m_online_entries.push_back({is_used, data.id, data.name, data.description, data.visibility });
}
else {
// offline repo
bool is_used = std::find(used_archs.begin(), used_archs.end(), data.id) != used_archs.end();
m_offline_entries.push_back({is_used, data.id, data.name, data.description, data.local_path.filename().string(), fs::exists(data.local_path)});
}
}
#if 0 // ysFIXME_delete
// Next code is just for testing
if (m_offline_entries.empty())
m_offline_entries = {
{true, "333", "Prusa AFS" , "Prusa FDM Prusa FDM Prusa FDM" , "/path/field/file1.zip", false},
{false, "444", "Prusa Trilab" , "Prusa sla Prusa sla Prusa sla" , "/path/field/file2.zip", true},
};
#endif
}
void UIManager::fill_grids()
{
// clear grids
m_online_sizer->Clear(true);
m_offline_sizer->Clear(true);
// Fill Online repository
if (!m_online_entries.empty()) {
auto add = [this](wxWindow* win) { m_online_sizer->Add(win, 0, wxALIGN_CENTER_VERTICAL); };
// header
for (const wxString& l : std::initializer_list<wxString>{ _L("Use"), "", _L("Name"), _L("Descrition") }) {
auto text = new wxStaticText(m_parent, wxID_ANY, l);
text->SetFont(wxGetApp().bold_font());
add(text);
}
// data
for (const auto& entry : m_online_entries)
{
auto chb = CheckBox::GetNewWin(m_parent, "");
CheckBox::SetValue(chb, entry.use);
chb->Bind(wxEVT_CHECKBOX, [this, chb, &entry](wxCommandEvent e) {
if (CheckBox::GetValue(chb))
m_online_selections.emplace(entry.id);
else
m_online_selections.erase(entry.id);
});
add(chb);
if (entry.visibility.empty())
add(new wxStaticText(m_parent, wxID_ANY, ""));
else {
wxStaticBitmap* bmp = new wxStaticBitmap(m_parent, wxID_ANY, *get_bmp_bundle("info"));
bmp->SetToolTip(from_u8(entry.visibility));
add(bmp);
}
add(new wxStaticText(m_parent, wxID_ANY, from_u8(entry.name)));
add(new wxStaticText(m_parent, wxID_ANY, from_u8(entry.description)));
}
}
if (!m_offline_entries.empty()) {
auto add = [this](wxWindow* win) { m_offline_sizer->Add(win, 0, wxALIGN_CENTER_VERTICAL); };
// header
for (const wxString& l : std::initializer_list<wxString>{ _L("Use"), _L("Name"), _L("Descrition"), "", _L("Sourse file"), "" }) {
auto text = new wxStaticText(m_parent, wxID_ANY, l);
text->SetFont(wxGetApp().bold_font());
add(text);
}
// data
for (const auto& entry : m_offline_entries)
{
auto chb = CheckBox::GetNewWin(m_parent, "");
CheckBox::SetValue(chb, entry.use);
chb->Bind(wxEVT_CHECKBOX, [this, chb, &entry](wxCommandEvent e) {
if (CheckBox::GetValue(chb))
m_offline_selections.emplace(entry.id);
else
m_offline_selections.erase(entry.id);
});
add(chb);
add(new wxStaticText(m_parent, wxID_ANY, from_u8(entry.name)));
add(new wxStaticText(m_parent, wxID_ANY, from_u8(entry.description)));
{
wxStaticBitmap* bmp = new wxStaticBitmap(m_parent, wxID_ANY, *get_bmp_bundle(entry.is_ok ? "tick_mark" : "exclamation"));
bmp->SetToolTip(entry.is_ok ? _L("Exists") : _L("Doesn't exist"));
add(bmp);
}
add(new wxStaticText(m_parent, wxID_ANY, from_u8(entry.source)));
{
ScalableButton* btn = new ScalableButton(m_parent, wxID_ANY, "", " " + _L("Remove") + " ");
wxGetApp().UpdateDarkUI(btn, true);
btn->Bind(wxEVT_BUTTON, [this, &entry](wxCommandEvent& event) { remove_offline_repos(entry.id); });
add(btn);
}
}
}
{
ScalableButton* btn = new ScalableButton(m_parent, wxID_ANY, "", " " + _L("Load") + "... ");
wxGetApp().UpdateDarkUI(btn, true);
btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) { load_offline_repos(); });
m_offline_sizer->Add(btn);
}
}
void UIManager::update()
{
fill_entries();
fill_grids();
m_main_sizer->Layout();
}
void UIManager::remove_offline_repos(const std::string& id)
{
m_pad->remove_local_archive(id);
update();
}
void UIManager::load_offline_repos()
{
wxArrayString input_files;
wxFileDialog dialog(m_parent, _L("Choose one or more YIP-files") + ":",
from_u8(wxGetApp().app_config->get_last_dir()), "",
file_wildcards(FT_ZIP), wxFD_OPEN | /*wxFD_MULTIPLE | */wxFD_FILE_MUST_EXIST);
if (dialog.ShowModal() == wxID_OK)
dialog.GetPaths(input_files);
if (input_files.IsEmpty())
return;
// Iterate through the input files
for (size_t i = 0; i < input_files.size(); ++i) {
std::string input_file = into_u8(input_files.Item(i));
try {
fs::path input_path = fs::path(input_file);
m_pad->add_local_archive(input_path);
}
catch (fs::filesystem_error const& e) {
std::cerr << e.what() << '\n';
}
}
update();
}
void UIManager::set_used_archives()
{
std::vector<std::string> used_ids;
for (const std::string& id : m_online_selections)
used_ids.push_back(id);
for (const std::string& id : m_offline_selections)
used_ids.push_back(id);
m_pad->set_used_archives(used_ids);
}
ManageUpdatesDialog::ManageUpdatesDialog(PresetArchiveDatabase* pad)
: DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY,
format_wxstr("%1% - %2%", SLIC3R_APP_NAME, _L("Manage Updates")),
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
this->SetFont(wxGetApp().normal_font());
const int em = em_unit();
m_manager = std::make_unique<UIManager>(this, pad, em);
auto sizer = m_manager->get_sizer();
wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK | wxCLOSE);
wxGetApp().SetWindowVariantForButton(buttons->GetCancelButton());
wxGetApp().UpdateDlgDarkUI(this, true);
this->SetEscapeId(wxID_CLOSE);
this->Bind(wxEVT_BUTTON, &ManageUpdatesDialog::onCloseDialog, this, wxID_CLOSE);
this->Bind(wxEVT_BUTTON, &ManageUpdatesDialog::onOkDialog, this, wxID_OK);
sizer->Add(buttons, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, em);
SetSizer(sizer);
sizer->SetSizeHints(this);
}
void ManageUpdatesDialog::on_dpi_changed(const wxRect &suggested_rect)
{
SetMinSize(GetBestSize());
Fit();
Refresh();
}
void ManageUpdatesDialog::onCloseDialog(wxEvent &)
{
this->EndModal(wxID_CLOSE);
}
void ManageUpdatesDialog::onOkDialog(wxEvent&)
{
m_manager->set_used_archives();
this->EndModal(wxID_CLOSE);
}
} // namespace GUI
} // namespace Slic3r

View File

@ -0,0 +1,93 @@
///|/ Copyright (c) Prusa Research 2018 - 2020 Oleksandra Iushchenko @YuSanka
///|/
#ifndef slic3r_GUI_UpdatesUIManager_hpp_
#define slic3r_GUI_UpdatesUIManager_hpp_
#include "GUI_Utils.hpp"
class wxWindow;
class wxEvent;
class wxSizer;
class wxFlexGridSizer;
namespace Slic3r {
namespace GUI {
class PresetArchiveDatabase;
class UIManager
{
struct OnlineEntry {
OnlineEntry(bool use, const std::string &id, const std::string &name, const std::string &description, const std::string &visibility) :
use(use), id(id), name(name), description(description), visibility(visibility) {}
bool use;
std::string id;
std::string name;
std::string description;
std::string visibility;
};
struct OfflineEntry {
OfflineEntry(bool use, const std::string &id, const std::string &name, const std::string &description, const std::string &source, bool is_ok) :
use(use), id(id), name(name), description(description), source(source), is_ok(is_ok) {}
bool use;
std::string id;
std::string name;
std::string description;
std::string source;
bool is_ok;
};
PresetArchiveDatabase* m_pad { nullptr };
wxWindow* m_parent { nullptr };
wxSizer* m_main_sizer { nullptr };
wxFlexGridSizer* m_online_sizer { nullptr };
wxFlexGridSizer* m_offline_sizer { nullptr };
std::vector<OnlineEntry> m_online_entries;
std::vector<OfflineEntry> m_offline_entries;
std::set<std::string> m_online_selections;
std::set<std::string> m_offline_selections;
void fill_entries();
void fill_grids();
void update();
void remove_offline_repos(const std::string& id);
void load_offline_repos();
public:
UIManager() {}
UIManager(wxWindow* parent, PresetArchiveDatabase* pad, int em);
~UIManager() {}
wxSizer* get_sizer() { return m_main_sizer; }
void set_used_archives();
};
class ManageUpdatesDialog : public DPIDialog
{
public:
ManageUpdatesDialog(PresetArchiveDatabase* pad);
~ManageUpdatesDialog() {}
protected:
void on_dpi_changed(const wxRect &suggested_rect) override;
private:
std::unique_ptr<UIManager> m_manager { nullptr };
void onCloseDialog(wxEvent &);
void onOkDialog(wxEvent &);
};
} // namespace GUI
} // namespace Slic3r
#endif