mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-08-03 12:04:05 -06:00
Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_gcode_window
This commit is contained in:
commit
db71a6308d
97 changed files with 4090 additions and 2862 deletions
|
@ -845,6 +845,57 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
|
|||
return contained_min_one;
|
||||
}
|
||||
|
||||
bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, bool& partlyOut, bool& fullyOut)
|
||||
{
|
||||
if (config == nullptr)
|
||||
return false;
|
||||
|
||||
const ConfigOptionPoints* opt = dynamic_cast<const ConfigOptionPoints*>(config->option("bed_shape"));
|
||||
if (opt == nullptr)
|
||||
return false;
|
||||
|
||||
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values));
|
||||
BoundingBoxf3 print_volume(Vec3d(unscale<double>(bed_box_2D.min(0)), unscale<double>(bed_box_2D.min(1)), 0.0), Vec3d(unscale<double>(bed_box_2D.max(0)), unscale<double>(bed_box_2D.max(1)), config->opt_float("max_print_height")));
|
||||
// Allow the objects to protrude below the print bed
|
||||
print_volume.min(2) = -1e10;
|
||||
print_volume.min(0) -= BedEpsilon;
|
||||
print_volume.min(1) -= BedEpsilon;
|
||||
print_volume.max(0) += BedEpsilon;
|
||||
print_volume.max(1) += BedEpsilon;
|
||||
|
||||
bool contained_min_one = false;
|
||||
|
||||
partlyOut = false;
|
||||
fullyOut = false;
|
||||
for (GLVolume* volume : this->volumes)
|
||||
{
|
||||
if ((volume == nullptr) || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || ((volume->composite_id.volume_id < 0) && !volume->shader_outside_printer_detection_enabled))
|
||||
continue;
|
||||
|
||||
const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box();
|
||||
bool contained = print_volume.contains(bb);
|
||||
|
||||
volume->is_outside = !contained;
|
||||
if (!volume->printable)
|
||||
continue;
|
||||
|
||||
if (contained)
|
||||
contained_min_one = true;
|
||||
|
||||
if (volume->is_outside) {
|
||||
if (print_volume.intersects(bb))
|
||||
partlyOut = true;
|
||||
else
|
||||
fullyOut = true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (out_state != nullptr)
|
||||
*out_state = state;
|
||||
*/
|
||||
return contained_min_one;
|
||||
}
|
||||
|
||||
void GLVolumeCollection::reset_outside_state()
|
||||
{
|
||||
for (GLVolume* volume : this->volumes)
|
||||
|
|
|
@ -569,6 +569,7 @@ public:
|
|||
// returns true if all the volumes are completely contained in the print volume
|
||||
// returns the containment state in the given out_state, if non-null
|
||||
bool check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state);
|
||||
bool check_outside_state(const DynamicPrintConfig* config, bool& partlyOut, bool& fullyOut);
|
||||
void reset_outside_state();
|
||||
|
||||
void update_colors_by_extruder(const DynamicPrintConfig* config);
|
||||
|
|
|
@ -285,8 +285,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
|||
"support_material_xy_spacing" })
|
||||
toggle_field(el, have_support_material);
|
||||
toggle_field("support_material_threshold", have_support_material_auto);
|
||||
toggle_field("support_material_bottom_contact_distance", have_support_material && ! have_support_soluble);
|
||||
|
||||
for (auto el : { "support_material_interface_spacing", "support_material_interface_extruder",
|
||||
for (auto el : { "support_material_bottom_interface_layers", "support_material_interface_spacing", "support_material_interface_extruder",
|
||||
"support_material_interface_speed", "support_material_interface_contact_loops" })
|
||||
toggle_field(el, have_support_material && have_support_interface);
|
||||
toggle_field("support_material_synchronize_layers", have_support_soluble);
|
||||
|
|
|
@ -1317,7 +1317,12 @@ wxString Control::get_tooltip(int tick/*=-1*/)
|
|||
"This code won't be processed during G-code generation.");
|
||||
|
||||
// Show custom Gcode as a first string of tooltop
|
||||
tooltip = " ";
|
||||
std::string space = " ";
|
||||
tooltip = space;
|
||||
auto format_gcode = [space](std::string gcode) {
|
||||
boost::replace_all(gcode, "\n", "\n" + space);
|
||||
return gcode;
|
||||
};
|
||||
tooltip +=
|
||||
tick_code_it->type == ColorChange ?
|
||||
(m_mode == SingleExtruder ?
|
||||
|
@ -1329,7 +1334,7 @@ wxString Control::get_tooltip(int tick/*=-1*/)
|
|||
format_wxstr(_L("Custom template (\"%1%\")"), gcode(Template)) :
|
||||
tick_code_it->type == ToolChange ?
|
||||
format_wxstr(_L("Extruder (tool) is changed to Extruder \"%1%\""), tick_code_it->extruder) :
|
||||
from_u8(tick_code_it->extra);// tick_code_it->type == Custom
|
||||
from_u8(format_gcode(tick_code_it->extra));// tick_code_it->type == Custom
|
||||
|
||||
// If tick is marked as a conflict (exclamation icon),
|
||||
// we should to explain why
|
||||
|
@ -1925,6 +1930,8 @@ void Control::auto_color_change()
|
|||
double delta_area = scale_(scale_(25)); // equal to 25 mm2
|
||||
|
||||
for (auto object : print.objects()) {
|
||||
if (object->layer_count() == 0)
|
||||
continue;
|
||||
double prev_area = area(object->get_layer(0)->lslices);
|
||||
|
||||
for (size_t i = 1; i < object->layers().size(); i++) {
|
||||
|
|
|
@ -902,7 +902,7 @@ void Choice::BUILD() {
|
|||
if (m_opt.width >= 0) size.SetWidth(m_opt.width*m_em_unit);
|
||||
|
||||
choice_ctrl* temp;
|
||||
if (!m_opt.gui_type.empty() && m_opt.gui_type.compare("select_open") != 0) {
|
||||
if (m_opt.gui_type != ConfigOptionDef::GUIType::undefined && m_opt.gui_type != ConfigOptionDef::GUIType::select_open) {
|
||||
m_is_editable = true;
|
||||
temp = new choice_ctrl(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size);
|
||||
}
|
||||
|
@ -965,15 +965,27 @@ void Choice::BUILD() {
|
|||
}
|
||||
|
||||
if (is_defined_input_value<choice_ctrl>(window, m_opt.type)) {
|
||||
if (m_opt.type == coFloatOrPercent) {
|
||||
switch (m_opt.type) {
|
||||
case coFloatOrPercent:
|
||||
{
|
||||
std::string old_val = !m_value.empty() ? boost::any_cast<std::string>(m_value) : "";
|
||||
if (old_val == boost::any_cast<std::string>(get_value()))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
double old_val = !m_value.empty() ? boost::any_cast<double>(m_value) : -99999;
|
||||
if (fabs(old_val - boost::any_cast<double>(get_value())) <= 0.0001)
|
||||
case coInt:
|
||||
{
|
||||
int old_val = !m_value.empty() ? boost::any_cast<int>(m_value) : 0;
|
||||
if (old_val == boost::any_cast<int>(get_value()))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
double old_val = !m_value.empty() ? boost::any_cast<double>(m_value) : -99999;
|
||||
if (fabs(old_val - boost::any_cast<double>(get_value())) <= 0.0001)
|
||||
return;
|
||||
}
|
||||
}
|
||||
on_change_field();
|
||||
}
|
||||
|
@ -1225,7 +1237,7 @@ boost::any& Choice::get_value()
|
|||
else if (m_opt_id == "brim_type")
|
||||
m_value = static_cast<BrimType>(ret_enum);
|
||||
}
|
||||
else if (m_opt.gui_type == "f_enum_open") {
|
||||
else if (m_opt.gui_type == ConfigOptionDef::GUIType::f_enum_open || m_opt.gui_type == ConfigOptionDef::GUIType::i_enum_open) {
|
||||
const int ret_enum = field->GetSelection();
|
||||
if (ret_enum < 0 || m_opt.enum_values.empty() || m_opt.type == coStrings ||
|
||||
(ret_str != m_opt.enum_values[ret_enum] && ret_str != _(m_opt.enum_labels[ret_enum])))
|
||||
|
@ -1233,6 +1245,8 @@ boost::any& Choice::get_value()
|
|||
get_value_by_opt_type(ret_str);
|
||||
else if (m_opt.type == coFloatOrPercent)
|
||||
m_value = m_opt.enum_values[ret_enum];
|
||||
else if (m_opt.type == coInt)
|
||||
m_value = atoi(m_opt.enum_values[ret_enum].c_str());
|
||||
else
|
||||
m_value = atof(m_opt.enum_values[ret_enum].c_str());
|
||||
}
|
||||
|
|
|
@ -641,6 +641,7 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool
|
|||
error = true;
|
||||
break;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(error) << state << " : " << text ;
|
||||
auto ¬ification_manager = *wxGetApp().plater()->get_notification_manager();
|
||||
if (state) {
|
||||
if(error)
|
||||
|
@ -1620,9 +1621,6 @@ void GLCanvas3D::render()
|
|||
wxGetApp().plater()->init_environment_texture();
|
||||
#endif // ENABLE_ENVIRONMENT_MAP
|
||||
|
||||
m_render_timer.Stop();
|
||||
m_extra_frame_requested_delayed = std::numeric_limits<int>::max();
|
||||
|
||||
const Size& cnv_size = get_canvas_size();
|
||||
// Probably due to different order of events on Linux/GTK2, when one switched from 3D scene
|
||||
// to preview, this was called before canvas had its final size. It reported zero width
|
||||
|
@ -1754,7 +1752,8 @@ void GLCanvas3D::render()
|
|||
m_tooltip.render(m_mouse.position, *this);
|
||||
|
||||
wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this);
|
||||
wxGetApp().plater()->get_notification_manager()->render_notifications(get_overlay_window_width());
|
||||
|
||||
wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width());
|
||||
|
||||
wxGetApp().imgui()->render();
|
||||
|
||||
|
@ -2238,24 +2237,24 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
|
||||
// checks for geometry outside the print volume to render it accordingly
|
||||
if (!m_volumes.empty()) {
|
||||
ModelInstanceEPrintVolumeState state;
|
||||
|
||||
const bool contained_min_one = m_volumes.check_outside_state(m_config, &state);
|
||||
bool partlyOut = false;
|
||||
bool fullyOut = false;
|
||||
const bool contained_min_one = m_volumes.check_outside_state(m_config, partlyOut, fullyOut);
|
||||
|
||||
#if ENABLE_WARNING_TEXTURE_REMOVAL
|
||||
_set_warning_notification(EWarning::ObjectClashed, state == ModelInstancePVS_Partly_Outside);
|
||||
_set_warning_notification(EWarning::ObjectOutside, state == ModelInstancePVS_Fully_Outside);
|
||||
if (printer_technology != ptSLA || state == ModelInstancePVS_Inside)
|
||||
_set_warning_notification(EWarning::ObjectClashed, partlyOut);
|
||||
_set_warning_notification(EWarning::ObjectOutside, fullyOut);
|
||||
if (printer_technology != ptSLA || !contained_min_one)
|
||||
_set_warning_notification(EWarning::SlaSupportsOutside, false);
|
||||
#else
|
||||
_set_warning_texture(WarningTexture::ObjectClashed, state == ModelInstancePVS_Partly_Outside);
|
||||
_set_warning_texture(WarningTexture::ObjectOutside, state == ModelInstancePVS_Fully_Outside);
|
||||
if(printer_technology != ptSLA || state == ModelInstancePVS_Inside)
|
||||
_set_warning_texture(WarningTexture::ObjectClashed, partlyOut);
|
||||
_set_warning_texture(WarningTexture::ObjectOutside, fullyOut);
|
||||
if(printer_technology != ptSLA || !contained_min_one)
|
||||
_set_warning_texture(WarningTexture::SlaSupportsOutside, false);
|
||||
#endif // ENABLE_WARNING_TEXTURE_REMOVAL
|
||||
|
||||
post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS,
|
||||
contained_min_one && !m_model->objects.empty() && state != ModelInstancePVS_Partly_Outside));
|
||||
contained_min_one && !m_model->objects.empty() && !partlyOut));
|
||||
}
|
||||
else {
|
||||
#if ENABLE_WARNING_TEXTURE_REMOVAL
|
||||
|
@ -2442,13 +2441,13 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
|
|||
if (!m_initialized)
|
||||
return;
|
||||
|
||||
// FIXME
|
||||
m_dirty |= m_main_toolbar.update_items_state();
|
||||
m_dirty |= m_undoredo_toolbar.update_items_state();
|
||||
m_dirty |= wxGetApp().plater()->get_view_toolbar().update_items_state();
|
||||
m_dirty |= wxGetApp().plater()->get_collapse_toolbar().update_items_state();
|
||||
bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply(wxGetApp().plater()->get_camera());
|
||||
m_dirty |= mouse3d_controller_applied;
|
||||
m_dirty |= wxGetApp().plater()->get_notification_manager()->update_notifications(*this);
|
||||
|
||||
if (!m_dirty)
|
||||
return;
|
||||
|
@ -2986,30 +2985,39 @@ void GLCanvas3D::on_timer(wxTimerEvent& evt)
|
|||
|
||||
void GLCanvas3D::on_render_timer(wxTimerEvent& evt)
|
||||
{
|
||||
// If slicer is not top window -> restart timer with one second to try again
|
||||
wxWindow* p = dynamic_cast<wxWindow*>(wxGetApp().plater());
|
||||
while (p->GetParent() != nullptr)
|
||||
p = p->GetParent();
|
||||
wxTopLevelWindow* top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p);
|
||||
if (!top_level_wnd->IsActive()) {
|
||||
request_extra_frame_delayed(1000);
|
||||
return;
|
||||
}
|
||||
//render();
|
||||
m_dirty = true;
|
||||
wxWakeUpIdle();
|
||||
// no need to do anything here
|
||||
// right after this event is recieved, idle event is fired
|
||||
|
||||
//m_dirty = true;
|
||||
//wxWakeUpIdle();
|
||||
}
|
||||
|
||||
void GLCanvas3D::request_extra_frame_delayed(int miliseconds)
|
||||
|
||||
void GLCanvas3D::schedule_extra_frame(int miliseconds)
|
||||
{
|
||||
// Schedule idle event right now
|
||||
if (miliseconds == 0)
|
||||
{
|
||||
// We want to wakeup idle evnt but most likely this is call inside render cycle so we need to wait
|
||||
if (m_in_render)
|
||||
miliseconds = 33;
|
||||
else {
|
||||
m_dirty = true;
|
||||
wxWakeUpIdle();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Start timer
|
||||
int64_t now = timestamp_now();
|
||||
// Timer is not running
|
||||
if (! m_render_timer.IsRunning()) {
|
||||
m_extra_frame_requested_delayed = miliseconds;
|
||||
m_render_timer.StartOnce(miliseconds);
|
||||
m_render_timer_start = now;
|
||||
// Timer is running - restart only if new period is shorter than remaning period
|
||||
} else {
|
||||
const int64_t remaining_time = (m_render_timer_start + m_extra_frame_requested_delayed) - now;
|
||||
if (miliseconds < remaining_time) {
|
||||
if (miliseconds + 20 < remaining_time) {
|
||||
m_render_timer.Stop();
|
||||
m_extra_frame_requested_delayed = miliseconds;
|
||||
m_render_timer.StartOnce(miliseconds);
|
||||
|
|
|
@ -743,7 +743,8 @@ public:
|
|||
void msw_rescale();
|
||||
|
||||
void request_extra_frame() { m_extra_frame_requested = true; }
|
||||
void request_extra_frame_delayed(int miliseconds);
|
||||
|
||||
void schedule_extra_frame(int miliseconds);
|
||||
|
||||
int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); }
|
||||
void force_main_toolbar_left_action(int item_id) { m_main_toolbar.force_left_action(item_id, *this); }
|
||||
|
|
|
@ -1978,6 +1978,11 @@ wxNotebook* GUI_App::tab_panel() const
|
|||
return mainframe->m_tabpanel;
|
||||
}
|
||||
|
||||
NotificationManager* GUI_App::notification_manager()
|
||||
{
|
||||
return plater_->get_notification_manager();
|
||||
}
|
||||
|
||||
// extruders count from selected printer preset
|
||||
int GUI_App::extruders_cnt() const
|
||||
{
|
||||
|
|
|
@ -43,6 +43,7 @@ class ObjectSettings;
|
|||
class ObjectList;
|
||||
class ObjectLayers;
|
||||
class Plater;
|
||||
class NotificationManager;
|
||||
struct GUI_InitParams;
|
||||
|
||||
|
||||
|
@ -226,14 +227,14 @@ public:
|
|||
void MacOpenFiles(const wxArrayString &fileNames) override;
|
||||
#endif /* __APPLE */
|
||||
|
||||
Sidebar& sidebar();
|
||||
ObjectManipulation* obj_manipul();
|
||||
ObjectSettings* obj_settings();
|
||||
ObjectList* obj_list();
|
||||
ObjectLayers* obj_layers();
|
||||
Plater* plater();
|
||||
Model& model();
|
||||
|
||||
Sidebar& sidebar();
|
||||
ObjectManipulation* obj_manipul();
|
||||
ObjectSettings* obj_settings();
|
||||
ObjectList* obj_list();
|
||||
ObjectLayers* obj_layers();
|
||||
Plater* plater();
|
||||
Model& model();
|
||||
NotificationManager* notification_manager();
|
||||
|
||||
// Parameters extracted from the command line to be passed to GUI after initialization.
|
||||
const GUI_InitParams* init_params { nullptr };
|
||||
|
|
1027
src/slic3r/GUI/GUI_Factories.cpp
Normal file
1027
src/slic3r/GUI/GUI_Factories.cpp
Normal file
File diff suppressed because it is too large
Load diff
104
src/slic3r/GUI/GUI_Factories.hpp
Normal file
104
src/slic3r/GUI/GUI_Factories.hpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
#ifndef slic3r_GUI_Factories_hpp_
|
||||
#define slic3r_GUI_Factories_hpp_
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
#include <wx/bitmap.h>
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
class wxMenu;
|
||||
class wxMenuItem;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
enum class ModelVolumeType : int;
|
||||
|
||||
namespace GUI {
|
||||
|
||||
struct SettingsFactory
|
||||
{
|
||||
// category -> vector ( option )
|
||||
typedef std::map<std::string, std::vector<std::string>> Bundle;
|
||||
static std::map<std::string, std::string> CATEGORY_ICON;
|
||||
|
||||
static wxBitmap get_category_bitmap(const std::string& category_name);
|
||||
static Bundle get_bundle(const DynamicPrintConfig* config, bool is_object_settings);
|
||||
static std::vector<std::string> get_options(bool is_part);
|
||||
};
|
||||
|
||||
class MenuFactory
|
||||
{
|
||||
public:
|
||||
static std::vector<std::pair<std::string, std::string>> ADD_VOLUME_MENU_ITEMS;
|
||||
static std::vector<wxBitmap> get_volume_bitmaps();
|
||||
|
||||
MenuFactory();
|
||||
~MenuFactory() = default;
|
||||
|
||||
void init(wxWindow* parent);
|
||||
void update_object_menu();
|
||||
void msw_rescale();
|
||||
|
||||
wxMenu* default_menu();
|
||||
wxMenu* object_menu();
|
||||
wxMenu* sla_object_menu();
|
||||
wxMenu* part_menu();
|
||||
wxMenu* instance_menu();
|
||||
wxMenu* layer_menu();
|
||||
wxMenu* multi_selection_menu();
|
||||
|
||||
private:
|
||||
enum MenuType {
|
||||
mtObjectFFF = 0,
|
||||
mtObjectSLA,
|
||||
mtCount
|
||||
};
|
||||
|
||||
wxWindow* m_parent {nullptr};
|
||||
|
||||
MenuWithSeparators m_object_menu;
|
||||
MenuWithSeparators m_part_menu;
|
||||
MenuWithSeparators m_sla_object_menu;
|
||||
MenuWithSeparators m_default_menu;
|
||||
MenuWithSeparators m_instance_menu;
|
||||
|
||||
// Removed/Prepended Items according to the view mode
|
||||
std::array<wxMenuItem*, mtCount> items_increase;
|
||||
std::array<wxMenuItem*, mtCount> items_decrease;
|
||||
std::array<wxMenuItem*, mtCount> items_set_number_of_copies;
|
||||
|
||||
void create_default_menu();
|
||||
void create_common_object_menu(wxMenu *menu);
|
||||
void create_object_menu();
|
||||
void create_sla_object_menu();
|
||||
void create_part_menu();
|
||||
|
||||
wxMenu* append_submenu_add_generic(wxMenu* menu, ModelVolumeType type);
|
||||
void append_menu_items_add_volume(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_layers_editing(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_settings(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_change_type(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_printable(wxMenu* menu);
|
||||
void append_menu_items_osx(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
|
||||
void append_menu_item_export_stl(wxMenu* menu);
|
||||
void append_menu_item_reload_from_disk(wxMenu* menu);
|
||||
void append_menu_item_change_extruder(wxMenu* menu);
|
||||
void append_menu_item_delete(wxMenu* menu);
|
||||
void append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu);
|
||||
void append_menu_items_convert_unit(wxMenu* menu, int insert_pos = 1); // Add "Conver/Revert..." menu items (from/to inches/meters) after "Reload From Disk"
|
||||
void append_menu_item_merge_to_multipart_object(wxMenu *menu);
|
||||
// void append_menu_item_merge_to_single_object(wxMenu *menu);
|
||||
void append_menu_items_mirror(wxMenu *menu);
|
||||
void append_menu_items_instance_manipulation(wxMenu *menu);
|
||||
void update_menu_items_instance_manipulation(MenuType type);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif //slic3r_GUI_Factories_hpp_
|
|
@ -9,6 +9,7 @@
|
|||
#include "slic3r/GUI/format.hpp"
|
||||
#include "slic3r/GUI/MainFrame.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/Utils/Platform.hpp"
|
||||
|
||||
// To show a message box if GUI initialization ends up with an exception thrown.
|
||||
#include <wx/msgdlg.h>
|
||||
|
@ -36,6 +37,8 @@ int GUI_Run(GUI_InitParams ¶ms)
|
|||
signal(SIGCHLD, SIG_DFL);
|
||||
#endif // __APPLE__
|
||||
|
||||
detect_platform();
|
||||
|
||||
try {
|
||||
GUI::GUI_App* gui = new GUI::GUI_App(params.start_as_gcodeviewer ? GUI::GUI_App::EAppMode::GCodeViewer : GUI::GUI_App::EAppMode::Editor);
|
||||
if (gui->get_app_mode() != GUI::GUI_App::EAppMode::GCodeViewer) {
|
||||
|
|
|
@ -260,16 +260,15 @@ void ObjectLayers::msw_rescale()
|
|||
editor->msw_rescale();
|
||||
}
|
||||
|
||||
const std::vector<size_t> btns = {2, 3}; // del_btn, add_btn
|
||||
for (auto btn : btns)
|
||||
{
|
||||
wxSizerItem* b_item = item->GetSizer()->GetItem(btn);
|
||||
if (b_item->IsWindow()) {
|
||||
auto button = dynamic_cast<PlusMinusButton*>(b_item->GetWindow());
|
||||
if (button != nullptr)
|
||||
button->msw_rescale();
|
||||
}
|
||||
}
|
||||
if (item->GetSizer()->GetItemCount() > 2) // if there are Add/Del buttons
|
||||
for (size_t btn : {2, 3}) { // del_btn, add_btn
|
||||
wxSizerItem* b_item = item->GetSizer()->GetItem(btn);
|
||||
if (b_item->IsWindow()) {
|
||||
auto button = dynamic_cast<PlusMinusButton*>(b_item->GetWindow());
|
||||
if (button != nullptr)
|
||||
button->msw_rescale();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_grid_sizer->Layout();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -31,18 +31,11 @@ class TriangleMesh;
|
|||
enum class ModelVolumeType : int;
|
||||
|
||||
// FIXME: broken build on mac os because of this is missing:
|
||||
typedef std::vector<std::string> t_config_option_keys;
|
||||
|
||||
typedef std::map<std::string, std::vector<std::string>> SettingsBundle;
|
||||
|
||||
// category -> vector ( option ; label )
|
||||
typedef std::map< std::string, std::vector< std::pair<std::string, std::string> > > settings_menu_hierarchy;
|
||||
|
||||
typedef std::vector<ModelVolume*> ModelVolumePtrs;
|
||||
|
||||
typedef double coordf_t;
|
||||
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
||||
typedef std::map<t_layer_height_range, ModelConfig> t_layer_config_ranges;
|
||||
typedef std::vector<std::string> t_config_option_keys;
|
||||
typedef std::vector<ModelVolume*> ModelVolumePtrs;
|
||||
typedef double coordf_t;
|
||||
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
||||
typedef std::map<t_layer_height_range, ModelConfig> t_layer_config_ranges;
|
||||
|
||||
namespace GUI {
|
||||
|
||||
|
@ -106,7 +99,7 @@ public:
|
|||
|
||||
private:
|
||||
SELECTION_MODE m_selection_mode {smUndef};
|
||||
int m_selected_layers_range_idx;
|
||||
int m_selected_layers_range_idx {-1};
|
||||
|
||||
Clipboard m_clipboard;
|
||||
|
||||
|
@ -147,23 +140,6 @@ private:
|
|||
} m_dragged_data;
|
||||
|
||||
wxBoxSizer *m_sizer {nullptr};
|
||||
wxWindow *m_parent {nullptr};
|
||||
|
||||
ScalableBitmap m_bmp_modifiermesh;
|
||||
ScalableBitmap m_bmp_solidmesh;
|
||||
ScalableBitmap m_bmp_support_enforcer;
|
||||
ScalableBitmap m_bmp_support_blocker;
|
||||
ScalableBitmap m_bmp_manifold_warning;
|
||||
ScalableBitmap m_bmp_cog;
|
||||
|
||||
MenuWithSeparators m_menu_object;
|
||||
MenuWithSeparators m_menu_part;
|
||||
MenuWithSeparators m_menu_sla_object;
|
||||
MenuWithSeparators m_menu_instance;
|
||||
MenuWithSeparators m_menu_layer;
|
||||
MenuWithSeparators m_menu_default;
|
||||
wxMenuItem* m_menu_item_settings { nullptr };
|
||||
wxMenuItem* m_menu_item_split_instances { nullptr };
|
||||
|
||||
ObjectDataViewModel *m_objects_model{ nullptr };
|
||||
ModelConfig *m_config {nullptr};
|
||||
|
@ -185,7 +161,6 @@ private:
|
|||
// update_settings_items - updating canvas selection is undesirable,
|
||||
// because it would turn off the gizmos (mainly a problem for the SLA gizmo)
|
||||
|
||||
int m_selected_row = 0;
|
||||
wxDataViewItem m_last_selected_item {nullptr};
|
||||
#ifdef __WXMSW__
|
||||
// Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected.
|
||||
|
@ -193,8 +168,8 @@ private:
|
|||
#endif /* __MSW__ */
|
||||
|
||||
#if 0
|
||||
SettingsBundle m_freq_settings_fff;
|
||||
SettingsBundle m_freq_settings_sla;
|
||||
SettingsFactory::Bundle m_freq_settings_fff;
|
||||
SettingsFactory::Bundle m_freq_settings_sla;
|
||||
#endif
|
||||
|
||||
size_t m_items_count { size_t(-1) };
|
||||
|
@ -212,8 +187,6 @@ public:
|
|||
void set_min_height();
|
||||
void update_min_height();
|
||||
|
||||
std::map<std::string, wxBitmap> CATEGORY_ICON;
|
||||
|
||||
ObjectDataViewModel* GetModel() const { return m_objects_model; }
|
||||
ModelConfig* config() const { return m_config; }
|
||||
std::vector<ModelObject*>* objects() const { return m_objects; }
|
||||
|
@ -221,7 +194,6 @@ public:
|
|||
ModelObject* object(const int obj_idx) const ;
|
||||
|
||||
void create_objects_ctrl();
|
||||
void create_popup_menus();
|
||||
void update_objects_list_extruder_column(size_t extruders_count);
|
||||
void update_extruder_colors();
|
||||
// show/hide "Extruder" column for Objects List
|
||||
|
@ -232,9 +204,6 @@ public:
|
|||
void update_name_in_model(const wxDataViewItem& item) const;
|
||||
void update_extruder_values_for_items(const size_t max_extruder);
|
||||
|
||||
void init_icons();
|
||||
void msw_rescale_icons();
|
||||
|
||||
// Get obj_idx and vol_idx values for the selected (by default) or an adjusted item
|
||||
void get_selected_item_indexes(int& obj_idx, int& vol_idx, const wxDataViewItem& item = wxDataViewItem(0));
|
||||
void get_selection_indexes(std::vector<int>& obj_idxs, std::vector<int>& vol_idxs);
|
||||
|
@ -264,39 +233,11 @@ public:
|
|||
void increase_instances();
|
||||
void decrease_instances();
|
||||
|
||||
void get_settings_choice(const wxString& category_name);
|
||||
void get_freq_settings_choice(const wxString& bundle_name);
|
||||
void add_category_to_settings_from_selection(const std::vector< std::pair<std::string, bool> >& category_options, wxDataViewItem item);
|
||||
void add_category_to_settings_from_frequent(const std::vector<std::string>& category_options, wxDataViewItem item);
|
||||
void show_settings(const wxDataViewItem settings_item);
|
||||
bool is_instance_or_object_selected();
|
||||
|
||||
wxMenu* append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type);
|
||||
void append_menu_items_add_volume(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_split(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_layers_editing(wxMenu* menu, wxWindow* parent);
|
||||
wxMenuItem* append_menu_item_settings(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_change_type(wxMenu* menu, wxWindow* parent = nullptr);
|
||||
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent);
|
||||
wxMenuItem* append_menu_item_printable(wxMenu* menu, wxWindow* parent);
|
||||
void append_menu_items_osx(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
|
||||
void append_menu_item_export_stl(wxMenu* menu) const;
|
||||
void append_menu_item_reload_from_disk(wxMenu* menu) const;
|
||||
void append_menu_item_change_extruder(wxMenu* menu);
|
||||
void append_menu_item_delete(wxMenu* menu);
|
||||
void append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu);
|
||||
void append_menu_items_convert_unit(wxMenu* menu, int insert_pos = 1); // Add "Conver/Revert..." menu items (from/to inches/meters) after "Reload From Disk"
|
||||
void append_menu_item_merge_to_multipart_object(wxMenu *menu);
|
||||
void append_menu_item_merge_to_single_object(wxMenu *menu);
|
||||
void create_object_popupmenu(wxMenu *menu);
|
||||
void create_sla_object_popupmenu(wxMenu*menu);
|
||||
void create_part_popupmenu(wxMenu*menu);
|
||||
void create_instance_popupmenu(wxMenu*menu);
|
||||
void create_default_popupmenu(wxMenu *menu);
|
||||
wxMenu* create_settings_popupmenu(wxMenu *parent_menu);
|
||||
void create_freq_settings_popupmenu(wxMenu *parent_menu, const bool is_object_settings = true);
|
||||
|
||||
void update_opt_keys(t_config_option_keys& t_optopt_keys, const bool is_object);
|
||||
|
||||
void load_subobject(ModelVolumeType type);
|
||||
void load_part(ModelObject* model_object, std::vector<std::pair<wxString, bool>> &volumes_info, ModelVolumeType type);
|
||||
void load_generic_subobject(const std::string& type_name, const ModelVolumeType type);
|
||||
|
@ -318,7 +259,7 @@ public:
|
|||
|
||||
DynamicPrintConfig get_default_layer_config(const int obj_idx);
|
||||
bool get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume);
|
||||
bool is_splittable();
|
||||
bool is_splittable(bool to_objects);
|
||||
bool selected_instances_of_same_object();
|
||||
bool can_split_instances();
|
||||
bool can_merge_to_multipart_object() const;
|
||||
|
@ -328,7 +269,6 @@ public:
|
|||
wxBoxSizer* get_sizer() {return m_sizer;}
|
||||
int get_selected_obj_idx() const;
|
||||
ModelConfig& get_item_config(const wxDataViewItem& item) const;
|
||||
SettingsBundle get_item_settings_bundle(const DynamicPrintConfig* config, const bool is_object_settings);
|
||||
|
||||
void changed_object(const int obj_idx = -1) const;
|
||||
void part_selection_changed();
|
||||
|
@ -404,11 +344,9 @@ public:
|
|||
void change_part_type();
|
||||
|
||||
void last_volume_is_deleted(const int obj_idx);
|
||||
void update_settings_items();
|
||||
void update_and_show_object_settings_item();
|
||||
void update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections);
|
||||
void update_object_list_by_printer_technology();
|
||||
void update_object_menu();
|
||||
|
||||
void instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idx);
|
||||
void instances_to_separated_objects(const int obj_idx);
|
||||
|
@ -433,7 +371,7 @@ public:
|
|||
void update_printable_state(int obj_idx, int instance_idx);
|
||||
void toggle_printable_state(wxDataViewItem item);
|
||||
|
||||
void show_multi_selection_menu();
|
||||
void set_extruder_for_selected_items(const int extruder) const ;
|
||||
|
||||
private:
|
||||
#ifdef __WXOSX__
|
||||
|
@ -454,11 +392,6 @@ private:
|
|||
#endif /* __WXMSW__ */
|
||||
void OnEditingDone(wxDataViewEvent &event);
|
||||
void extruder_selection();
|
||||
void set_extruder_for_selected_items(const int extruder) const ;
|
||||
|
||||
std::vector<std::string> get_options(const bool is_part);
|
||||
const std::vector<std::string>& get_options_for_bundle(const wxString& bundle_name);
|
||||
void get_options_menu(settings_menu_hierarchy& settings_menu, const bool is_part);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "GUI_ObjectSettings.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "GUI_Factories.hpp"
|
||||
|
||||
#include "OptionsGroup.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
|
@ -83,7 +84,7 @@ bool ObjectSettings::update_settings_list()
|
|||
return false;
|
||||
|
||||
const bool is_object_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itObject;
|
||||
SettingsBundle cat_options = objects_ctrl->get_item_settings_bundle(&config->get(), is_object_settings);
|
||||
SettingsFactory::Bundle cat_options = SettingsFactory::get_bundle(&config->get(), is_object_settings);
|
||||
|
||||
if (!cat_options.empty())
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Layer.hpp"
|
||||
#include "GUI_Preview.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "GUI.hpp"
|
||||
|
@ -24,6 +25,7 @@
|
|||
// this include must follow the wxWidgets ones or it won't compile on Windows -> see http://trac.wxwidgets.org/ticket/2421
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include "NotificationManager.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
@ -639,6 +641,53 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee
|
|||
else
|
||||
m_layers_slider->SetLayersTimes(m_gcode_result->time_statistics.modes.front().layers_times);
|
||||
|
||||
// Suggest the auto color change, if model looks like sign
|
||||
if (ticks_info_from_model.gcodes.empty())
|
||||
{
|
||||
NotificationManager* notif_mngr = wxGetApp().plater()->get_notification_manager();
|
||||
notif_mngr->close_notification_of_type(NotificationType::SignDetected);
|
||||
|
||||
const Print& print = wxGetApp().plater()->fff_print();
|
||||
double delta_area = scale_(scale_(25)); // equal to 25 mm2
|
||||
|
||||
//bool is_possible_auto_color_change = false;
|
||||
for (auto object : print.objects()) {
|
||||
double height = object->height();
|
||||
coord_t longer_side = std::max(object->size().x(), object->size().y());
|
||||
if (height / longer_side > 0.3)
|
||||
continue;
|
||||
|
||||
const ExPolygons& bottom = object->get_layer(0)->lslices;
|
||||
if (bottom.size() > 1 || !bottom[0].holes.empty())
|
||||
continue;
|
||||
|
||||
double bottom_area = area(bottom);
|
||||
int i;
|
||||
for (i = 1; i < int(0.3 * object->layers().size()); i++)
|
||||
if (area(object->get_layer(1)->lslices) != bottom_area)
|
||||
break;
|
||||
if (i < int(0.3 * object->layers().size()))
|
||||
continue;
|
||||
|
||||
double top_area = area(object->get_layer(int(object->layers().size()) - 1)->lslices);
|
||||
if( bottom_area - top_area > delta_area) {
|
||||
notif_mngr->push_notification(
|
||||
NotificationType::SignDetected, NotificationManager::NotificationLevel::RegularNotification,
|
||||
_u8L("NOTE:") + "\n" + _u8L("Sliced object looks like the sign") + "\n",
|
||||
_u8L("Apply auto color change to print"),
|
||||
[this, notif_mngr](wxEvtHandler*) {
|
||||
notif_mngr->close_notification_of_type(NotificationType::SignDetected);
|
||||
m_layers_slider->auto_color_change();
|
||||
return true;
|
||||
});
|
||||
|
||||
notif_mngr->set_in_preview(true);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_layers_slider_sizer->Show((size_t)0);
|
||||
Layout();
|
||||
}
|
||||
|
|
|
@ -200,12 +200,20 @@ void HollowedMesh::on_update()
|
|||
if (print_object->is_step_done(slaposDrillHoles) && print_object->has_mesh(slaposDrillHoles)) {
|
||||
size_t timestamp = print_object->step_state_with_timestamp(slaposDrillHoles).timestamp;
|
||||
if (timestamp > m_old_hollowing_timestamp) {
|
||||
const TriangleMesh& backend_mesh = print_object->get_mesh_to_print();
|
||||
const TriangleMesh& backend_mesh = print_object->get_mesh_to_slice();
|
||||
if (! backend_mesh.empty()) {
|
||||
m_hollowed_mesh_transformed.reset(new TriangleMesh(backend_mesh));
|
||||
Transform3d trafo_inv = canvas->sla_print()->sla_trafo(*mo).inverse();
|
||||
m_hollowed_mesh_transformed->transform(trafo_inv);
|
||||
m_old_hollowing_timestamp = timestamp;
|
||||
|
||||
const TriangleMesh &interior = print_object->hollowed_interior_mesh();
|
||||
if (!interior.empty()) {
|
||||
m_hollowed_interior_transformed = std::make_unique<TriangleMesh>(interior);
|
||||
m_hollowed_interior_transformed->repaired = false;
|
||||
m_hollowed_interior_transformed->repair(true);
|
||||
m_hollowed_interior_transformed->transform(trafo_inv);
|
||||
}
|
||||
}
|
||||
else
|
||||
m_hollowed_mesh_transformed.reset(nullptr);
|
||||
|
@ -230,6 +238,10 @@ const TriangleMesh* HollowedMesh::get_hollowed_mesh() const
|
|||
return m_hollowed_mesh_transformed.get();
|
||||
}
|
||||
|
||||
const TriangleMesh* HollowedMesh::get_hollowed_interior() const
|
||||
{
|
||||
return m_hollowed_interior_transformed.get();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -306,6 +318,10 @@ void ObjectClipper::on_update()
|
|||
m_clippers.back()->set_mesh(*mesh);
|
||||
}
|
||||
m_old_meshes = meshes;
|
||||
|
||||
if (has_hollowed)
|
||||
m_clippers.front()->set_negative_mesh(*get_pool()->hollowed_mesh()->get_hollowed_interior());
|
||||
|
||||
m_active_inst_bb_radius =
|
||||
mo->instance_bounding_box(get_pool()->selection_info()->get_active_instance()).radius();
|
||||
//if (has_hollowed && m_clp_ratio != 0.)
|
||||
|
|
|
@ -199,6 +199,7 @@ public:
|
|||
#endif // NDEBUG
|
||||
|
||||
const TriangleMesh* get_hollowed_mesh() const;
|
||||
const TriangleMesh* get_hollowed_interior() const;
|
||||
|
||||
protected:
|
||||
void on_update() override;
|
||||
|
@ -206,6 +207,7 @@ protected:
|
|||
|
||||
private:
|
||||
std::unique_ptr<TriangleMesh> m_hollowed_mesh_transformed;
|
||||
std::unique_ptr<TriangleMesh> m_hollowed_interior_transformed;
|
||||
size_t m_old_hollowing_timestamp = 0;
|
||||
int m_print_object_idx = -1;
|
||||
int m_print_objects_count = 0;
|
||||
|
|
|
@ -51,7 +51,9 @@ static const std::map<const char, std::string> font_icons_large = {
|
|||
{ImGui::EjectButton , "notification_eject_sd" },
|
||||
{ImGui::EjectHoverButton , "notification_eject_sd_hover" },
|
||||
{ImGui::WarningMarker , "notification_warning" },
|
||||
{ImGui::ErrorMarker , "notification_error" }
|
||||
{ImGui::ErrorMarker , "notification_error" },
|
||||
{ImGui::CancelButton , "notification_cancel" },
|
||||
{ImGui::CancelHoverButton , "notification_cancel_hover" },
|
||||
};
|
||||
|
||||
const ImVec4 ImGuiWrapper::COL_GREY_DARK = { 0.333f, 0.333f, 0.333f, 1.0f };
|
||||
|
|
|
@ -562,8 +562,6 @@ void MainFrame::init_tabpanel()
|
|||
|
||||
wxGetApp().plater_ = m_plater;
|
||||
|
||||
wxGetApp().obj_list()->create_popup_menus();
|
||||
|
||||
if (wxGetApp().is_editor())
|
||||
create_preset_tabs();
|
||||
|
||||
|
@ -1219,6 +1217,9 @@ void MainFrame::init_menubar_as_editor()
|
|||
append_menu_check_item(viewMenu, wxID_ANY, _L("&Collapse sidebar") + sep + "Shift+" + sep_space + "Tab", _L("Collapse sidebar"),
|
||||
[this](wxCommandEvent&) { m_plater->collapse_sidebar(!m_plater->is_sidebar_collapsed()); }, this,
|
||||
[]() { return true; }, [this]() { return m_plater->is_sidebar_collapsed(); }, this);
|
||||
append_menu_check_item(viewMenu, wxID_ANY, _L("&Full screen") + "\t" + "F11", _L("Full screen"),
|
||||
[this](wxCommandEvent&) { this->ShowFullScreen(!this->IsFullScreen()); }, this,
|
||||
[]() { return true; }, [this]() { return this->IsFullScreen(); }, this);
|
||||
}
|
||||
|
||||
// Help menu
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "libslic3r/Tesselate.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
|
||||
#include "slic3r/GUI/Camera.hpp"
|
||||
|
||||
|
@ -31,6 +32,15 @@ void MeshClipper::set_mesh(const TriangleMesh& mesh)
|
|||
}
|
||||
}
|
||||
|
||||
void MeshClipper::set_negative_mesh(const TriangleMesh& mesh)
|
||||
{
|
||||
if (m_negative_mesh != &mesh) {
|
||||
m_negative_mesh = &mesh;
|
||||
m_triangles_valid = false;
|
||||
m_triangles2d.resize(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MeshClipper::set_transformation(const Geometry::Transformation& trafo)
|
||||
|
@ -74,6 +84,15 @@ void MeshClipper::recalculate_triangles()
|
|||
std::vector<ExPolygons> list_of_expolys;
|
||||
m_tms->set_up_direction(up.cast<float>());
|
||||
m_tms->slice(std::vector<float>{height_mesh}, SlicingMode::Regular, 0.f, &list_of_expolys, [](){});
|
||||
|
||||
if (m_negative_mesh && !m_negative_mesh->empty()) {
|
||||
TriangleMeshSlicer negative_tms{m_negative_mesh};
|
||||
negative_tms.set_up_direction(up.cast<float>());
|
||||
|
||||
std::vector<ExPolygons> neg_polys;
|
||||
negative_tms.slice(std::vector<float>{height_mesh}, SlicingMode::Regular, 0.f, &neg_polys, [](){});
|
||||
list_of_expolys.front() = diff_ex(list_of_expolys.front(), neg_polys.front());
|
||||
}
|
||||
m_triangles2d = triangulate_expolygons_2f(list_of_expolys[0], m_trafo.get_matrix().matrix().determinant() < 0.);
|
||||
|
||||
// Rotate the cut into world coords:
|
||||
|
|
|
@ -78,6 +78,8 @@ public:
|
|||
// must make sure that it stays valid.
|
||||
void set_mesh(const TriangleMesh& mesh);
|
||||
|
||||
void set_negative_mesh(const TriangleMesh &mesh);
|
||||
|
||||
// Inform the MeshClipper about the transformation that transforms the mesh
|
||||
// into world coordinates.
|
||||
void set_transformation(const Geometry::Transformation& trafo);
|
||||
|
@ -91,6 +93,7 @@ private:
|
|||
|
||||
Geometry::Transformation m_trafo;
|
||||
const TriangleMesh* m_mesh = nullptr;
|
||||
const TriangleMesh* m_negative_mesh = nullptr;
|
||||
ClippingPlane m_plane;
|
||||
std::vector<Vec2f> m_triangles2d;
|
||||
GLIndexedVertexArray m_vertex_array;
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
#include "NotificationManager.hpp"
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "Plater.hpp"
|
||||
#include "GLCanvas3D.hpp"
|
||||
#include "ImGuiWrapper.hpp"
|
||||
|
||||
#include "GUI.hpp"
|
||||
#include "ImGuiWrapper.hpp"
|
||||
#include "PrintHostDialogs.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
@ -22,9 +20,6 @@ static constexpr float SPACE_RIGHT_PANEL = 10.0f;
|
|||
static constexpr float FADING_OUT_DURATION = 2.0f;
|
||||
// Time in Miliseconds after next render when fading out is requested
|
||||
static constexpr int FADING_OUT_TIMEOUT = 100;
|
||||
// If timeout is changed to higher than 1 second, substract_time call should be revorked
|
||||
//static constexpr int MAX_TIMEOUT_MILISECONDS = 1000;
|
||||
//static constexpr int MAX_TIMEOUT_SECONDS = 1;
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
@ -131,35 +126,35 @@ void NotificationManager::NotificationIDProvider::release_id(int) {}
|
|||
NotificationManager::PopNotification::PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler) :
|
||||
m_data (n)
|
||||
, m_id_provider (id_provider)
|
||||
, m_remaining_time (n.duration)
|
||||
, m_last_remaining_time (n.duration)
|
||||
, m_counting_down (n.duration != 0)
|
||||
, m_text1 (n.text1)
|
||||
, m_hypertext (n.hypertext)
|
||||
, m_text2 (n.text2)
|
||||
, m_evt_handler (evt_handler)
|
||||
, m_notification_start (GLCanvas3D::timestamp_now())
|
||||
{
|
||||
//init();
|
||||
}
|
||||
{}
|
||||
|
||||
void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width)
|
||||
{
|
||||
if (!m_initialized)
|
||||
|
||||
if (m_state == EState::Unknown)
|
||||
init();
|
||||
|
||||
if (m_hidden) {
|
||||
if (m_state == EState::Hidden) {
|
||||
m_top_y = initial_y - GAP_WIDTH;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_fading_out)
|
||||
m_last_render_fading = GLCanvas3D::timestamp_now();
|
||||
if (m_state == EState::ClosePending || m_state == EState::Finished)
|
||||
{
|
||||
m_state = EState::Finished;
|
||||
return;
|
||||
}
|
||||
|
||||
Size cnv_size = canvas.get_canvas_size();
|
||||
Size cnv_size = canvas.get_canvas_size();
|
||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||
ImVec2 mouse_pos = ImGui::GetMousePos();
|
||||
float right_gap = SPACE_RIGHT_PANEL + (move_from_overlay ? overlay_width + m_line_height * 5 : 0);
|
||||
ImVec2 mouse_pos = ImGui::GetMousePos();
|
||||
float right_gap = SPACE_RIGHT_PANEL + (move_from_overlay ? overlay_width + m_line_height * 5 : 0);
|
||||
bool fading_pop = false;
|
||||
|
||||
if (m_line_height != ImGui::CalcTextSize("A").y)
|
||||
init();
|
||||
|
@ -174,54 +169,46 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init
|
|||
imgui.set_next_window_size(m_window_width, m_window_height, ImGuiCond_Always);
|
||||
|
||||
// find if hovered
|
||||
m_hovered = false;
|
||||
if (m_state == EState::Hovered)
|
||||
m_state = EState::Shown;
|
||||
|
||||
if (mouse_pos.x < win_pos.x && mouse_pos.x > win_pos.x - m_window_width && mouse_pos.y > win_pos.y && mouse_pos.y < win_pos.y + m_window_height) {
|
||||
ImGui::SetNextWindowFocus();
|
||||
m_hovered = true;
|
||||
m_state = EState::Hovered;
|
||||
}
|
||||
|
||||
|
||||
// color change based on fading out
|
||||
bool fading_pop = false;
|
||||
if (m_fading_out) {
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text), m_fading_out, m_current_fade_opacity);
|
||||
if (m_state == EState::FadingOut) {
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), true, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text), true, m_current_fade_opacity);
|
||||
fading_pop = true;
|
||||
}
|
||||
|
||||
|
||||
// background color
|
||||
if (m_is_gray) {
|
||||
ImVec4 backcolor(0.7f, 0.7f, 0.7f, 0.5f);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
}
|
||||
else if (m_data.level == NotificationLevel::ErrorNotification) {
|
||||
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
|
||||
backcolor.x += 0.3f;
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
}
|
||||
else if (m_data.level == NotificationLevel::WarningNotification) {
|
||||
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
|
||||
backcolor.x += 0.3f;
|
||||
backcolor.y += 0.15f;
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
}
|
||||
|
||||
// name of window - probably indentifies window and is shown so last_end add whitespaces according to id
|
||||
|
||||
// name of window indentifies window - has to be unique string
|
||||
if (m_id == 0)
|
||||
m_id = m_id_provider.allocate_id();
|
||||
std::string name = "!!Ntfctn" + std::to_string(m_id);
|
||||
|
||||
if (imgui.begin(name, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar)) {
|
||||
ImVec2 win_size = ImGui::GetWindowSize();
|
||||
|
||||
//FIXME: dont forget to us this for texts
|
||||
//GUI::format(_utf8(L()));
|
||||
|
||||
/*
|
||||
//countdown numbers
|
||||
ImGui::SetCursorPosX(15);
|
||||
ImGui::SetCursorPosY(15);
|
||||
imgui.text(std::to_string(m_remaining_time).c_str());
|
||||
*/
|
||||
|
||||
render_left_sign(imgui);
|
||||
render_text(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y);
|
||||
render_close_button(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y);
|
||||
|
@ -253,9 +240,14 @@ void NotificationManager::PopNotification::count_spaces()
|
|||
m_window_width_offset = m_left_indentation + m_line_height * 3.f;
|
||||
m_window_width = m_line_height * 25;
|
||||
}
|
||||
|
||||
void NotificationManager::PopNotification::init()
|
||||
{
|
||||
std::string text = m_text1 + " " + m_hypertext;
|
||||
// Do not init closing notification
|
||||
if (is_finished())
|
||||
return;
|
||||
|
||||
std::string text = m_text1 + " " + m_hypertext;
|
||||
size_t last_end = 0;
|
||||
m_lines_count = 0;
|
||||
|
||||
|
@ -306,7 +298,9 @@ void NotificationManager::PopNotification::init()
|
|||
}
|
||||
if (m_lines_count == 3)
|
||||
m_multiline = true;
|
||||
m_initialized = true;
|
||||
m_notification_start = GLCanvas3D::timestamp_now();
|
||||
//if (m_state != EState::Hidden)
|
||||
// m_state = EState::Shown;
|
||||
}
|
||||
void NotificationManager::PopNotification::set_next_window_size(ImGuiWrapper& imgui)
|
||||
{
|
||||
|
@ -375,12 +369,14 @@ void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, cons
|
|||
ImGui::SetCursorPosY(win_size.y / 2 - win_size.y / 6 - m_line_height / 2);
|
||||
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
|
||||
// line2
|
||||
std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0));
|
||||
cursor_y = win_size.y / 2 + win_size.y / 6 - m_line_height / 2;
|
||||
ImGui::SetCursorPosX(x_offset);
|
||||
ImGui::SetCursorPosY(cursor_y);
|
||||
imgui.text(line.c_str());
|
||||
cursor_x = x_offset + ImGui::CalcTextSize(line.c_str()).x;
|
||||
if (m_text1.length() > m_endlines[0]) {
|
||||
std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0));
|
||||
cursor_y = win_size.y / 2 + win_size.y / 6 - m_line_height / 2;
|
||||
ImGui::SetCursorPosX(x_offset);
|
||||
ImGui::SetCursorPosY(cursor_y);
|
||||
imgui.text(line.c_str());
|
||||
cursor_x = x_offset + ImGui::CalcTextSize(line.c_str()).x;
|
||||
}
|
||||
} else {
|
||||
ImGui::SetCursorPosX(x_offset);
|
||||
ImGui::SetCursorPosY(cursor_y);
|
||||
|
@ -423,8 +419,8 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui,
|
|||
m_multiline = true;
|
||||
set_next_window_size(imgui);
|
||||
}
|
||||
else {
|
||||
m_close_pending = on_text_click();
|
||||
else if (on_text_click()) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
|
@ -432,12 +428,12 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui,
|
|||
ImGui::PopStyleColor();
|
||||
|
||||
//hover color
|
||||
ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f);//ImGui::GetStyleColorVec4(ImGuiCol_Button);
|
||||
ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f);
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly))
|
||||
orange_color.y += 0.2f;
|
||||
|
||||
//text
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, orange_color, m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, orange_color, m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
ImGui::SetCursorPosX(text_x);
|
||||
ImGui::SetCursorPosY(text_y);
|
||||
imgui.text(text.c_str());
|
||||
|
@ -448,7 +444,7 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui,
|
|||
lineEnd.y -= 2;
|
||||
ImVec2 lineStart = lineEnd;
|
||||
lineStart.x = ImGui::GetItemRectMin().x;
|
||||
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (int)(orange_color.w * 255.f * (m_fading_out ? m_current_fade_opacity : 1.f))));
|
||||
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (int)(orange_color.w * 255.f * (m_state == EState::FadingOut ? m_current_fade_opacity : 1.f))));
|
||||
|
||||
}
|
||||
|
||||
|
@ -458,12 +454,11 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img
|
|||
ImVec2 win_pos(win_pos_x, win_pos_y);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f));
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f));
|
||||
|
||||
|
||||
//button - if part if treggered
|
||||
std::string button_text;
|
||||
button_text = ImGui::CloseNotifButton;
|
||||
|
||||
|
@ -479,7 +474,7 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img
|
|||
ImGui::SetCursorPosY(win_size.y / 2 - button_size.y);
|
||||
if (imgui.button(button_text.c_str(), button_size.x, button_size.y))
|
||||
{
|
||||
m_close_pending = true;
|
||||
close();
|
||||
}
|
||||
|
||||
//invisible large button
|
||||
|
@ -487,7 +482,7 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img
|
|||
ImGui::SetCursorPosY(0);
|
||||
if (imgui.button(" ", m_line_height * 2.125, win_size.y - ( m_minimize_b_visible ? 2 * m_line_height : 0)))
|
||||
{
|
||||
m_close_pending = true;
|
||||
close();
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
|
@ -510,9 +505,9 @@ void NotificationManager::PopNotification::render_minimize_button(ImGuiWrapper&
|
|||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f));
|
||||
Notifications_Internal::push_style_color(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
|
||||
|
||||
//button - if part if treggered
|
||||
|
@ -564,71 +559,62 @@ bool NotificationManager::PopNotification::compare_text(const std::string& text)
|
|||
return false;
|
||||
}
|
||||
|
||||
void NotificationManager::PopNotification::update_state()
|
||||
bool NotificationManager::PopNotification::update_state(bool paused, const int64_t delta)
|
||||
{
|
||||
if (!m_initialized)
|
||||
init();
|
||||
|
||||
m_next_render = std::numeric_limits<int64_t>::max();
|
||||
|
||||
if (m_hidden) {
|
||||
m_state = EState::Hidden;
|
||||
return;
|
||||
if (m_state == EState::Unknown) {
|
||||
init();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_state == EState::Hidden) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t now = GLCanvas3D::timestamp_now();
|
||||
|
||||
if (m_hovered) {
|
||||
// reset fading
|
||||
m_fading_out = false;
|
||||
// reset timers - hovered state is set in render
|
||||
if (m_state == EState::Hovered) {
|
||||
m_current_fade_opacity = 1.0f;
|
||||
m_remaining_time = m_data.duration;
|
||||
m_notification_start = now;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (m_counting_down) {
|
||||
// Timers when not fading
|
||||
} else if (m_state != EState::FadingOut && m_data.duration != 0 && !paused) {
|
||||
int64_t up_time = now - m_notification_start;
|
||||
if (up_time >= m_data.duration * 1000) {
|
||||
m_state = EState::FadingOut;
|
||||
m_fading_start = now;
|
||||
} else {
|
||||
m_next_render = m_data.duration * 1000 - up_time;
|
||||
}
|
||||
}
|
||||
// Timers when fading
|
||||
if (m_state == EState::FadingOut && !paused) {
|
||||
int64_t curr_time = now - m_fading_start;
|
||||
int64_t next_render = FADING_OUT_TIMEOUT - delta;
|
||||
m_current_fade_opacity = std::clamp(1.0f - 0.001f * static_cast<float>(curr_time) / FADING_OUT_DURATION, 0.0f, 1.0f);
|
||||
if (m_current_fade_opacity <= 0.0f) {
|
||||
m_state = EState::Finished;
|
||||
return true;
|
||||
} else if (next_render <= 20) {
|
||||
m_next_render = FADING_OUT_TIMEOUT;
|
||||
return true;
|
||||
} else {
|
||||
m_next_render = next_render;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_fading_out && m_current_fade_opacity <= 0.0f)
|
||||
m_finished = true;
|
||||
else if (!m_fading_out && /*m_remaining_time <=0*/up_time >= m_data.duration * 1000) {
|
||||
m_fading_out = true;
|
||||
m_fading_start = now;
|
||||
m_last_render_fading = now;
|
||||
} else if (!m_fading_out) {
|
||||
m_next_render = m_data.duration * 1000 - up_time;//std::min<int64_t>(/*m_data.duration * 1000 - up_time*/m_remaining_time * 1000, MAX_TIMEOUT_MILISECONDS);
|
||||
}
|
||||
|
||||
if (m_state == EState::Finished) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_finished) {
|
||||
|
||||
if (m_state == EState::ClosePending) {
|
||||
m_state = EState::Finished;
|
||||
m_next_render = 0;
|
||||
return;
|
||||
}
|
||||
if (m_close_pending) {
|
||||
m_finished = true;
|
||||
m_state = EState::ClosePending;
|
||||
m_next_render = 0;
|
||||
return;
|
||||
}
|
||||
if (m_fading_out) {
|
||||
if (!m_paused) {
|
||||
m_state = EState::FadingOutStatic;
|
||||
int64_t curr_time = now - m_fading_start;
|
||||
int64_t no_render_time = now - m_last_render_fading;
|
||||
m_current_fade_opacity = std::clamp(1.0f - 0.001f * static_cast<float>(curr_time) / FADING_OUT_DURATION, 0.0f, 1.0f);
|
||||
auto next_render = FADING_OUT_TIMEOUT - no_render_time;
|
||||
if (next_render <= 0) {
|
||||
//m_last_render_fading = GLCanvas3D::timestamp_now();
|
||||
m_state = EState::FadingOutRender;
|
||||
m_next_render = 0;
|
||||
} else
|
||||
m_next_render = next_render;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
NotificationManager::SlicingCompleteLargeNotification::SlicingCompleteLargeNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool large) :
|
||||
|
@ -672,9 +658,11 @@ void NotificationManager::SlicingCompleteLargeNotification::set_print_info(const
|
|||
void NotificationManager::SlicingCompleteLargeNotification::set_large(bool l)
|
||||
{
|
||||
m_is_large = l;
|
||||
m_counting_down = !l;
|
||||
//FIXME this information should not be lost (change m_data?)
|
||||
// m_counting_down = !l;
|
||||
m_hypertext = l ? _u8L("Export G-Code.") : std::string();
|
||||
m_hidden = !l;
|
||||
m_state = l ? EState::Shown : EState::Hidden;
|
||||
init();
|
||||
}
|
||||
//---------------ExportFinishedNotification-----------
|
||||
void NotificationManager::ExportFinishedNotification::count_spaces()
|
||||
|
@ -733,8 +721,8 @@ void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiW
|
|||
ImVec2 win_pos(win_pos_x, win_pos_y);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f));
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f));
|
||||
|
||||
std::string button_text;
|
||||
|
@ -768,7 +756,7 @@ void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiW
|
|||
assert(m_evt_handler != nullptr);
|
||||
if (m_evt_handler != nullptr)
|
||||
wxPostEvent(m_evt_handler, EjectDriveNotificationClickedEvent(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED));
|
||||
m_close_pending = true;
|
||||
close();
|
||||
}
|
||||
|
||||
//invisible large button
|
||||
|
@ -779,7 +767,7 @@ void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiW
|
|||
assert(m_evt_handler != nullptr);
|
||||
if (m_evt_handler != nullptr)
|
||||
wxPostEvent(m_evt_handler, EjectDriveNotificationClickedEvent(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED));
|
||||
m_close_pending = true;
|
||||
close();
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
|
@ -799,30 +787,157 @@ void NotificationManager::ProgressBarNotification::init()
|
|||
m_lines_count++;
|
||||
m_endlines.push_back(m_endlines.back());
|
||||
}
|
||||
void NotificationManager::ProgressBarNotification::count_spaces()
|
||||
{
|
||||
//determine line width
|
||||
m_line_height = ImGui::CalcTextSize("A").y;
|
||||
|
||||
m_left_indentation = m_line_height;
|
||||
if (m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification) {
|
||||
std::string text;
|
||||
text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker);
|
||||
float picture_width = ImGui::CalcTextSize(text.c_str()).x;
|
||||
m_left_indentation = picture_width + m_line_height / 2;
|
||||
}
|
||||
m_window_width_offset = m_line_height * (m_has_cancel_button ? 6 : 4);
|
||||
m_window_width = m_line_height * 25;
|
||||
}
|
||||
|
||||
void NotificationManager::ProgressBarNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
|
||||
{
|
||||
PopNotification::render_text(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
|
||||
// line1 - we do not print any more text than what fits on line 1. Line 2 is bar.
|
||||
ImGui::SetCursorPosX(m_left_indentation);
|
||||
ImGui::SetCursorPosY(win_size_y / 2 - win_size_y / 6 - m_line_height / 2);
|
||||
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
|
||||
if (m_has_cancel_button)
|
||||
render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
|
||||
render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
|
||||
|
||||
}
|
||||
void NotificationManager::ProgressBarNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
|
||||
{
|
||||
ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f);
|
||||
float invisible_length = 0;//((float)(m_data.duration - m_remaining_time) / (float)m_data.duration * win_size_x);
|
||||
//invisible_length -= win_size_x / ((float)m_data.duration * 60.f) * (60 - m_countdown_frame);
|
||||
ImVec2 lineEnd = ImVec2(win_pos_x - invisible_length - m_window_width_offset, win_pos_y + win_size_y/2 + m_line_height / 2);
|
||||
ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation, win_pos_y + win_size_y/2 + m_line_height / 2);
|
||||
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (1.0f * 255.f)), m_line_height * 0.7f);
|
||||
/*
|
||||
//countdown line
|
||||
ImVec4 orange_color = ImGui::GetStyleColorVec4(ImGuiCol_Button);
|
||||
float invisible_length = ((float)(m_data.duration - m_remaining_time) / (float)m_data.duration * win_size_x);
|
||||
invisible_length -= win_size_x / ((float)m_data.duration * 60.f) * (60 - m_countdown_frame);
|
||||
ImVec2 lineEnd = ImVec2(win_pos_x - invisible_length, win_pos_y + win_size_y - 5);
|
||||
ImVec2 lineStart = ImVec2(win_pos_x - win_size_x, win_pos_y + win_size_y - 5);
|
||||
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (int)(orange_color.picture_width * 255.f * (m_fading_out ? m_current_fade_opacity : 1.f))), 2.f);
|
||||
if (!m_paused)
|
||||
m_countdown_frame++;
|
||||
*/
|
||||
ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f);
|
||||
ImVec4 gray_color = ImVec4(.34f, .34f, .34f, 1.0f);
|
||||
ImVec2 lineEnd = ImVec2(win_pos_x - m_window_width_offset, win_pos_y + win_size_y / 2 + m_line_height / 4);
|
||||
ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation, win_pos_y + win_size_y / 2 + m_line_height / 4);
|
||||
ImVec2 midPoint = ImVec2(lineStart.x + (lineEnd.x - lineStart.x) * m_percentage, lineStart.y);
|
||||
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(gray_color.x * 255), (int)(gray_color.y * 255), (int)(gray_color.z * 255), (1.0f * 255.f)), m_line_height * 0.2f);
|
||||
ImGui::GetWindowDrawList()->AddLine(lineStart, midPoint, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (1.0f * 255.f)), m_line_height * 0.2f);
|
||||
}
|
||||
//------PrintHostUploadNotification----------------
|
||||
void NotificationManager::PrintHostUploadNotification::set_percentage(float percent)
|
||||
{
|
||||
if (m_uj_state == UploadJobState::PB_CANCELLED)
|
||||
return;
|
||||
m_percentage = percent;
|
||||
if (percent >= 1.0f) {
|
||||
m_uj_state = UploadJobState::PB_COMPLETED;
|
||||
m_has_cancel_button = false;
|
||||
} else if (percent < 0.0f) {
|
||||
error();
|
||||
} else {
|
||||
m_uj_state = UploadJobState::PB_PROGRESS;
|
||||
m_has_cancel_button = true;
|
||||
}
|
||||
}
|
||||
void NotificationManager::PrintHostUploadNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
|
||||
{
|
||||
std::string text;
|
||||
switch (m_uj_state) {
|
||||
case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_PROGRESS:
|
||||
{
|
||||
ProgressBarNotification::render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
|
||||
float uploaded = m_file_size / 100 * m_percentage;
|
||||
std::stringstream stream;
|
||||
stream << std::fixed << std::setprecision(2) << (int)(m_percentage * 100) << "% - " << uploaded << " of " << m_file_size << "MB uploaded";
|
||||
text = stream.str();
|
||||
ImGui::SetCursorPosX(m_left_indentation);
|
||||
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 /*- m_line_height / 4 * 3*/);
|
||||
break;
|
||||
}
|
||||
case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_ERROR:
|
||||
text = _u8L("ERROR");
|
||||
ImGui::SetCursorPosX(m_left_indentation);
|
||||
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2);
|
||||
break;
|
||||
case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_CANCELLED:
|
||||
text = _u8L("CANCELED");
|
||||
ImGui::SetCursorPosX(m_left_indentation);
|
||||
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2);
|
||||
break;
|
||||
case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_COMPLETED:
|
||||
text = _u8L("COMPLETED");
|
||||
ImGui::SetCursorPosX(m_left_indentation);
|
||||
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2);
|
||||
break;
|
||||
}
|
||||
|
||||
imgui.text(text.c_str());
|
||||
|
||||
}
|
||||
void NotificationManager::PrintHostUploadNotification::render_cancel_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
|
||||
{
|
||||
ImVec2 win_size(win_size_x, win_size_y);
|
||||
ImVec2 win_pos(win_pos_x, win_pos_y);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f));
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f));
|
||||
|
||||
std::string button_text;
|
||||
button_text = ImGui::CancelButton;
|
||||
|
||||
if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - m_line_height * 5.f, win_pos.y),
|
||||
ImVec2(win_pos.x - m_line_height * 2.5f, win_pos.y + win_size.y),
|
||||
true))
|
||||
{
|
||||
button_text = ImGui::CancelHoverButton;
|
||||
// tooltip
|
||||
long time_now = wxGetLocalTime();
|
||||
if (m_hover_time > 0 && m_hover_time < time_now) {
|
||||
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND);
|
||||
ImGui::BeginTooltip();
|
||||
imgui.text(_u8L("Cancel upload") + " " + GUI::shortkey_ctrl_prefix() + "T");
|
||||
ImGui::EndTooltip();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
if (m_hover_time == 0)
|
||||
m_hover_time = time_now;
|
||||
}
|
||||
else
|
||||
m_hover_time = 0;
|
||||
|
||||
ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str());
|
||||
ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f);
|
||||
ImGui::SetCursorPosX(win_size.x - m_line_height * 5.0f);
|
||||
ImGui::SetCursorPosY(win_size.y / 2 - button_size.y);
|
||||
if (imgui.button(button_text.c_str(), button_size.x, button_size.y))
|
||||
{
|
||||
assert(m_evt_handler != nullptr);
|
||||
if (m_evt_handler != nullptr) {
|
||||
auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_CANCEL, m_job_id, m_job_id);
|
||||
wxQueueEvent(m_evt_handler, evt);
|
||||
}
|
||||
}
|
||||
|
||||
//invisible large button
|
||||
ImGui::SetCursorPosX(win_size.x - m_line_height * 4.625f);
|
||||
ImGui::SetCursorPosY(0);
|
||||
if (imgui.button(" ", m_line_height * 2.f, win_size.y))
|
||||
{
|
||||
assert(m_evt_handler != nullptr);
|
||||
if (m_evt_handler != nullptr) {
|
||||
auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_CANCEL, m_job_id, m_job_id);
|
||||
wxQueueEvent(m_evt_handler, evt);
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
}
|
||||
//------NotificationManager--------
|
||||
NotificationManager::NotificationManager(wxEvtHandler* evt_handler) :
|
||||
|
@ -881,12 +996,7 @@ void NotificationManager::push_plater_error_notification(const std::string& text
|
|||
{
|
||||
push_notification_data({ NotificationType::PlaterError, NotificationLevel::ErrorNotification, 0, _u8L("ERROR:") + "\n" + text }, 0);
|
||||
}
|
||||
void NotificationManager::push_plater_warning_notification(const std::string& text)
|
||||
{
|
||||
push_notification_data({ NotificationType::PlaterWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text }, 0);
|
||||
// dissaper if in preview
|
||||
set_in_preview(m_in_preview);
|
||||
}
|
||||
|
||||
void NotificationManager::close_plater_error_notification(const std::string& text)
|
||||
{
|
||||
for (std::unique_ptr<PopNotification> ¬ification : m_pop_notifications) {
|
||||
|
@ -895,11 +1005,32 @@ void NotificationManager::close_plater_error_notification(const std::string& tex
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationManager::push_plater_warning_notification(const std::string& text)
|
||||
{
|
||||
// Find if was not hidden
|
||||
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::PlaterWarning && notification->compare_text(_u8L("WARNING:") + "\n" + text)) {
|
||||
if (notification->get_state() == PopNotification::EState::Hidden) {
|
||||
//dynamic_cast<PlaterWarningNotification*>(notification.get())->show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NotificationData data{ NotificationType::PlaterWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text };
|
||||
|
||||
auto notification = std::make_unique<NotificationManager::PlaterWarningNotification>(data, m_id_provider, m_evt_handler);
|
||||
push_notification_data(std::move(notification), 0);
|
||||
// dissaper if in preview
|
||||
set_in_preview(m_in_preview);
|
||||
}
|
||||
|
||||
void NotificationManager::close_plater_warning_notification(const std::string& text)
|
||||
{
|
||||
for (std::unique_ptr<PopNotification> ¬ification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::PlaterWarning && notification->compare_text(_u8L("WARNING:") + "\n" + text)) {
|
||||
notification->close();
|
||||
dynamic_cast<PlaterWarningNotification*>(notification.get())->real_close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -997,23 +1128,50 @@ void NotificationManager::push_exporting_finished_notification(const std::string
|
|||
NotificationData data{ NotificationType::ExportFinished, NotificationLevel::RegularNotification, on_removable ? 0 : 20, _u8L("Exporting finished.") + "\n" + path };
|
||||
push_notification_data(std::make_unique<NotificationManager::ExportFinishedNotification>(data, m_id_provider, m_evt_handler, on_removable, path, dir_path), 0);
|
||||
}
|
||||
void NotificationManager::push_progress_bar_notification(const std::string& text, float percentage)
|
||||
|
||||
void NotificationManager::push_upload_job_notification(wxEvtHandler* evt_handler, int id, float filesize, const std::string& filename, const std::string& host, float percentage)
|
||||
{
|
||||
NotificationData data{ NotificationType::ProgressBar, NotificationLevel::ProgressBarNotification, 0, text };
|
||||
push_notification_data(std::make_unique<NotificationManager::ProgressBarNotification>(data, m_id_provider, m_evt_handler, 0), 0);
|
||||
std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host);
|
||||
NotificationData data{ NotificationType::PrintHostUpload, NotificationLevel::ProgressBarNotification, 0, text };
|
||||
push_notification_data(std::make_unique<NotificationManager::PrintHostUploadNotification>(data, m_id_provider, evt_handler, 0, id, filesize), 0);
|
||||
}
|
||||
void NotificationManager::set_progress_bar_percentage(const std::string& text, float percentage)
|
||||
void NotificationManager::set_upload_job_notification_percentage(int id, const std::string& filename, const std::string& host, float percentage)
|
||||
{
|
||||
bool found = false;
|
||||
std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host);
|
||||
// bool found = false;
|
||||
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::ProgressBar && notification->compare_text(text)) {
|
||||
dynamic_cast<ProgressBarNotification*>(notification.get())->set_percentage(percentage);
|
||||
wxGetApp().plater()->get_current_canvas3D()->request_extra_frame();
|
||||
found = true;
|
||||
dynamic_cast<PrintHostUploadNotification*>(notification.get())->set_percentage(percentage);
|
||||
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
|
||||
// found = true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (!found) {
|
||||
push_progress_bar_notification(text, percentage);
|
||||
push_upload_job_notification(id, filename, host, percentage);
|
||||
}
|
||||
*/
|
||||
}
|
||||
void NotificationManager::upload_job_notification_show_canceled(int id, const std::string& filename, const std::string& host)
|
||||
{
|
||||
std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host);
|
||||
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::PrintHostUpload && notification->compare_text(text)) {
|
||||
dynamic_cast<PrintHostUploadNotification*>(notification.get())->cancel();
|
||||
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void NotificationManager::upload_job_notification_show_error(int id, const std::string& filename, const std::string& host)
|
||||
{
|
||||
std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host);
|
||||
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::PrintHostUpload && notification->compare_text(text)) {
|
||||
dynamic_cast<PrintHostUploadNotification*>(notification.get())->error();
|
||||
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool NotificationManager::push_notification_data(const NotificationData& notification_data, int timestamp)
|
||||
|
@ -1035,20 +1193,19 @@ bool NotificationManager::push_notification_data(std::unique_ptr<NotificationMan
|
|||
|
||||
if (this->activate_existing(notification.get())) {
|
||||
m_pop_notifications.back()->update(notification->get_data());
|
||||
canvas.request_extra_frame_delayed(33);
|
||||
canvas.schedule_extra_frame(0);
|
||||
return false;
|
||||
} else {
|
||||
m_pop_notifications.emplace_back(std::move(notification));
|
||||
canvas.request_extra_frame_delayed(33);
|
||||
canvas.schedule_extra_frame(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationManager::render_notifications(float overlay_width)
|
||||
void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay_width)
|
||||
{
|
||||
sort_notifications();
|
||||
|
||||
GLCanvas3D& canvas = *wxGetApp().plater()->get_current_canvas3D();
|
||||
|
||||
float last_y = 0.0f;
|
||||
|
||||
for (const auto& notification : m_pop_notifications) {
|
||||
|
@ -1059,7 +1216,49 @@ void NotificationManager::render_notifications(float overlay_width)
|
|||
}
|
||||
|
||||
}
|
||||
update_notifications();
|
||||
m_last_render = GLCanvas3D::timestamp_now();
|
||||
}
|
||||
|
||||
bool NotificationManager::update_notifications(GLCanvas3D& canvas)
|
||||
{
|
||||
// no update if not top window
|
||||
wxWindow* p = dynamic_cast<wxWindow*>(wxGetApp().plater());
|
||||
while (p->GetParent() != nullptr)
|
||||
p = p->GetParent();
|
||||
wxTopLevelWindow* top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p);
|
||||
if (!top_level_wnd->IsActive())
|
||||
return false;
|
||||
|
||||
// next_render() returns numeric_limits::max if no need for frame
|
||||
const int64_t max = std::numeric_limits<int64_t>::max();
|
||||
int64_t next_render = max;
|
||||
const int64_t time_since_render = GLCanvas3D::timestamp_now() - m_last_render;
|
||||
bool request_render = false;
|
||||
// During render, each notification detects if its currently hovered and changes its state to EState::Hovered
|
||||
// If any notification is hovered, all restarts its countdown
|
||||
bool hover = false;
|
||||
for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
|
||||
if (notification->is_hovered()) {
|
||||
hover = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// update state of all notif and erase finished
|
||||
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
|
||||
std::unique_ptr<PopNotification>& notification = *it;
|
||||
request_render |= notification->update_state(hover, time_since_render);
|
||||
next_render = std::min<int64_t>(next_render, notification->next_render());
|
||||
if (notification->get_state() == PopNotification::EState::Finished)
|
||||
it = m_pop_notifications.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
// request next frame in future
|
||||
if (next_render < max)
|
||||
canvas.schedule_extra_frame(int(next_render));
|
||||
|
||||
return request_render;
|
||||
}
|
||||
|
||||
void NotificationManager::sort_notifications()
|
||||
|
@ -1080,9 +1279,11 @@ bool NotificationManager::activate_existing(const NotificationManager::PopNotifi
|
|||
const std::string &new_text = notification->get_data().text1;
|
||||
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end(); ++it) {
|
||||
if ((*it)->get_type() == new_type && !(*it)->is_finished()) {
|
||||
if (new_type == NotificationType::CustomNotification || new_type == NotificationType::PlaterWarning) {
|
||||
if (!(*it)->compare_text(new_text))
|
||||
if (std::find(m_multiple_types.begin(), m_multiple_types.end(), new_type) != m_multiple_types.end()) {
|
||||
// If found same type and same text, return true - update will be performed on the old notif
|
||||
if ((*it)->compare_text(new_text) == false) {
|
||||
continue;
|
||||
}
|
||||
} else if (new_type == NotificationType::SlicingWarning) {
|
||||
auto w1 = dynamic_cast<const SlicingWarningNotification*>(notification);
|
||||
auto w2 = dynamic_cast<const SlicingWarningNotification*>(it->get());
|
||||
|
@ -1094,7 +1295,6 @@ bool NotificationManager::activate_existing(const NotificationManager::PopNotifi
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (it != m_pop_notifications.end() - 1)
|
||||
std::rotate(it, it + 1, m_pop_notifications.end());
|
||||
return true;
|
||||
|
@ -1108,107 +1308,12 @@ void NotificationManager::set_in_preview(bool preview)
|
|||
m_in_preview = preview;
|
||||
for (std::unique_ptr<PopNotification> ¬ification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::PlaterWarning)
|
||||
notification->hide(preview);
|
||||
notification->hide(preview);
|
||||
if (notification->get_type() == NotificationType::SignDetected)
|
||||
notification->hide(!preview);
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationManager::update_notifications()
|
||||
{
|
||||
// no update if not top window
|
||||
wxWindow* p = dynamic_cast<wxWindow*>(wxGetApp().plater());
|
||||
while (p->GetParent() != nullptr)
|
||||
p = p->GetParent();
|
||||
wxTopLevelWindow* top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p);
|
||||
if (!top_level_wnd->IsActive())
|
||||
return;
|
||||
|
||||
//static size_t last_size = m_pop_notifications.size();
|
||||
|
||||
//request frames
|
||||
int64_t next_render = std::numeric_limits<int64_t>::max();
|
||||
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
|
||||
std::unique_ptr<PopNotification>& notification = *it;
|
||||
notification->set_paused(m_hovered);
|
||||
notification->update_state();
|
||||
next_render = std::min<int64_t>(next_render, notification->next_render());
|
||||
if (notification->get_state() == PopNotification::EState::Finished)
|
||||
it = m_pop_notifications.erase(it);
|
||||
else {
|
||||
|
||||
++it;
|
||||
}
|
||||
}
|
||||
/*
|
||||
m_requires_update = false;
|
||||
for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
|
||||
if (notification->requires_update()) {
|
||||
m_requires_update = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
// update hovering state
|
||||
m_hovered = false;
|
||||
for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
|
||||
if (notification->is_hovered()) {
|
||||
m_hovered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Reuire render if some notification was just deleted.
|
||||
size_t curr_size = m_pop_notifications.size();
|
||||
m_requires_render = m_hovered || (last_size != curr_size);
|
||||
last_size = curr_size;
|
||||
|
||||
// Ask notification if it needs render
|
||||
if (!m_requires_render) {
|
||||
for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
|
||||
if (notification->requires_render()) {
|
||||
m_requires_render = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Make sure there will be update after last notification erased
|
||||
if (m_requires_render)
|
||||
m_requires_update = true;
|
||||
*/
|
||||
|
||||
|
||||
if (next_render == 0)
|
||||
wxGetApp().plater()->get_current_canvas3D()->request_extra_frame_delayed(33); //few milliseconds to get from GLCanvas::render
|
||||
else if (next_render < std::numeric_limits<int64_t>::max())
|
||||
wxGetApp().plater()->get_current_canvas3D()->request_extra_frame_delayed(int(next_render));
|
||||
|
||||
/*
|
||||
// actualizate timers
|
||||
wxWindow* p = dynamic_cast<wxWindow*>(wxGetApp().plater());
|
||||
while (p->GetParent() != nullptr)
|
||||
p = p->GetParent();
|
||||
wxTopLevelWindow* top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p);
|
||||
if (!top_level_wnd->IsActive())
|
||||
return;
|
||||
|
||||
{
|
||||
// Control the fade-out.
|
||||
// time in seconds
|
||||
long now = wxGetLocalTime();
|
||||
// Pausing fade-out when the mouse is over some notification.
|
||||
if (!m_hovered && m_last_time < now) {
|
||||
if (now - m_last_time >= MAX_TIMEOUT_SECONDS) {
|
||||
for (auto& notification : m_pop_notifications) {
|
||||
//if (notification->get_state() != PopNotification::EState::Static)
|
||||
notification->substract_remaining_time(MAX_TIMEOUT_SECONDS);
|
||||
}
|
||||
m_last_time = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
bool NotificationManager::has_slicing_error_notification()
|
||||
{
|
||||
return std::any_of(m_pop_notifications.begin(), m_pop_notifications.end(), [](auto &n) {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#ifndef slic3r_GUI_NotificationManager_hpp_
|
||||
#define slic3r_GUI_NotificationManager_hpp_
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
#include "Plater.hpp"
|
||||
#include "GLCanvas3D.hpp"
|
||||
#include "Event.hpp"
|
||||
#include "I18N.hpp"
|
||||
|
||||
|
@ -66,12 +69,16 @@ enum class NotificationType
|
|||
PlaterWarning,
|
||||
// Progress bar instead of text.
|
||||
ProgressBar,
|
||||
// Progress bar with info from Print Host Upload Queue dialog.
|
||||
PrintHostUpload,
|
||||
// Notification, when Color Change G-code is empty and user try to add color change on DoubleSlider.
|
||||
EmptyColorChangeCode,
|
||||
// Notification that custom supports/seams were deleted after mesh repair.
|
||||
CustomSupportsAndSeamRemovedAfterRepair,
|
||||
// Notification that auto adding of color changes is impossible
|
||||
EmptyAutoColorChange,
|
||||
// Notification about detected sign
|
||||
SignDetected,
|
||||
// Notification emitted by Print::validate
|
||||
PrintValidateWarning,
|
||||
// Notification telling user to quit SLA supports manual editing
|
||||
|
@ -140,21 +147,24 @@ public:
|
|||
// Exporting finished, show this information with path, button to open containing folder and if ejectable - eject button
|
||||
void push_exporting_finished_notification(const std::string& path, const std::string& dir_path, bool on_removable);
|
||||
// notification with progress bar
|
||||
void push_progress_bar_notification(const std::string& text, float percentage = 0);
|
||||
void set_progress_bar_percentage(const std::string& text, float percentage);
|
||||
void push_upload_job_notification(wxEvtHandler* evt_handler, int id, float filesize, const std::string& filename, const std::string& host, float percentage = 0);
|
||||
void set_upload_job_notification_percentage(int id, const std::string& filename, const std::string& host, float percentage);
|
||||
void upload_job_notification_show_canceled(int id, const std::string& filename, const std::string& host);
|
||||
void upload_job_notification_show_error(int id, const std::string& filename, const std::string& host);
|
||||
// Close old notification ExportFinished.
|
||||
void new_export_began(bool on_removable);
|
||||
// finds ExportFinished notification and closes it if it was to removable device
|
||||
void device_ejected();
|
||||
// renders notifications in queue and deletes expired ones
|
||||
void render_notifications(float overlay_width);
|
||||
void render_notifications(GLCanvas3D& canvas, float overlay_width);
|
||||
// finds and closes all notifications of given type
|
||||
void close_notification_of_type(const NotificationType type);
|
||||
// Which view is active? Plater or G-code preview? Hide warnings in G-code preview.
|
||||
void set_in_preview(bool preview);
|
||||
// Move to left to avoid colision with variable layer height gizmo.
|
||||
void set_move_from_overlay(bool move) { m_move_from_overlay = move; }
|
||||
|
||||
// perform update_state on each notification and ask for more frames if needed, return true for render needed
|
||||
bool update_notifications(GLCanvas3D& canvas);
|
||||
private:
|
||||
// duration 0 means not disapearing
|
||||
struct NotificationData {
|
||||
|
@ -192,23 +202,24 @@ private:
|
|||
|
||||
enum class EState
|
||||
{
|
||||
Unknown,
|
||||
Unknown, // NOT initialized
|
||||
Hidden,
|
||||
FadingOutRender, // Requesting Render
|
||||
FadingOutStatic,
|
||||
Shown, // Requesting Render at some time if duration != 0
|
||||
FadingOut, // Requesting Render at some time
|
||||
ClosePending, // Requesting Render
|
||||
Finished, // Requesting Render
|
||||
Hovered, // Followed by Shown
|
||||
Paused
|
||||
};
|
||||
|
||||
PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler);
|
||||
virtual ~PopNotification() { if (m_id) m_id_provider.release_id(m_id); }
|
||||
void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width);
|
||||
virtual void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width);
|
||||
// close will dissapear notification on next render
|
||||
void close() { m_close_pending = true; }
|
||||
virtual void close() { m_state = EState::ClosePending; wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);}
|
||||
// data from newer notification of same type
|
||||
void update(const NotificationData& n);
|
||||
bool is_finished() const { return m_finished || m_close_pending; }
|
||||
bool is_hovered() const { return m_hovered; }
|
||||
bool is_finished() const { return m_state == EState::ClosePending || m_state == EState::Finished; }
|
||||
// returns top after movement
|
||||
float get_top() const { return m_top_y; }
|
||||
//returns top in actual frame
|
||||
|
@ -216,23 +227,17 @@ private:
|
|||
const NotificationType get_type() const { return m_data.type; }
|
||||
const NotificationData get_data() const { return m_data; }
|
||||
const bool is_gray() const { return m_is_gray; }
|
||||
// Call equals one second down
|
||||
void substract_remaining_time(int seconds) { m_remaining_time -= seconds; }
|
||||
void set_gray(bool g) { m_is_gray = g; }
|
||||
void set_paused(bool p) { m_paused = p; }
|
||||
bool compare_text(const std::string& text);
|
||||
void hide(bool h) { m_hidden = h; }
|
||||
// sets m_next_render with time of next mandatory rendering
|
||||
void update_state();
|
||||
int64_t next_render() const { return m_next_render; }
|
||||
/*
|
||||
bool requires_render() const { return m_state == EState::FadingOutRender || m_state == EState::ClosePending || m_state == EState::Finished; }
|
||||
bool requires_update() const { return m_state != EState::Hidden; }
|
||||
*/
|
||||
EState get_state() const { return m_state; }
|
||||
protected:
|
||||
void hide(bool h) { if (is_finished()) return; m_state = h ? EState::Hidden : EState::Unknown; }
|
||||
// sets m_next_render with time of next mandatory rendering. Delta is time since last render.
|
||||
bool update_state(bool paused, const int64_t delta);
|
||||
int64_t next_render() const { return is_finished() ? 0 : m_next_render; }
|
||||
EState get_state() const { return m_state; }
|
||||
bool is_hovered() const { return m_state == EState::Hovered; }
|
||||
|
||||
// Call after every size change
|
||||
void init();
|
||||
virtual void init();
|
||||
// Part of init()
|
||||
virtual void count_spaces();
|
||||
// Calculetes correct size but not se it in imgui!
|
||||
|
@ -254,45 +259,36 @@ private:
|
|||
// Hypertext action, returns true if notification should close.
|
||||
// Action is stored in NotificationData::callback as std::function<bool(wxEvtHandler*)>
|
||||
virtual bool on_text_click();
|
||||
|
||||
protected:
|
||||
const NotificationData m_data;
|
||||
|
||||
// For reusing ImGUI windows.
|
||||
NotificationIDProvider &m_id_provider;
|
||||
int m_id{ 0 };
|
||||
|
||||
// State for rendering
|
||||
EState m_state { EState::Unknown };
|
||||
|
||||
int m_id { 0 };
|
||||
bool m_initialized { false };
|
||||
// Time values for rendering fade-out
|
||||
|
||||
int64_t m_fading_start{ 0LL };
|
||||
|
||||
// first appereance of notification or last hover;
|
||||
int64_t m_notification_start;
|
||||
// time to next must-do render
|
||||
int64_t m_next_render{ std::numeric_limits<int64_t>::max() };
|
||||
float m_current_fade_opacity{ 1.0f };
|
||||
|
||||
// Notification data
|
||||
|
||||
// Main text
|
||||
std::string m_text1;
|
||||
// Clickable text
|
||||
std::string m_hypertext;
|
||||
// Aditional text after hypertext - currently not used
|
||||
std::string m_text2;
|
||||
// Countdown variables
|
||||
long m_remaining_time;
|
||||
bool m_counting_down;
|
||||
long m_last_remaining_time;
|
||||
bool m_paused { false };
|
||||
int m_countdown_frame { 0 };
|
||||
bool m_fading_out { false };
|
||||
int64_t m_fading_start { 0LL };
|
||||
// time of last done render when fading
|
||||
int64_t m_last_render_fading { 0LL };
|
||||
// first appereance of notification or last hover;
|
||||
int64_t m_notification_start;
|
||||
// time to next must-do render
|
||||
int64_t m_next_render { std::numeric_limits<int64_t>::max() };
|
||||
float m_current_fade_opacity { 1.0f };
|
||||
// If hidden the notif is alive but not visible to user
|
||||
bool m_hidden { false };
|
||||
// m_finished = true - does not render, marked to delete
|
||||
bool m_finished { false };
|
||||
// Will go to m_finished next render
|
||||
bool m_close_pending { false };
|
||||
bool m_hovered { false };
|
||||
// variables to count positions correctly
|
||||
|
||||
// inner variables to position notification window, texts and buttons correctly
|
||||
|
||||
// all space without text
|
||||
float m_window_width_offset;
|
||||
// Space on left side without text
|
||||
|
@ -302,9 +298,7 @@ private:
|
|||
float m_window_width { 450.0f };
|
||||
//Distance from bottom of notifications to top of this notification
|
||||
float m_top_y { 0.0f };
|
||||
|
||||
// Height of text
|
||||
// Used as basic scaling unit!
|
||||
// Height of text - Used as basic scaling unit!
|
||||
float m_line_height;
|
||||
std::vector<size_t> m_endlines;
|
||||
// Gray are f.e. eorrors when its uknown if they are still valid
|
||||
|
@ -322,10 +316,16 @@ private:
|
|||
{
|
||||
public:
|
||||
SlicingCompleteLargeNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool largeds);
|
||||
void set_large(bool l);
|
||||
bool get_large() { return m_is_large; }
|
||||
|
||||
void set_print_info(const std::string &info);
|
||||
void set_large(bool l);
|
||||
bool get_large() { return m_is_large; }
|
||||
void set_print_info(const std::string &info);
|
||||
virtual void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width)
|
||||
{
|
||||
// This notification is always hidden if !large (means side bar is collapsed)
|
||||
if (!get_large() && !is_finished())
|
||||
m_state = EState::Hidden;
|
||||
PopNotification::render(canvas, initial_y, move_from_overlay, overlay_width);
|
||||
}
|
||||
protected:
|
||||
virtual void render_text(ImGuiWrapper& imgui,
|
||||
const float win_size_x, const float win_size_y,
|
||||
|
@ -344,21 +344,78 @@ private:
|
|||
int warning_step;
|
||||
};
|
||||
|
||||
class PlaterWarningNotification : public PopNotification
|
||||
{
|
||||
public:
|
||||
PlaterWarningNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler) : PopNotification(n, id_provider, evt_handler) {}
|
||||
virtual void close() { if(is_finished()) return; m_state = EState::Hidden; wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); }
|
||||
void real_close() { m_state = EState::ClosePending; wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); }
|
||||
void show() { m_state = EState::Unknown; }
|
||||
};
|
||||
|
||||
|
||||
class ProgressBarNotification : public PopNotification
|
||||
{
|
||||
public:
|
||||
|
||||
ProgressBarNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, float percentage) : PopNotification(n, id_provider, evt_handler) { set_percentage(percentage); }
|
||||
void set_percentage(float percent) { m_percentage = percent; if (percent >= 1.0f) m_progress_complete = true; else m_progress_complete = false; }
|
||||
virtual void set_percentage(float percent) { m_percentage = percent; }
|
||||
protected:
|
||||
virtual void init();
|
||||
virtual void init() override;
|
||||
virtual void count_spaces() override;
|
||||
virtual void render_text(ImGuiWrapper& imgui,
|
||||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x, const float win_pos_y);
|
||||
void render_bar(ImGuiWrapper& imgui,
|
||||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x, const float win_pos_y);
|
||||
bool m_progress_complete{ false };
|
||||
float m_percentage;
|
||||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x, const float win_pos_y);
|
||||
virtual void render_bar(ImGuiWrapper& imgui,
|
||||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x, const float win_pos_y);
|
||||
virtual void render_cancel_button(ImGuiWrapper& imgui,
|
||||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x, const float win_pos_y)
|
||||
{}
|
||||
float m_percentage;
|
||||
|
||||
bool m_has_cancel_button {false};
|
||||
// local time of last hover for showing tooltip
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class PrintHostUploadNotification : public ProgressBarNotification
|
||||
{
|
||||
public:
|
||||
enum class UploadJobState
|
||||
{
|
||||
PB_PROGRESS,
|
||||
PB_ERROR,
|
||||
PB_CANCELLED,
|
||||
PB_COMPLETED
|
||||
};
|
||||
PrintHostUploadNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, float percentage, int job_id, float filesize)
|
||||
:ProgressBarNotification(n, id_provider, evt_handler, percentage)
|
||||
, m_job_id(job_id)
|
||||
, m_file_size(filesize)
|
||||
{
|
||||
m_has_cancel_button = true;
|
||||
}
|
||||
static std::string get_upload_job_text(int id, const std::string& filename, const std::string& host) { return "[" + std::to_string(id) + "] " + filename + " -> " + host; }
|
||||
virtual void set_percentage(float percent);
|
||||
void cancel() { m_uj_state = UploadJobState::PB_CANCELLED; m_has_cancel_button = false; }
|
||||
void error() { m_uj_state = UploadJobState::PB_ERROR; m_has_cancel_button = false; }
|
||||
protected:
|
||||
virtual void render_bar(ImGuiWrapper& imgui,
|
||||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x, const float win_pos_y);
|
||||
virtual void render_cancel_button(ImGuiWrapper& imgui,
|
||||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x, const float win_pos_y);
|
||||
// Identifies job in cancel callback
|
||||
int m_job_id;
|
||||
// Size of uploaded size to be displayed in MB
|
||||
float m_file_size;
|
||||
long m_hover_time{ 0 };
|
||||
UploadJobState m_uj_state{ UploadJobState::PB_PROGRESS };
|
||||
};
|
||||
|
||||
class ExportFinishedNotification : public PopNotification
|
||||
|
@ -405,32 +462,25 @@ private:
|
|||
void sort_notifications();
|
||||
// If there is some error notification active, then the "Export G-code" notification after the slicing is finished is suppressed.
|
||||
bool has_slicing_error_notification();
|
||||
// perform update_state on each notification and ask for more frames if needed
|
||||
void update_notifications();
|
||||
|
||||
|
||||
// Target for wxWidgets events sent by clicking on the hyperlink available at some notifications.
|
||||
wxEvtHandler* m_evt_handler;
|
||||
// Cache of IDs to identify and reuse ImGUI windows.
|
||||
NotificationIDProvider m_id_provider;
|
||||
std::deque<std::unique_ptr<PopNotification>> m_pop_notifications;
|
||||
// Last render time in seconds for fade out control.
|
||||
long m_last_time { 0 };
|
||||
// When mouse hovers over some notification, the fade-out of all notifications is suppressed.
|
||||
bool m_hovered { false };
|
||||
//timestamps used for slicing finished - notification could be gone so it needs to be stored here
|
||||
std::unordered_set<int> m_used_timestamps;
|
||||
// True if G-code preview is active. False if the Plater is active.
|
||||
bool m_in_preview { false };
|
||||
// True if the layer editing is enabled in Plater, so that the notifications are shifted left of it.
|
||||
bool m_move_from_overlay { false };
|
||||
|
||||
// Timestamp of last rendering
|
||||
int64_t m_last_render { 0LL };
|
||||
// Notification types that can be shown multiple types at once (compared by text)
|
||||
const std::vector<NotificationType> m_multiple_types = { NotificationType::CustomNotification, NotificationType::PlaterWarning, NotificationType::ProgressBar, NotificationType::PrintHostUpload };
|
||||
//prepared (basic) notifications
|
||||
const std::vector<NotificationData> basic_notifications = {
|
||||
// {NotificationType::SlicingNotPossible, NotificationLevel::RegularNotification, 10, _u8L("Slicing is not possible.")},
|
||||
// {NotificationType::ExportToRemovableFinished, NotificationLevel::ImportantNotification, 0, _u8L("Exporting finished."), _u8L("Eject drive.") },
|
||||
{NotificationType::Mouse3dDisconnected, NotificationLevel::RegularNotification, 10, _u8L("3D Mouse disconnected.") },
|
||||
// {NotificationType::Mouse3dConnected, NotificationLevel::RegularNotification, 5, _u8L("3D Mouse connected.") },
|
||||
// {NotificationType::NewPresetsAviable, NotificationLevel::ImportantNotification, 20, _u8L("New Presets are available."), _u8L("See here.") },
|
||||
{NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 20, _u8L("Configuration update is available."), _u8L("See more."),
|
||||
[](wxEvtHandler* evnthndlr) {
|
||||
if (evnthndlr != nullptr)
|
||||
|
|
|
@ -91,7 +91,7 @@ void OG_CustomCtrl::init_ctrl_lines()
|
|||
height = m_bmp_blinking_sz.GetHeight() + m_v_gap;
|
||||
ctrl_lines.emplace_back(CtrlLine(height, this, line, true));
|
||||
}
|
||||
else if (opt_group->label_width != 0 && (!line.label.IsEmpty() || option_set.front().opt.gui_type == "legend") )
|
||||
else if (opt_group->label_width != 0 && (!line.label.IsEmpty() || option_set.front().opt.gui_type == ConfigOptionDef::GUIType::legend) )
|
||||
{
|
||||
wxSize label_sz = GetTextExtent(line.label);
|
||||
height = label_sz.y * (label_sz.GetWidth() > int(opt_group->label_width * m_em_unit) ? 2 : 1) + m_v_gap;
|
||||
|
@ -186,11 +186,11 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/)
|
|||
#endif //__WXMSW__
|
||||
h_pos += label_w + 1 + m_h_gap;
|
||||
}
|
||||
h_pos += (opt.opt.gui_type == "legend" ? 1 : 3) * blinking_button_width;
|
||||
h_pos += (opt.opt.gui_type == ConfigOptionDef::GUIType::legend ? 1 : 3) * blinking_button_width;
|
||||
|
||||
if (field == field_in)
|
||||
break;
|
||||
if (opt.opt.gui_type == "legend")
|
||||
if (opt.opt.gui_type == ConfigOptionDef::GUIType::legend)
|
||||
h_pos += 2 * blinking_button_width;
|
||||
|
||||
h_pos += field->getWindow()->GetSize().x;
|
||||
|
@ -580,7 +580,7 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_mode_bmp(wxDC& dc, wxCoord v_pos)
|
|||
wxBitmap bmp = create_scaled_bitmap(bmp_name, ctrl, wxOSX ? 10 : 12);
|
||||
wxCoord y_draw = v_pos + lround((height - get_bitmap_size(bmp).GetHeight()) / 2);
|
||||
|
||||
if (og_line.get_options().front().opt.gui_type != "legend")
|
||||
if (og_line.get_options().front().opt.gui_type != ConfigOptionDef::GUIType::legend)
|
||||
dc.DrawBitmap(bmp, 0, y_draw);
|
||||
|
||||
return get_bitmap_size(bmp).GetWidth() + ctrl->m_h_gap;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "wxExtensions.hpp"
|
||||
#include "BitmapCache.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "GUI_Factories.hpp"
|
||||
#include "I18N.hpp"
|
||||
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
@ -44,8 +44,9 @@ void ObjectDataViewModelNode::init_container()
|
|||
#endif //__WXGTK__
|
||||
}
|
||||
|
||||
#define LAYER_ROOT_ICON "edit_layers_all"
|
||||
#define LAYER_ICON "edit_layers_some"
|
||||
static constexpr char LayerRootIcon[] = "edit_layers_all";
|
||||
static constexpr char LayerIcon[] = "edit_layers_some";
|
||||
static constexpr char WarningIcon[] = "exclamation";
|
||||
|
||||
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type) :
|
||||
m_parent(parent),
|
||||
|
@ -65,7 +66,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
|
|||
}
|
||||
else if (type == itLayerRoot)
|
||||
{
|
||||
m_bmp = create_scaled_bitmap(LAYER_ROOT_ICON); // FIXME: pass window ptr
|
||||
m_bmp = create_scaled_bitmap(LayerRootIcon); // FIXME: pass window ptr
|
||||
m_name = _(L("Layers"));
|
||||
}
|
||||
|
||||
|
@ -94,7 +95,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
|
|||
}
|
||||
const std::string label_range = (boost::format(" %.2f-%.2f ") % layer_range.first % layer_range.second).str();
|
||||
m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
|
||||
m_bmp = create_scaled_bitmap(LAYER_ICON); // FIXME: pass window ptr
|
||||
m_bmp = create_scaled_bitmap(LayerIcon); // FIXME: pass window ptr
|
||||
|
||||
set_action_and_extruder_icons();
|
||||
init_container();
|
||||
|
@ -140,17 +141,14 @@ void ObjectDataViewModelNode::update_settings_digest_bitmaps()
|
|||
{
|
||||
m_bmp = m_empty_bmp;
|
||||
|
||||
std::map<std::string, wxBitmap>& categories_icon = Slic3r::GUI::wxGetApp().obj_list()->CATEGORY_ICON;
|
||||
|
||||
std::string scaled_bitmap_name = m_name.ToUTF8().data();
|
||||
scaled_bitmap_name += "-em" + std::to_string(wxGetApp().em_unit()) + (wxGetApp().dark_mode() ? "-dm" : "");
|
||||
|
||||
wxBitmap *bmp = m_bitmap_cache->find(scaled_bitmap_name);
|
||||
if (bmp == nullptr) {
|
||||
std::vector<wxBitmap> bmps;
|
||||
for (auto& cat : m_opt_categories)
|
||||
bmps.emplace_back( categories_icon.find(cat) == categories_icon.end() ?
|
||||
wxNullBitmap : categories_icon.at(cat));
|
||||
for (auto& category : m_opt_categories)
|
||||
bmps.emplace_back(SettingsFactory::get_category_bitmap(category));
|
||||
bmp = m_bitmap_cache->insert(scaled_bitmap_name, bmps);
|
||||
}
|
||||
|
||||
|
@ -249,6 +247,9 @@ static int get_root_idx(ObjectDataViewModelNode *parent_node, const ItemType roo
|
|||
ObjectDataViewModel::ObjectDataViewModel()
|
||||
{
|
||||
m_bitmap_cache = new Slic3r::GUI::BitmapCache;
|
||||
|
||||
m_volume_bmps = MenuFactory::get_volume_bitmaps();
|
||||
m_warning_bmp = create_scaled_bitmap(WarningIcon);
|
||||
}
|
||||
|
||||
ObjectDataViewModel::~ObjectDataViewModel()
|
||||
|
@ -267,7 +268,7 @@ wxDataViewItem ObjectDataViewModel::Add(const wxString &name,
|
|||
auto root = new ObjectDataViewModelNode(name, extruder_str);
|
||||
// Add error icon if detected auto-repaire
|
||||
if (has_errors)
|
||||
root->m_bmp = *m_warning_bmp;
|
||||
root->m_bmp = m_warning_bmp;
|
||||
|
||||
m_objects.push_back(root);
|
||||
// notify control
|
||||
|
@ -317,7 +318,7 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent
|
|||
|
||||
// if part with errors is added, but object wasn't marked, then mark it
|
||||
if (!obj_errors && has_errors)
|
||||
root->SetBitmap(*m_warning_bmp);
|
||||
root->SetBitmap(m_warning_bmp);
|
||||
|
||||
// notify control
|
||||
const wxDataViewItem child((void*)node);
|
||||
|
@ -1434,10 +1435,20 @@ void ObjectDataViewModel::SetVolumeType(const wxDataViewItem &item, const Slic3r
|
|||
return;
|
||||
|
||||
ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
|
||||
node->SetBitmap(*m_volume_bmps[int(type)]);
|
||||
node->SetVolumeType(type);
|
||||
node->SetBitmap(m_volume_bmps[int(type)]);
|
||||
ItemChanged(item);
|
||||
}
|
||||
|
||||
ModelVolumeType ObjectDataViewModel::GetVolumeType(const wxDataViewItem& item)
|
||||
{
|
||||
if (!item.IsOk() || GetItemType(item) != itVolume)
|
||||
return ModelVolumeType::INVALID;
|
||||
|
||||
ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
|
||||
return node->GetVolumeType();
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::SetPrintableState(
|
||||
PrintIndicator printable,
|
||||
int obj_idx,
|
||||
|
@ -1480,6 +1491,9 @@ wxDataViewItem ObjectDataViewModel::SetObjectPrintableState(
|
|||
|
||||
void ObjectDataViewModel::Rescale()
|
||||
{
|
||||
m_volume_bmps = MenuFactory::get_volume_bitmaps();
|
||||
m_warning_bmp = create_scaled_bitmap(WarningIcon);
|
||||
|
||||
wxDataViewItemArray all_items;
|
||||
GetAllChildren(wxDataViewItem(0), all_items);
|
||||
|
||||
|
@ -1494,15 +1508,15 @@ void ObjectDataViewModel::Rescale()
|
|||
switch (node->m_type)
|
||||
{
|
||||
case itObject:
|
||||
if (node->m_bmp.IsOk()) node->m_bmp = *m_warning_bmp;
|
||||
if (node->m_bmp.IsOk()) node->m_bmp = m_warning_bmp;
|
||||
break;
|
||||
case itVolume:
|
||||
node->m_bmp = GetVolumeIcon(node->m_volume_type, node->m_bmp.GetWidth() != node->m_bmp.GetHeight());
|
||||
break;
|
||||
case itLayerRoot:
|
||||
node->m_bmp = create_scaled_bitmap(LAYER_ROOT_ICON);
|
||||
node->m_bmp = create_scaled_bitmap(LayerRootIcon);
|
||||
case itLayer:
|
||||
node->m_bmp = create_scaled_bitmap(LAYER_ICON);
|
||||
node->m_bmp = create_scaled_bitmap(LayerIcon);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
@ -1514,7 +1528,7 @@ void ObjectDataViewModel::Rescale()
|
|||
wxBitmap ObjectDataViewModel::GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, const bool is_marked/* = false*/)
|
||||
{
|
||||
if (!is_marked)
|
||||
return *m_volume_bmps[static_cast<int>(vol_type)];
|
||||
return m_volume_bmps[static_cast<int>(vol_type)];
|
||||
|
||||
std::string scaled_bitmap_name = "warning" + std::to_string(static_cast<int>(vol_type));
|
||||
scaled_bitmap_name += "-em" + std::to_string(Slic3r::GUI::wxGetApp().em_unit());
|
||||
|
@ -1523,8 +1537,8 @@ wxBitmap ObjectDataViewModel::GetVolumeIcon(const Slic3r::ModelVolumeType vol_ty
|
|||
if (bmp == nullptr) {
|
||||
std::vector<wxBitmap> bmps;
|
||||
|
||||
bmps.emplace_back(*m_warning_bmp);
|
||||
bmps.emplace_back(*m_volume_bmps[static_cast<int>(vol_type)]);
|
||||
bmps.emplace_back(m_warning_bmp);
|
||||
bmps.emplace_back(m_volume_bmps[static_cast<int>(vol_type)]);
|
||||
|
||||
bmp = m_bitmap_cache->insert(scaled_bitmap_name, bmps);
|
||||
}
|
||||
|
@ -1543,7 +1557,7 @@ void ObjectDataViewModel::DeleteWarningIcon(const wxDataViewItem& item, const bo
|
|||
return;
|
||||
|
||||
if (node->GetType() & itVolume) {
|
||||
node->SetBitmap(*m_volume_bmps[static_cast<int>(node->volume_type())]);
|
||||
node->SetBitmap(m_volume_bmps[static_cast<int>(node->volume_type())]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -171,13 +171,14 @@ public:
|
|||
}
|
||||
|
||||
bool SetValue(const wxVariant &variant, unsigned int col);
|
||||
|
||||
void SetVolumeType(ModelVolumeType type) { m_volume_type = type; }
|
||||
void SetBitmap(const wxBitmap &icon) { m_bmp = icon; }
|
||||
const wxBitmap& GetBitmap() const { return m_bmp; }
|
||||
const wxString& GetName() const { return m_name; }
|
||||
ItemType GetType() const { return m_type; }
|
||||
void SetIdx(const int& idx);
|
||||
int GetIdx() const { return m_idx; }
|
||||
ModelVolumeType GetVolumeType() { return m_volume_type; }
|
||||
t_layer_height_range GetLayerRange() const { return m_layer_range; }
|
||||
PrintIndicator IsPrintable() const { return m_printable; }
|
||||
|
||||
|
@ -241,8 +242,8 @@ wxDECLARE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent);
|
|||
class ObjectDataViewModel :public wxDataViewModel
|
||||
{
|
||||
std::vector<ObjectDataViewModelNode*> m_objects;
|
||||
std::vector<wxBitmap*> m_volume_bmps;
|
||||
wxBitmap* m_warning_bmp { nullptr };
|
||||
std::vector<wxBitmap> m_volume_bmps;
|
||||
wxBitmap m_warning_bmp;
|
||||
|
||||
wxDataViewCtrl* m_ctrl { nullptr };
|
||||
|
||||
|
@ -348,9 +349,8 @@ public:
|
|||
void UpdateObjectPrintable(wxDataViewItem parent_item);
|
||||
void UpdateInstancesPrintable(wxDataViewItem parent_item);
|
||||
|
||||
void SetVolumeBitmaps(const std::vector<wxBitmap*>& volume_bmps) { m_volume_bmps = volume_bmps; }
|
||||
void SetWarningBitmap(wxBitmap* bitmap) { m_warning_bmp = bitmap; }
|
||||
void SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type);
|
||||
ModelVolumeType GetVolumeType(const wxDataViewItem &item);
|
||||
wxDataViewItem SetPrintableState( PrintIndicator printable, int obj_idx,
|
||||
int subobj_idx = -1,
|
||||
ItemType subobj_type = itInstance);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "GUI.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#include "slic3r/Utils/Platform.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
@ -319,7 +320,13 @@ void OpenGLManager::detect_multisample(int* attribList)
|
|||
{
|
||||
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER;
|
||||
bool enable_multisample = wxVersion >= 30003;
|
||||
s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? EMultisampleState::Enabled : EMultisampleState::Disabled;
|
||||
s_multisample =
|
||||
enable_multisample &&
|
||||
// Disable multi-sampling on ChromeOS, as the OpenGL virtualization swaps Red/Blue channels with multi-sampling enabled,
|
||||
// at least on some platforms.
|
||||
(platform() != Platform::Linux || platform_flavor() != PlatformFlavor::LinuxOnChromium) &&
|
||||
wxGLCanvas::IsDisplaySupported(attribList)
|
||||
? EMultisampleState::Enabled : EMultisampleState::Disabled;
|
||||
// Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows
|
||||
// s_multisample = enable_multisample && wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample");
|
||||
}
|
||||
|
|
|
@ -25,23 +25,27 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id) {
|
|||
const t_field& OptionsGroup::build_field(const t_config_option_key& id, const ConfigOptionDef& opt) {
|
||||
// Check the gui_type field first, fall through
|
||||
// is the normal type.
|
||||
if (opt.gui_type == "select") {
|
||||
} else if (opt.gui_type == "select_open") {
|
||||
switch (opt.gui_type) {
|
||||
case ConfigOptionDef::GUIType::select_open:
|
||||
m_fields.emplace(id, Choice::Create<Choice>(this->ctrl_parent(), opt, id));
|
||||
} else if (opt.gui_type == "color") {
|
||||
break;
|
||||
case ConfigOptionDef::GUIType::color:
|
||||
m_fields.emplace(id, ColourPicker::Create<ColourPicker>(this->ctrl_parent(), opt, id));
|
||||
} else if (opt.gui_type == "f_enum_open" ||
|
||||
opt.gui_type == "i_enum_open" ||
|
||||
opt.gui_type == "i_enum_closed") {
|
||||
break;
|
||||
case ConfigOptionDef::GUIType::f_enum_open:
|
||||
case ConfigOptionDef::GUIType::i_enum_open:
|
||||
m_fields.emplace(id, Choice::Create<Choice>(this->ctrl_parent(), opt, id));
|
||||
} else if (opt.gui_type == "slider") {
|
||||
break;
|
||||
case ConfigOptionDef::GUIType::slider:
|
||||
m_fields.emplace(id, SliderCtrl::Create<SliderCtrl>(this->ctrl_parent(), opt, id));
|
||||
} else if (opt.gui_type == "i_spin") { // Spinctrl
|
||||
} else if (opt.gui_type == "legend") { // StaticText
|
||||
break;
|
||||
case ConfigOptionDef::GUIType::legend: // StaticText
|
||||
m_fields.emplace(id, StaticText::Create<StaticText>(this->ctrl_parent(), opt, id));
|
||||
} else if (opt.gui_type == "one_string") {
|
||||
break;
|
||||
case ConfigOptionDef::GUIType::one_string:
|
||||
m_fields.emplace(id, TextCtrl::Create<TextCtrl>(this->ctrl_parent(), opt, id));
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
switch (opt.type) {
|
||||
case coFloatOrPercent:
|
||||
case coFloat:
|
||||
|
@ -122,7 +126,7 @@ bool OptionsGroup::is_legend_line()
|
|||
{
|
||||
if (m_lines.size() == 1) {
|
||||
const std::vector<Option>& option_set = m_lines.front().get_options();
|
||||
return !option_set.empty() && option_set.front().opt.gui_type == "legend";
|
||||
return !option_set.empty() && option_set.front().opt.gui_type == ConfigOptionDef::GUIType::legend;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -213,7 +217,7 @@ void OptionsGroup::activate_line(Line& line)
|
|||
}
|
||||
|
||||
auto option_set = line.get_options();
|
||||
bool is_legend_line = option_set.front().opt.gui_type == "legend";
|
||||
bool is_legend_line = option_set.front().opt.gui_type == ConfigOptionDef::GUIType::legend;
|
||||
|
||||
if (!custom_ctrl && m_use_custom_ctrl) {
|
||||
custom_ctrl = new OG_CustomCtrl(is_legend_line || !staticbox ? this->parent() : static_cast<wxWindow*>(this->stb), this);
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "GUI_ObjectManipulation.hpp"
|
||||
#include "GUI_ObjectLayers.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "GUI_Factories.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "format.hpp"
|
||||
|
@ -75,6 +76,7 @@
|
|||
#include "../Utils/FixModelByWin10.hpp"
|
||||
#include "../Utils/UndoRedo.hpp"
|
||||
#include "../Utils/PresetUpdater.hpp"
|
||||
#include "../Utils/Platform.hpp"
|
||||
#include "../Utils/Process.hpp"
|
||||
#include "RemovableDriveManager.hpp"
|
||||
#include "InstanceCheck.hpp"
|
||||
|
@ -356,7 +358,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) :
|
|||
ConfigOptionDef support_def;
|
||||
support_def.label = L("Supports");
|
||||
support_def.type = coStrings;
|
||||
support_def.gui_type = "select_open";
|
||||
support_def.gui_type = ConfigOptionDef::GUIType::select_open;
|
||||
support_def.tooltip = L("Select what kind of support do you need");
|
||||
support_def.enum_labels.push_back(L("None"));
|
||||
support_def.enum_labels.push_back(L("Support on build plate only"));
|
||||
|
@ -396,7 +398,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) :
|
|||
def.label = L("Brim");
|
||||
def.type = coBool;
|
||||
def.tooltip = L("This flag enables the brim that will be printed around each object on the first layer.");
|
||||
def.gui_type = "";
|
||||
def.gui_type = ConfigOptionDef::GUIType::undefined;
|
||||
def.set_default_value(new ConfigOptionBool{ m_brim_width > 0.0 ? true : false });
|
||||
option = Option(def, "brim");
|
||||
option.opt.sidetext = "";
|
||||
|
@ -499,7 +501,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) :
|
|||
ConfigOptionDef pad_def;
|
||||
pad_def.label = L("Pad");
|
||||
pad_def.type = coStrings;
|
||||
pad_def.gui_type = "select_open";
|
||||
pad_def.gui_type = ConfigOptionDef::GUIType::select_open;
|
||||
pad_def.tooltip = L("Select what kind of pad do you need");
|
||||
pad_def.enum_labels.push_back(L("None"));
|
||||
pad_def.enum_labels.push_back(L("Below object"));
|
||||
|
@ -1322,7 +1324,7 @@ void Sidebar::update_mode()
|
|||
|
||||
p->object_list->unselect_objects();
|
||||
p->object_list->update_selections();
|
||||
p->object_list->update_object_menu();
|
||||
// p->object_list->update_object_menu();
|
||||
|
||||
Layout();
|
||||
}
|
||||
|
@ -1404,23 +1406,7 @@ struct Plater::priv
|
|||
Plater *q;
|
||||
MainFrame *main_frame;
|
||||
|
||||
// Object popup menu
|
||||
MenuWithSeparators object_menu;
|
||||
// Part popup menu
|
||||
MenuWithSeparators part_menu;
|
||||
// SLA-Object popup menu
|
||||
MenuWithSeparators sla_object_menu;
|
||||
// Default popup menu (when nothing is selected on 3DScene)
|
||||
MenuWithSeparators default_menu;
|
||||
|
||||
// Removed/Prepended Items according to the view mode
|
||||
std::vector<wxMenuItem*> items_increase;
|
||||
std::vector<wxMenuItem*> items_decrease;
|
||||
std::vector<wxMenuItem*> items_set_number_of_copies;
|
||||
enum MenuIdentifier {
|
||||
miObjectFFF=0,
|
||||
miObjectSLA
|
||||
};
|
||||
MenuFactory menus;
|
||||
|
||||
// Data
|
||||
Slic3r::DynamicPrintConfig *config; // FIXME: leak?
|
||||
|
@ -1669,7 +1655,6 @@ struct Plater::priv
|
|||
void on_update_geometry(Vec3dsEvent<2>&);
|
||||
void on_3dcanvas_mouse_dragging_finished(SimpleEvent&);
|
||||
|
||||
void update_object_menu();
|
||||
void show_action_buttons(const bool is_ready_to_slice) const;
|
||||
|
||||
// Set the bed shape to a single closed 2D polygon(array of two element arrays),
|
||||
|
@ -1690,12 +1675,11 @@ struct Plater::priv
|
|||
bool can_set_instance_to_object() const;
|
||||
bool can_mirror() const;
|
||||
bool can_reload_from_disk() const;
|
||||
bool can_split(bool to_objects) const;
|
||||
|
||||
void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
|
||||
void generate_thumbnails(ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
|
||||
|
||||
void msw_rescale_object_menu();
|
||||
|
||||
void bring_instance_forward() const;
|
||||
|
||||
// returns the path to project file with the given extension (none if extension == wxEmptyString)
|
||||
|
@ -1712,13 +1696,6 @@ struct Plater::priv
|
|||
bool inside_snapshot_capture() { return m_prevent_snapshots != 0; }
|
||||
bool process_completed_with_error { false };
|
||||
private:
|
||||
bool init_object_menu();
|
||||
bool init_common_menu(wxMenu* menu, const bool is_part = false);
|
||||
bool complit_init_object_menu();
|
||||
bool complit_init_sla_object_menu();
|
||||
bool complit_init_part_menu();
|
||||
|
||||
bool can_split() const;
|
||||
bool layers_height_allowed() const;
|
||||
|
||||
void update_fff_scene();
|
||||
|
@ -1762,7 +1739,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
// These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor.
|
||||
"layer_height", "first_layer_height", "min_layer_height", "max_layer_height",
|
||||
"brim_width", "perimeters", "perimeter_extruder", "fill_density", "infill_extruder", "top_solid_layers",
|
||||
"support_material", "support_material_extruder", "support_material_interface_extruder", "support_material_contact_distance", "raft_layers"
|
||||
"support_material", "support_material_extruder", "support_material_interface_extruder",
|
||||
"support_material_contact_distance", "support_material_bottom_contact_distance", "raft_layers"
|
||||
}))
|
||||
, sidebar(new Sidebar(q))
|
||||
, m_ui_jobs(this)
|
||||
|
@ -1827,7 +1805,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
hsizer->Add(sidebar, 0, wxEXPAND | wxLEFT | wxRIGHT, 0);
|
||||
q->SetSizer(hsizer);
|
||||
|
||||
init_object_menu();
|
||||
menus.init(q);
|
||||
|
||||
// Events:
|
||||
|
||||
|
@ -2723,19 +2701,19 @@ void Plater::priv::split_object()
|
|||
Model new_model = model;
|
||||
ModelObject* current_model_object = new_model.objects[obj_idx];
|
||||
|
||||
if (current_model_object->volumes.size() > 1)
|
||||
{
|
||||
Slic3r::GUI::warning_catcher(q, _L("The selected object can't be split because it contains more than one volume/material."));
|
||||
return;
|
||||
}
|
||||
|
||||
wxBusyCursor wait;
|
||||
ModelObjectPtrs new_objects;
|
||||
current_model_object->split(&new_objects);
|
||||
if (new_objects.size() == 1)
|
||||
Slic3r::GUI::warning_catcher(q, _L("The selected object couldn't be split because it contains only one part."));
|
||||
// #ysFIXME use notification
|
||||
Slic3r::GUI::warning_catcher(q, _L("The selected object couldn't be split because it contains only one solid part."));
|
||||
else
|
||||
{
|
||||
if (current_model_object->volumes.size() != new_objects.size())
|
||||
notification_manager->push_notification(NotificationType::CustomNotification,
|
||||
NotificationManager::NotificationLevel::RegularNotification,
|
||||
_u8L("All non-solid parts (modifiers) was deleted"));
|
||||
|
||||
Plater::TakeSnapshot snapshot(q, _L("Split to Objects"));
|
||||
|
||||
remove(obj_idx);
|
||||
|
@ -3563,6 +3541,7 @@ void Plater::priv::on_slicing_began()
|
|||
{
|
||||
clear_warnings();
|
||||
notification_manager->close_notification_of_type(NotificationType::SlicingComplete);
|
||||
notification_manager->close_notification_of_type(NotificationType::SignDetected);
|
||||
}
|
||||
void Plater::priv::add_warning(const Slic3r::PrintStateBase::Warning& warning, size_t oid)
|
||||
{
|
||||
|
@ -3679,7 +3658,9 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
|||
// If writing to removable drive was scheduled, show notification with eject button
|
||||
if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !has_error) {
|
||||
show_action_buttons(false);
|
||||
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, true);
|
||||
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path,
|
||||
// Don't offer the "Eject" button on ChromeOS, the Linux side has no control over it.
|
||||
platform() != Platform::Linux || platform_flavor() != PlatformFlavor::LinuxOnChromium);
|
||||
wxGetApp().removable_drive_manager()->set_exporting_finished(true);
|
||||
}else if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !has_error)
|
||||
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, false);
|
||||
|
@ -3727,70 +3708,25 @@ void Plater::priv::on_right_click(RBtnEvent& evt)
|
|||
|
||||
wxMenu* menu = nullptr;
|
||||
|
||||
if (obj_idx == -1) // no one or several object are selected
|
||||
{
|
||||
if (obj_idx == -1) { // no one or several object are selected
|
||||
if (evt.data.second) // right button was clicked on empty space
|
||||
menu = &default_menu;
|
||||
menu = menus.default_menu();
|
||||
else
|
||||
{
|
||||
sidebar->obj_list()->show_multi_selection_menu();
|
||||
return;
|
||||
}
|
||||
menu = menus.multi_selection_menu();
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
// If in 3DScene is(are) selected volume(s), but right button was clicked on empty space
|
||||
if (evt.data.second)
|
||||
return;
|
||||
|
||||
int menu_item_convert_unit_position = 11;
|
||||
return;
|
||||
|
||||
if (printer_technology == ptSLA)
|
||||
menu = &sla_object_menu;
|
||||
else
|
||||
{
|
||||
menu = menus.sla_object_menu();
|
||||
else {
|
||||
// show "Object menu" for each one or several FullInstance instead of FullObject
|
||||
const bool is_some_full_instances = get_selection().is_single_full_instance() ||
|
||||
get_selection().is_single_full_object() ||
|
||||
get_selection().is_multiple_full_instance();
|
||||
menu = is_some_full_instances ? &object_menu : &part_menu;
|
||||
if (!is_some_full_instances)
|
||||
menu_item_convert_unit_position = 2;
|
||||
}
|
||||
|
||||
sidebar->obj_list()->append_menu_items_convert_unit(menu, menu_item_convert_unit_position);
|
||||
sidebar->obj_list()->append_menu_item_settings(menu);
|
||||
|
||||
if (printer_technology != ptSLA)
|
||||
sidebar->obj_list()->append_menu_item_change_extruder(menu);
|
||||
|
||||
if (menu != &part_menu)
|
||||
{
|
||||
/* Remove/Prepend "increase/decrease instances" menu items according to the view mode.
|
||||
* Suppress to show those items for a Simple mode
|
||||
*/
|
||||
const MenuIdentifier id = printer_technology == ptSLA ? miObjectSLA : miObjectFFF;
|
||||
if (wxGetApp().get_mode() == comSimple) {
|
||||
if (menu->FindItem(_L("Add instance")) != wxNOT_FOUND)
|
||||
{
|
||||
/* Detach an items from the menu, but don't delete them
|
||||
* so that they can be added back later
|
||||
* (after switching to the Advanced/Expert mode)
|
||||
*/
|
||||
menu->Remove(items_increase[id]);
|
||||
menu->Remove(items_decrease[id]);
|
||||
menu->Remove(items_set_number_of_copies[id]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (menu->FindItem(_L("Add instance")) == wxNOT_FOUND)
|
||||
{
|
||||
// Prepend items to the menu, if those aren't not there
|
||||
menu->Prepend(items_set_number_of_copies[id]);
|
||||
menu->Prepend(items_decrease[id]);
|
||||
menu->Prepend(items_increase[id]);
|
||||
}
|
||||
}
|
||||
menu = is_some_full_instances ? menus.object_menu() : menus.part_menu();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3837,26 +3773,6 @@ void Plater::priv::on_3dcanvas_mouse_dragging_finished(SimpleEvent&)
|
|||
}
|
||||
}
|
||||
|
||||
bool Plater::priv::init_object_menu()
|
||||
{
|
||||
items_increase.reserve(2);
|
||||
items_decrease.reserve(2);
|
||||
items_set_number_of_copies.reserve(2);
|
||||
|
||||
init_common_menu(&object_menu);
|
||||
complit_init_object_menu();
|
||||
|
||||
init_common_menu(&sla_object_menu);
|
||||
complit_init_sla_object_menu();
|
||||
|
||||
init_common_menu(&part_menu, true);
|
||||
complit_init_part_menu();
|
||||
|
||||
sidebar->obj_list()->create_default_popupmenu(&default_menu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
|
||||
{
|
||||
view3D->get_canvas3d()->render_thumbnail(data, w, h, printable_only, parts_only, show_bed, transparent_background);
|
||||
|
@ -3875,12 +3791,6 @@ void Plater::priv::generate_thumbnails(ThumbnailsList& thumbnails, const Vec2ds&
|
|||
}
|
||||
}
|
||||
|
||||
void Plater::priv::msw_rescale_object_menu()
|
||||
{
|
||||
for (MenuWithSeparators* menu : { &object_menu, &sla_object_menu, &part_menu, &default_menu })
|
||||
msw_rescale_menu(dynamic_cast<wxMenu*>(menu));
|
||||
}
|
||||
|
||||
wxString Plater::priv::get_project_filename(const wxString& extension) const
|
||||
{
|
||||
return m_project_filename.empty() ? "" : m_project_filename + extension;
|
||||
|
@ -3909,144 +3819,6 @@ void Plater::priv::set_project_filename(const wxString& filename)
|
|||
wxGetApp().mainframe->add_to_recent_projects(filename);
|
||||
}
|
||||
|
||||
bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/)
|
||||
{
|
||||
if (is_part) {
|
||||
append_menu_item(menu, wxID_ANY, _L("Delete") + "\tDel", _L("Remove the selected object"),
|
||||
[this](wxCommandEvent&) { q->remove_selected(); }, "delete", nullptr, [this]() { return can_delete(); }, q);
|
||||
|
||||
append_menu_item(menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected volumes from disk"),
|
||||
[this](wxCommandEvent&) { q->reload_from_disk(); }, "", menu, [this]() { return can_reload_from_disk(); }, q);
|
||||
|
||||
sidebar->obj_list()->append_menu_item_export_stl(menu);
|
||||
}
|
||||
else {
|
||||
wxMenuItem* item_increase = append_menu_item(menu, wxID_ANY, _L("Add instance") + "\t+", _L("Add one more instance of the selected object"),
|
||||
[this](wxCommandEvent&) { q->increase_instances(); }, "add_copies", nullptr, [this]() { return can_increase_instances(); }, q);
|
||||
wxMenuItem* item_decrease = append_menu_item(menu, wxID_ANY, _L("Remove instance") + "\t-", _L("Remove one instance of the selected object"),
|
||||
[this](wxCommandEvent&) { q->decrease_instances(); }, "remove_copies", nullptr, [this]() { return can_decrease_instances(); }, q);
|
||||
wxMenuItem* item_set_number_of_copies = append_menu_item(menu, wxID_ANY, _L("Set number of instances") + dots, _L("Change the number of instances of the selected object"),
|
||||
[this](wxCommandEvent&) { q->set_number_of_copies(); }, "number_of_copies", nullptr, [this]() { return can_increase_instances(); }, q);
|
||||
append_menu_item(menu, wxID_ANY, _L("Fill bed with instances") + dots, _L("Fill the remaining area of bed with instances of the selected object"),
|
||||
[this](wxCommandEvent&) { q->fill_bed_with_instances(); }, "", nullptr, [this]() { return can_increase_instances(); }, q);
|
||||
|
||||
|
||||
items_increase.push_back(item_increase);
|
||||
items_decrease.push_back(item_decrease);
|
||||
items_set_number_of_copies.push_back(item_set_number_of_copies);
|
||||
|
||||
// Delete menu was moved to be after +/- instace to make it more difficult to be selected by mistake.
|
||||
append_menu_item(menu, wxID_ANY, _L("Delete") + "\tDel", _L("Remove the selected object"),
|
||||
[this](wxCommandEvent&) { q->remove_selected(); }, "delete", nullptr, [this]() { return can_delete(); }, q);
|
||||
|
||||
menu->AppendSeparator();
|
||||
sidebar->obj_list()->append_menu_item_instance_to_object(menu, q);
|
||||
menu->AppendSeparator();
|
||||
|
||||
wxMenuItem* menu_item_printable = sidebar->obj_list()->append_menu_item_printable(menu, q);
|
||||
menu->AppendSeparator();
|
||||
|
||||
append_menu_item(menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected object from disk"),
|
||||
[this](wxCommandEvent&) { reload_from_disk(); }, "", nullptr, [this]() { return can_reload_from_disk(); }, q);
|
||||
|
||||
append_menu_item(menu, wxID_ANY, _L("Export as STL") + dots, _L("Export the selected object as STL file"),
|
||||
[this](wxCommandEvent&) { q->export_stl(false, true); }, "", nullptr,
|
||||
[this]() {
|
||||
const Selection& selection = get_selection();
|
||||
return selection.is_single_full_instance() || selection.is_single_full_object();
|
||||
}, q);
|
||||
|
||||
menu->AppendSeparator();
|
||||
|
||||
// "Scale to print volume" makes a sense just for whole object
|
||||
sidebar->obj_list()->append_menu_item_scale_selection_to_fit_print_volume(menu);
|
||||
|
||||
q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) {
|
||||
const Selection& selection = get_selection();
|
||||
int instance_idx = selection.get_instance_idx();
|
||||
evt.Enable(selection.is_single_full_instance() || selection.is_single_full_object());
|
||||
if (instance_idx != -1)
|
||||
{
|
||||
evt.Check(model.objects[selection.get_object_idx()]->instances[instance_idx]->printable);
|
||||
view3D->set_as_dirty();
|
||||
}
|
||||
}, menu_item_printable->GetId());
|
||||
}
|
||||
|
||||
sidebar->obj_list()->append_menu_item_fix_through_netfabb(menu);
|
||||
|
||||
wxMenu* mirror_menu = new wxMenu();
|
||||
if (mirror_menu == nullptr)
|
||||
return false;
|
||||
|
||||
append_menu_item(mirror_menu, wxID_ANY, _L("Along X axis"), _L("Mirror the selected object along the X axis"),
|
||||
[this](wxCommandEvent&) { mirror(X); }, "mark_X", menu);
|
||||
append_menu_item(mirror_menu, wxID_ANY, _L("Along Y axis"), _L("Mirror the selected object along the Y axis"),
|
||||
[this](wxCommandEvent&) { mirror(Y); }, "mark_Y", menu);
|
||||
append_menu_item(mirror_menu, wxID_ANY, _L("Along Z axis"), _L("Mirror the selected object along the Z axis"),
|
||||
[this](wxCommandEvent&) { mirror(Z); }, "mark_Z", menu);
|
||||
|
||||
append_submenu(menu, mirror_menu, wxID_ANY, _L("Mirror"), _L("Mirror the selected object"), "",
|
||||
[this]() { return can_mirror(); }, q);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Plater::priv::complit_init_object_menu()
|
||||
{
|
||||
wxMenu* split_menu = new wxMenu();
|
||||
if (split_menu == nullptr)
|
||||
return false;
|
||||
|
||||
append_menu_item(split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into individual objects"),
|
||||
[this](wxCommandEvent&) { split_object(); }, "split_object_SMALL", &object_menu, [this]() { return can_split(); }, q);
|
||||
append_menu_item(split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into individual sub-parts"),
|
||||
[this](wxCommandEvent&) { split_volume(); }, "split_parts_SMALL", &object_menu, [this]() { return can_split(); }, q);
|
||||
|
||||
append_submenu(&object_menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "",
|
||||
[this]() { return can_split() && wxGetApp().get_mode() > comSimple; }, q);
|
||||
object_menu.AppendSeparator();
|
||||
|
||||
// Layers Editing for object
|
||||
sidebar->obj_list()->append_menu_item_layers_editing(&object_menu, q);
|
||||
object_menu.AppendSeparator();
|
||||
|
||||
// "Add (volumes)" popupmenu will be added later in append_menu_items_add_volume()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Plater::priv::complit_init_sla_object_menu()
|
||||
{
|
||||
append_menu_item(&sla_object_menu, wxID_ANY, _L("Split"), _L("Split the selected object into individual objects"),
|
||||
[this](wxCommandEvent&) { split_object(); }, "split_object_SMALL", nullptr, [this]() { return can_split(); }, q);
|
||||
|
||||
sla_object_menu.AppendSeparator();
|
||||
|
||||
// Add the automatic rotation sub-menu
|
||||
append_menu_item(
|
||||
&sla_object_menu, wxID_ANY, _(L("Optimize orientation")),
|
||||
_(L("Optimize the rotation of the object for better print results.")),
|
||||
[this](wxCommandEvent &) {
|
||||
m_ui_jobs.optimize_rotation();
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Plater::priv::complit_init_part_menu()
|
||||
{
|
||||
append_menu_item(&part_menu, wxID_ANY, _L("Split"), _L("Split the selected object into individual sub-parts"),
|
||||
[this](wxCommandEvent&) { split_volume(); }, "split_parts_SMALL", nullptr, [this]() { return can_split(); }, q);
|
||||
|
||||
part_menu.AppendSeparator();
|
||||
|
||||
auto obj_list = sidebar->obj_list();
|
||||
obj_list->append_menu_item_change_type(&part_menu, q);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Plater::priv::set_current_canvas_as_dirty()
|
||||
{
|
||||
if (current_panel == view3D)
|
||||
|
@ -4196,9 +3968,9 @@ bool Plater::priv::can_set_instance_to_object() const
|
|||
return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && (model.objects[obj_idx]->instances.size() > 1);
|
||||
}
|
||||
|
||||
bool Plater::priv::can_split() const
|
||||
bool Plater::priv::can_split(bool to_objects) const
|
||||
{
|
||||
return sidebar->obj_list()->is_splittable();
|
||||
return sidebar->obj_list()->is_splittable(to_objects);
|
||||
}
|
||||
|
||||
bool Plater::priv::layers_height_allowed() const
|
||||
|
@ -4314,12 +4086,12 @@ bool Plater::priv::can_decrease_instances() const
|
|||
|
||||
bool Plater::priv::can_split_to_objects() const
|
||||
{
|
||||
return can_split();
|
||||
return q->can_split(true);
|
||||
}
|
||||
|
||||
bool Plater::priv::can_split_to_volumes() const
|
||||
{
|
||||
return (printer_technology != ptSLA) && can_split();
|
||||
return (printer_technology != ptSLA) && q->can_split(false);
|
||||
}
|
||||
|
||||
bool Plater::priv::can_arrange() const
|
||||
|
@ -4332,11 +4104,6 @@ bool Plater::priv::can_layers_editing() const
|
|||
return layers_height_allowed();
|
||||
}
|
||||
|
||||
void Plater::priv::update_object_menu()
|
||||
{
|
||||
sidebar->obj_list()->append_menu_items_add_volume(&object_menu);
|
||||
}
|
||||
|
||||
void Plater::priv::show_action_buttons(const bool ready_to_slice) const
|
||||
{
|
||||
// Cache this value, so that the callbacks from the RemovableDriveManager may repeat that value when calling show_action_buttons().
|
||||
|
@ -5363,7 +5130,7 @@ void Plater::export_stl(bool extended, bool selection_only)
|
|||
inst_mesh.merge(inst_supports_mesh);
|
||||
}
|
||||
|
||||
TriangleMesh inst_object_mesh = object->get_mesh_to_print();
|
||||
TriangleMesh inst_object_mesh = object->get_mesh_to_slice();
|
||||
inst_object_mesh.transform(mesh_trafo_inv);
|
||||
inst_object_mesh.transform(inst_transform, is_left_handed);
|
||||
|
||||
|
@ -6056,9 +5823,12 @@ void Plater::suppress_background_process(const bool stop_background_process)
|
|||
}
|
||||
|
||||
void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) { p->fix_through_netfabb(obj_idx, vol_idx); }
|
||||
|
||||
void Plater::update_object_menu() { p->update_object_menu(); }
|
||||
void Plater::show_action_buttons(const bool ready_to_slice) const { p->show_action_buttons(ready_to_slice); }
|
||||
void Plater::mirror(Axis axis) { p->mirror(axis); }
|
||||
void Plater::split_object() { p->split_object(); }
|
||||
void Plater::split_volume() { p->split_volume(); }
|
||||
void Plater::optimize_rotation() { p->m_ui_jobs.optimize_rotation();}
|
||||
void Plater::update_object_menu() { p->menus.update_object_menu(); }
|
||||
void Plater::show_action_buttons(const bool ready_to_slice) const { p->show_action_buttons(ready_to_slice); }
|
||||
|
||||
void Plater::copy_selection_to_clipboard()
|
||||
{
|
||||
|
@ -6115,7 +5885,7 @@ void Plater::msw_rescale()
|
|||
|
||||
p->sidebar->msw_rescale();
|
||||
|
||||
p->msw_rescale_object_menu();
|
||||
p->menus.msw_rescale();
|
||||
|
||||
Layout();
|
||||
GetParent()->Layout();
|
||||
|
@ -6127,7 +5897,7 @@ void Plater::sys_color_changed()
|
|||
p->sidebar->sys_color_changed();
|
||||
|
||||
// msw_rescale_menu updates just icons, so use it
|
||||
p->msw_rescale_object_menu();
|
||||
p->menus.msw_rescale();
|
||||
|
||||
Layout();
|
||||
GetParent()->Layout();
|
||||
|
@ -6292,6 +6062,8 @@ bool Plater::can_copy_to_clipboard() const
|
|||
bool Plater::can_undo() const { return p->undo_redo_stack().has_undo_snapshot(); }
|
||||
bool Plater::can_redo() const { return p->undo_redo_stack().has_redo_snapshot(); }
|
||||
bool Plater::can_reload_from_disk() const { return p->can_reload_from_disk(); }
|
||||
bool Plater::can_mirror() const { return p->can_mirror(); }
|
||||
bool Plater::can_split(bool to_objects) const { return p->can_split(to_objects); }
|
||||
const UndoRedo::Stack& Plater::undo_redo_stack_main() const { return p->undo_redo_stack_main(); }
|
||||
void Plater::clear_undo_redo_stack_main() { p->undo_redo_stack_main().clear(); }
|
||||
void Plater::enter_gizmos_stack() { p->enter_gizmos_stack(); }
|
||||
|
@ -6333,6 +6105,15 @@ void Plater::bring_instance_forward()
|
|||
p->bring_instance_forward();
|
||||
}
|
||||
|
||||
wxMenu* Plater::object_menu() { return p->menus.object_menu(); }
|
||||
wxMenu* Plater::part_menu() { return p->menus.part_menu(); }
|
||||
wxMenu* Plater::sla_object_menu() { return p->menus.sla_object_menu(); }
|
||||
wxMenu* Plater::default_menu() { return p->menus.default_menu(); }
|
||||
wxMenu* Plater::instance_menu() { return p->menus.instance_menu(); }
|
||||
wxMenu* Plater::layer_menu() { return p->menus.layer_menu(); }
|
||||
wxMenu* Plater::multi_selection_menu() { return p->menus.multi_selection_menu(); }
|
||||
|
||||
|
||||
SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
|
||||
m_was_scheduled(wxGetApp().plater()->is_background_process_update_scheduled())
|
||||
{
|
||||
|
|
|
@ -271,6 +271,10 @@ public:
|
|||
void copy_selection_to_clipboard();
|
||||
void paste_from_clipboard();
|
||||
void search(bool plater_is_active);
|
||||
void mirror(Axis axis);
|
||||
void split_object();
|
||||
void split_volume();
|
||||
void optimize_rotation();
|
||||
|
||||
bool can_delete() const;
|
||||
bool can_delete_all() const;
|
||||
|
@ -287,6 +291,8 @@ public:
|
|||
bool can_undo() const;
|
||||
bool can_redo() const;
|
||||
bool can_reload_from_disk() const;
|
||||
bool can_mirror() const;
|
||||
bool can_split(bool to_objects) const;
|
||||
|
||||
void msw_rescale();
|
||||
void sys_color_changed();
|
||||
|
@ -375,6 +381,15 @@ public:
|
|||
bool PopupMenu(wxMenu *menu, const wxPoint& pos = wxDefaultPosition);
|
||||
bool PopupMenu(wxMenu *menu, int x, int y) { return this->PopupMenu(menu, wxPoint(x, y)); }
|
||||
|
||||
// get same Plater/ObjectList menus
|
||||
wxMenu* object_menu();
|
||||
wxMenu* part_menu();
|
||||
wxMenu* sla_object_menu();
|
||||
wxMenu* default_menu();
|
||||
wxMenu* instance_menu();
|
||||
wxMenu* layer_menu();
|
||||
wxMenu* multi_selection_menu();
|
||||
|
||||
private:
|
||||
struct priv;
|
||||
std::unique_ptr<priv> p;
|
||||
|
|
|
@ -148,74 +148,33 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
|
|||
speed_normal = first_layer_speed.get_abs_value(speed_normal);
|
||||
return (speed_normal > 0.) ? speed_normal : speed_max;
|
||||
};
|
||||
auto test_flow =
|
||||
[first_layer_extrusion_width_ptr, extrusion_width, nozzle_diameter, lh, bridging, bridge_speed, bridge_flow_ratio, limit_by_first_layer_speed, max_print_speed, &max_flow, &max_flow_extrusion_type]
|
||||
(FlowRole flow_role, const ConfigOptionFloatOrPercent &this_extrusion_width, double speed, const char *err_msg) {
|
||||
Flow flow = bridging ?
|
||||
Flow::new_from_config_width(flow_role, first_positive(first_layer_extrusion_width_ptr, this_extrusion_width, extrusion_width), nozzle_diameter, lh) :
|
||||
Flow::bridging_flow(nozzle_diameter * bridge_flow_ratio, nozzle_diameter);
|
||||
double volumetric_flow = flow.mm3_per_mm() * (bridging ? bridge_speed : limit_by_first_layer_speed(speed, max_print_speed));
|
||||
if (max_flow < volumetric_flow) {
|
||||
max_flow = volumetric_flow;
|
||||
max_flow_extrusion_type = _utf8(err_msg);
|
||||
}
|
||||
};
|
||||
if (perimeter_extruder_active) {
|
||||
double external_perimeter_rate = Flow::new_from_config_width(frExternalPerimeter,
|
||||
first_positive(first_layer_extrusion_width_ptr, external_perimeter_extrusion_width, extrusion_width),
|
||||
nozzle_diameter, lh, bfr).mm3_per_mm() *
|
||||
(bridging ? bridge_speed :
|
||||
limit_by_first_layer_speed(std::max(external_perimeter_speed, small_perimeter_speed), max_print_speed));
|
||||
if (max_flow < external_perimeter_rate) {
|
||||
max_flow = external_perimeter_rate;
|
||||
max_flow_extrusion_type = _utf8(L("external perimeters"));
|
||||
}
|
||||
double perimeter_rate = Flow::new_from_config_width(frPerimeter,
|
||||
first_positive(first_layer_extrusion_width_ptr, perimeter_extrusion_width, extrusion_width),
|
||||
nozzle_diameter, lh, bfr).mm3_per_mm() *
|
||||
(bridging ? bridge_speed :
|
||||
limit_by_first_layer_speed(std::max(perimeter_speed, small_perimeter_speed), max_print_speed));
|
||||
if (max_flow < perimeter_rate) {
|
||||
max_flow = perimeter_rate;
|
||||
max_flow_extrusion_type = _utf8(L("perimeters"));
|
||||
}
|
||||
}
|
||||
if (! bridging && infill_extruder_active) {
|
||||
double infill_rate = Flow::new_from_config_width(frInfill,
|
||||
first_positive(first_layer_extrusion_width_ptr, infill_extrusion_width, extrusion_width),
|
||||
nozzle_diameter, lh, bfr).mm3_per_mm() * limit_by_first_layer_speed(infill_speed, max_print_speed);
|
||||
if (max_flow < infill_rate) {
|
||||
max_flow = infill_rate;
|
||||
max_flow_extrusion_type = _utf8(L("infill"));
|
||||
}
|
||||
test_flow(frExternalPerimeter, external_perimeter_extrusion_width, std::max(external_perimeter_speed, small_perimeter_speed), L("external perimeters"));
|
||||
test_flow(frPerimeter, perimeter_extrusion_width, std::max(perimeter_speed, small_perimeter_speed), L("perimeters"));
|
||||
}
|
||||
if (! bridging && infill_extruder_active)
|
||||
test_flow(frInfill, infill_extrusion_width, infill_speed, L("infill"));
|
||||
if (solid_infill_extruder_active) {
|
||||
double solid_infill_rate = Flow::new_from_config_width(frInfill,
|
||||
first_positive(first_layer_extrusion_width_ptr, solid_infill_extrusion_width, extrusion_width),
|
||||
nozzle_diameter, lh, 0).mm3_per_mm() *
|
||||
(bridging ? bridge_speed : limit_by_first_layer_speed(solid_infill_speed, max_print_speed));
|
||||
if (max_flow < solid_infill_rate) {
|
||||
max_flow = solid_infill_rate;
|
||||
max_flow_extrusion_type = _utf8(L("solid infill"));
|
||||
}
|
||||
if (! bridging) {
|
||||
double top_solid_infill_rate = Flow::new_from_config_width(frInfill,
|
||||
first_positive(first_layer_extrusion_width_ptr, top_infill_extrusion_width, extrusion_width),
|
||||
nozzle_diameter, lh, bfr).mm3_per_mm() * limit_by_first_layer_speed(top_solid_infill_speed, max_print_speed);
|
||||
if (max_flow < top_solid_infill_rate) {
|
||||
max_flow = top_solid_infill_rate;
|
||||
max_flow_extrusion_type = _utf8(L("top solid infill"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (support_material_extruder_active) {
|
||||
double support_material_rate = Flow::new_from_config_width(frSupportMaterial,
|
||||
first_positive(first_layer_extrusion_width_ptr, support_material_extrusion_width, extrusion_width),
|
||||
nozzle_diameter, lh, bfr).mm3_per_mm() *
|
||||
(bridging ? bridge_speed : limit_by_first_layer_speed(support_material_speed, max_print_speed));
|
||||
if (max_flow < support_material_rate) {
|
||||
max_flow = support_material_rate;
|
||||
max_flow_extrusion_type = _utf8(L("support"));
|
||||
}
|
||||
}
|
||||
if (support_material_interface_extruder_active) {
|
||||
double support_material_interface_rate = Flow::new_from_config_width(frSupportMaterialInterface,
|
||||
first_positive(first_layer_extrusion_width_ptr, support_material_extrusion_width, extrusion_width),
|
||||
nozzle_diameter, lh, bfr).mm3_per_mm() *
|
||||
(bridging ? bridge_speed : limit_by_first_layer_speed(support_material_interface_speed, max_print_speed));
|
||||
if (max_flow < support_material_interface_rate) {
|
||||
max_flow = support_material_interface_rate;
|
||||
max_flow_extrusion_type = _utf8(L("support interface"));
|
||||
}
|
||||
test_flow(frInfill, solid_infill_extrusion_width, solid_infill_speed, L("solid infill"));
|
||||
if (! bridging)
|
||||
test_flow(frInfill, top_infill_extrusion_width, top_solid_infill_speed, L("top solid infill"));
|
||||
}
|
||||
if (! bridging && support_material_extruder_active)
|
||||
test_flow(frSupportMaterial, support_material_extrusion_width, support_material_speed, L("support"));
|
||||
if (support_material_interface_extruder_active)
|
||||
test_flow(frSupportMaterialInterface, support_material_extrusion_width, support_material_interface_speed, L("support interface"));
|
||||
//FIXME handle gap_fill_speed
|
||||
if (! out.empty())
|
||||
out += "\n";
|
||||
|
@ -254,11 +213,11 @@ std::string PresetHints::recommended_thin_wall_thickness(const PresetBundle &pre
|
|||
Flow external_perimeter_flow = Flow::new_from_config_width(
|
||||
frExternalPerimeter,
|
||||
*print_config.opt<ConfigOptionFloatOrPercent>("external_perimeter_extrusion_width"),
|
||||
nozzle_diameter, layer_height, false);
|
||||
nozzle_diameter, layer_height);
|
||||
Flow perimeter_flow = Flow::new_from_config_width(
|
||||
frPerimeter,
|
||||
*print_config.opt<ConfigOptionFloatOrPercent>("perimeter_extrusion_width"),
|
||||
nozzle_diameter, layer_height, false);
|
||||
nozzle_diameter, layer_height);
|
||||
|
||||
|
||||
if (num_perimeters > 0) {
|
||||
|
@ -266,7 +225,7 @@ std::string PresetHints::recommended_thin_wall_thickness(const PresetBundle &pre
|
|||
out += (boost::format(_utf8(L("Recommended object thin wall thickness for layer height %.2f and"))) % layer_height).str() + " ";
|
||||
// Start with the width of two closely spaced
|
||||
try {
|
||||
double width = external_perimeter_flow.width + external_perimeter_flow.spacing();
|
||||
double width = external_perimeter_flow.width() + external_perimeter_flow.spacing();
|
||||
for (int i = 2; i <= num_lines; thin_walls ? ++ i : i += 2) {
|
||||
if (i > 2)
|
||||
out += ", ";
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "PrintHostDialogs.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
|
||||
#include <wx/frame.h>
|
||||
#include <wx/progdlg.h>
|
||||
|
@ -13,14 +14,18 @@
|
|||
#include <wx/wupdlock.h>
|
||||
#include <wx/debug.h>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
|
||||
#include "GUI.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "../Utils/PrintHost.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "NotificationManager.hpp"
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
|
@ -182,15 +187,24 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent)
|
|||
|
||||
auto *topsizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
std::vector<int> widths;
|
||||
widths.reserve(6);
|
||||
if (!load_user_data(UDT_COLS, widths)) {
|
||||
widths.clear();
|
||||
for (size_t i = 0; i < 6; i++)
|
||||
widths.push_back(-1);
|
||||
}
|
||||
|
||||
job_list = new wxDataViewListCtrl(this, wxID_ANY);
|
||||
// Note: Keep these in sync with Column
|
||||
job_list->AppendTextColumn(_L("ID"), wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendProgressColumn(_L("Progress"), wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendTextColumn(_L("Status"), wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendTextColumn(_L("Host"), wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendTextColumn(_L("Filename"), wxDATAVIEW_CELL_INERT);
|
||||
job_list->AppendTextColumn(_L("ID"), wxDATAVIEW_CELL_INERT, widths[0], wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
|
||||
job_list->AppendProgressColumn(_L("Progress"), wxDATAVIEW_CELL_INERT, widths[1], wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
|
||||
job_list->AppendTextColumn(_L("Status"), wxDATAVIEW_CELL_INERT, widths[2], wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
|
||||
job_list->AppendTextColumn(_L("Host"), wxDATAVIEW_CELL_INERT, widths[3], wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
|
||||
job_list->AppendTextColumn(_CTX_utf8(L_CONTEXT("Size", "OfFile"), "OfFile"), wxDATAVIEW_CELL_INERT, widths[4], wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
|
||||
job_list->AppendTextColumn(_L("Filename"), wxDATAVIEW_CELL_INERT, widths[5], wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
|
||||
job_list->AppendTextColumn(_L("Error Message"), wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER, wxDATAVIEW_COL_HIDDEN);
|
||||
|
||||
|
||||
auto *btnsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
btn_cancel = new wxButton(this, wxID_DELETE, _L("Cancel selected"));
|
||||
btn_cancel->Disable();
|
||||
|
@ -207,7 +221,21 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent)
|
|||
topsizer->Add(btnsizer, 0, wxEXPAND);
|
||||
SetSizer(topsizer);
|
||||
|
||||
SetSize(wxSize(HEIGHT * em, WIDTH * em));
|
||||
std::vector<int> size;
|
||||
SetSize(load_user_data(UDT_SIZE, size) ? wxSize(size[0] * em, size[1] * em) : wxSize(HEIGHT * em, WIDTH * em));
|
||||
|
||||
Bind(wxEVT_SIZE, [this, em](wxSizeEvent& evt) {
|
||||
OnSize(evt);
|
||||
save_user_data(UDT_SIZE | UDT_POSITION | UDT_COLS);
|
||||
});
|
||||
|
||||
std::vector<int> pos;
|
||||
if (load_user_data(UDT_POSITION, pos))
|
||||
SetPosition(wxPoint(pos[0], pos[1]));
|
||||
|
||||
Bind(wxEVT_MOVE, [this, em](wxMoveEvent& evt) {
|
||||
save_user_data(UDT_SIZE | UDT_POSITION | UDT_COLS);
|
||||
});
|
||||
|
||||
job_list->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxDataViewEvent&) { on_list_select(); });
|
||||
|
||||
|
@ -238,11 +266,23 @@ void PrintHostQueueDialog::append_job(const PrintHostJob &job)
|
|||
fields.push_back(wxVariant(0));
|
||||
fields.push_back(wxVariant(_L("Enqueued")));
|
||||
fields.push_back(wxVariant(job.printhost->get_host()));
|
||||
boost::system::error_code ec;
|
||||
boost::uintmax_t size_i = boost::filesystem::file_size(job.upload_data.source_path, ec);
|
||||
std::stringstream stream;
|
||||
if (ec) {
|
||||
stream << "unknown";
|
||||
size_i = 0;
|
||||
BOOST_LOG_TRIVIAL(error) << ec.message();
|
||||
} else
|
||||
stream << std::fixed << std::setprecision(2) << ((float)size_i / 1024 / 1024) << "MB";
|
||||
fields.push_back(wxVariant(stream.str()));
|
||||
fields.push_back(wxVariant(job.upload_data.upload_path.string()));
|
||||
fields.push_back(wxVariant(""));
|
||||
job_list->AppendItem(fields, static_cast<wxUIntPtr>(ST_NEW));
|
||||
// Both strings are UTF-8 encoded.
|
||||
upload_names.emplace_back(job.printhost->get_host(), job.upload_data.upload_path.string());
|
||||
|
||||
//wxGetApp().notification_manager()->push_upload_job_notification(this, job_list->GetItemCount(), 0, job.upload_data.upload_path.string(), job.printhost->get_host());
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::on_dpi_changed(const wxRect &suggested_rect)
|
||||
|
@ -255,6 +295,8 @@ void PrintHostQueueDialog::on_dpi_changed(const wxRect &suggested_rect)
|
|||
|
||||
Fit();
|
||||
Refresh();
|
||||
|
||||
save_user_data(UDT_SIZE | UDT_POSITION | UDT_COLS);
|
||||
}
|
||||
|
||||
PrintHostQueueDialog::JobState PrintHostQueueDialog::get_state(int idx)
|
||||
|
@ -276,6 +318,8 @@ void PrintHostQueueDialog::set_state(int idx, JobState state)
|
|||
case ST_CANCELLED: job_list->SetValue(_L("Cancelled"), idx, COL_STATUS); break;
|
||||
case ST_COMPLETED: job_list->SetValue(_L("Completed"), idx, COL_STATUS); break;
|
||||
}
|
||||
// This might be ambigous call, but user data needs to be saved time to time
|
||||
save_user_data(UDT_SIZE | UDT_POSITION | UDT_COLS);
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::on_list_select()
|
||||
|
@ -304,6 +348,14 @@ void PrintHostQueueDialog::on_progress(Event &evt)
|
|||
}
|
||||
|
||||
on_list_select();
|
||||
|
||||
if (evt.progress > 0)
|
||||
{
|
||||
wxVariant nm, hst;
|
||||
job_list->GetValue(nm, evt.job_id, COL_FILENAME);
|
||||
job_list->GetValue(hst, evt.job_id, COL_HOST);
|
||||
wxGetApp().notification_manager()->set_upload_job_notification_percentage(evt.job_id + 1, boost::nowide::narrow(nm.GetString()), boost::nowide::narrow(hst.GetString()), 100 / evt.progress);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::on_error(Event &evt)
|
||||
|
@ -319,6 +371,11 @@ void PrintHostQueueDialog::on_error(Event &evt)
|
|||
on_list_select();
|
||||
|
||||
GUI::show_error(nullptr, errormsg);
|
||||
|
||||
wxVariant nm, hst;
|
||||
job_list->GetValue(nm, evt.job_id, COL_FILENAME);
|
||||
job_list->GetValue(hst, evt.job_id, COL_HOST);
|
||||
wxGetApp().notification_manager()->upload_job_notification_show_error(evt.job_id + 1, boost::nowide::narrow(nm.GetString()), boost::nowide::narrow(hst.GetString()));
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::on_cancel(Event &evt)
|
||||
|
@ -329,7 +386,13 @@ void PrintHostQueueDialog::on_cancel(Event &evt)
|
|||
job_list->SetValue(wxVariant(0), evt.job_id, COL_PROGRESS);
|
||||
|
||||
on_list_select();
|
||||
|
||||
wxVariant nm, hst;
|
||||
job_list->GetValue(nm, evt.job_id, COL_FILENAME);
|
||||
job_list->GetValue(hst, evt.job_id, COL_HOST);
|
||||
wxGetApp().notification_manager()->upload_job_notification_show_canceled(evt.job_id + 1, boost::nowide::narrow(nm.GetString()), boost::nowide::narrow(hst.GetString()));
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::get_active_jobs(std::vector<std::pair<std::string, std::string>>& ret)
|
||||
{
|
||||
int ic = job_list->GetItemCount();
|
||||
|
@ -343,4 +406,60 @@ void PrintHostQueueDialog::get_active_jobs(std::vector<std::pair<std::string, st
|
|||
}
|
||||
//job_list->data
|
||||
}
|
||||
void PrintHostQueueDialog::save_user_data(int udt)
|
||||
{
|
||||
const auto em = GetTextExtent("m").x;
|
||||
BOOST_LOG_TRIVIAL(error) << "save" << this->GetSize().x / em << " " << this->GetSize().y / em << " " << this->GetPosition().x << " " << this->GetPosition().y;
|
||||
auto *app_config = wxGetApp().app_config;
|
||||
if (udt & UserDataType::UDT_SIZE) {
|
||||
|
||||
app_config->set("print_host_queue_dialog_height", std::to_string(this->GetSize().x / em));
|
||||
app_config->set("print_host_queue_dialog_width", std::to_string(this->GetSize().y / em));
|
||||
}
|
||||
if (udt & UserDataType::UDT_POSITION)
|
||||
{
|
||||
app_config->set("print_host_queue_dialog_x", std::to_string(this->GetPosition().x));
|
||||
app_config->set("print_host_queue_dialog_y", std::to_string(this->GetPosition().y));
|
||||
}
|
||||
if (udt & UserDataType::UDT_COLS)
|
||||
{
|
||||
for (size_t i = 0; i < job_list->GetColumnCount() - 1; i++)
|
||||
{
|
||||
app_config->set("print_host_queue_dialog_column_" + std::to_string(i), std::to_string(job_list->GetColumn(i)->GetWidth()));
|
||||
}
|
||||
}
|
||||
}
|
||||
bool PrintHostQueueDialog::load_user_data(int udt, std::vector<int>& vector)
|
||||
{
|
||||
auto* app_config = wxGetApp().app_config;
|
||||
auto hasget = [app_config](const std::string& name, std::vector<int>& vector)->bool {
|
||||
if (app_config->has(name)) {
|
||||
vector.push_back(std::stoi(app_config->get(name)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (udt & UserDataType::UDT_SIZE) {
|
||||
if (!hasget("print_host_queue_dialog_height",vector))
|
||||
return false;
|
||||
if (!hasget("print_host_queue_dialog_width", vector))
|
||||
return false;
|
||||
}
|
||||
if (udt & UserDataType::UDT_POSITION)
|
||||
{
|
||||
if (!hasget("print_host_queue_dialog_x", vector))
|
||||
return false;
|
||||
if (!hasget("print_host_queue_dialog_y", vector))
|
||||
return false;
|
||||
}
|
||||
if (udt & UserDataType::UDT_COLS)
|
||||
{
|
||||
for (size_t i = 0; i < 6; i++)
|
||||
{
|
||||
if (!hasget("print_host_queue_dialog_column_" + std::to_string(i), vector))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}}
|
||||
|
|
|
@ -8,10 +8,8 @@
|
|||
#include <wx/event.h>
|
||||
#include <wx/dialog.h>
|
||||
|
||||
#include "GUI.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "../Utils/PrintHost.hpp"
|
||||
|
||||
class wxButton;
|
||||
class wxTextCtrl;
|
||||
|
@ -65,6 +63,13 @@ public:
|
|||
|
||||
void append_job(const PrintHostJob &job);
|
||||
void get_active_jobs(std::vector<std::pair<std::string, std::string>>& ret);
|
||||
|
||||
virtual bool Show(bool show = true) override
|
||||
{
|
||||
if(!show)
|
||||
save_user_data(UDT_SIZE | UDT_POSITION | UDT_COLS);
|
||||
return DPIDialog::Show(show);
|
||||
}
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
|
||||
|
@ -74,8 +79,9 @@ private:
|
|||
COL_PROGRESS,
|
||||
COL_STATUS,
|
||||
COL_HOST,
|
||||
COL_SIZE,
|
||||
COL_FILENAME,
|
||||
COL_ERRORMSG,
|
||||
COL_ERRORMSG
|
||||
};
|
||||
|
||||
enum JobState {
|
||||
|
@ -89,6 +95,12 @@ private:
|
|||
|
||||
enum { HEIGHT = 60, WIDTH = 30, SPACING = 5 };
|
||||
|
||||
enum UserDataType{
|
||||
UDT_SIZE = 1,
|
||||
UDT_POSITION = 2,
|
||||
UDT_COLS = 4
|
||||
};
|
||||
|
||||
wxButton *btn_cancel;
|
||||
wxButton *btn_error;
|
||||
wxDataViewListCtrl *job_list;
|
||||
|
@ -105,6 +117,8 @@ private:
|
|||
void on_cancel(Event&);
|
||||
// This vector keep adress and filename of uploads. It is used when checking for running uploads during exit.
|
||||
std::vector<std::pair<std::string, std::string>> upload_names;
|
||||
void save_user_data(int);
|
||||
bool load_user_data(int, std::vector<int>&);
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT(EVT_PRINTHOST_PROGRESS, PrintHostQueueDialog::Event);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "RemovableDriveManager.hpp"
|
||||
#include "slic3r/Utils/Platform.hpp"
|
||||
#include <libslic3r/libslic3r.h>
|
||||
|
||||
#include <boost/nowide/convert.hpp>
|
||||
|
@ -231,22 +232,28 @@ std::vector<DriveData> RemovableDriveManager::search_for_removable_drives() cons
|
|||
|
||||
#else
|
||||
|
||||
//search /media/* folder
|
||||
search_for_drives_internal::search_path("/media/*", "/media", current_drives);
|
||||
if (platform() == Platform::Linux && platform_flavor() == PlatformFlavor::LinuxOnChromium) {
|
||||
// ChromeOS specific: search /mnt/chromeos/removable/* folder
|
||||
search_for_drives_internal::search_path("/mnt/chromeos/removable/*", "/mnt/chromeos/removable", current_drives);
|
||||
} else {
|
||||
//search /media/* folder
|
||||
search_for_drives_internal::search_path("/media/*", "/media", current_drives);
|
||||
|
||||
//search_path("/Volumes/*", "/Volumes");
|
||||
std::string path(std::getenv("USER"));
|
||||
std::string pp(path);
|
||||
//search_path("/Volumes/*", "/Volumes");
|
||||
std::string path(std::getenv("USER"));
|
||||
std::string pp(path);
|
||||
|
||||
//search /media/USERNAME/* folder
|
||||
pp = "/media/"+pp;
|
||||
path = "/media/" + path + "/*";
|
||||
search_for_drives_internal::search_path(path, pp, current_drives);
|
||||
//search /media/USERNAME/* folder
|
||||
pp = "/media/"+pp;
|
||||
path = "/media/" + path + "/*";
|
||||
search_for_drives_internal::search_path(path, pp, current_drives);
|
||||
|
||||
//search /run/media/USERNAME/* folder
|
||||
path = "/run" + path;
|
||||
pp = "/run"+pp;
|
||||
search_for_drives_internal::search_path(path, pp, current_drives);
|
||||
}
|
||||
|
||||
//search /run/media/USERNAME/* folder
|
||||
path = "/run" + path;
|
||||
pp = "/run"+pp;
|
||||
search_for_drives_internal::search_path(path, pp, current_drives);
|
||||
#endif
|
||||
|
||||
return current_drives;
|
||||
|
@ -443,7 +450,10 @@ RemovableDriveManager::RemovableDrivesStatus RemovableDriveManager::status()
|
|||
RemovableDriveManager::RemovableDrivesStatus out;
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_drives_mutex);
|
||||
out.has_eject = this->find_last_save_path_drive_data() != m_current_drives.end();
|
||||
out.has_eject =
|
||||
// Cannot control eject on Chromium.
|
||||
(platform() != Platform::Linux || platform_flavor() != PlatformFlavor::LinuxOnChromium) &&
|
||||
this->find_last_save_path_drive_data() != m_current_drives.end();
|
||||
out.has_removable_drives = ! m_current_drives.empty();
|
||||
}
|
||||
if (! out.has_eject)
|
||||
|
|
|
@ -1433,6 +1433,7 @@ void TabPrint::build()
|
|||
optgroup->append_single_option_line("avoid_crossing_perimeters", category_path + "avoid-crossing-perimeters");
|
||||
optgroup->append_single_option_line("avoid_crossing_perimeters_max_detour", category_path + "avoid_crossing_perimeters_max_detour");
|
||||
optgroup->append_single_option_line("thin_walls", category_path + "detect-thin-walls");
|
||||
optgroup->append_single_option_line("thick_bridges", category_path + "thick_bridges");
|
||||
optgroup->append_single_option_line("overhangs", category_path + "detect-bridging-perimeters");
|
||||
|
||||
optgroup = page->new_optgroup(L("Advanced"));
|
||||
|
@ -1506,11 +1507,13 @@ void TabPrint::build()
|
|||
|
||||
optgroup = page->new_optgroup(L("Options for support material and raft"));
|
||||
optgroup->append_single_option_line("support_material_contact_distance", category_path + "contact-z-distance");
|
||||
optgroup->append_single_option_line("support_material_bottom_contact_distance", category_path + "contact-z-distance");
|
||||
optgroup->append_single_option_line("support_material_pattern", category_path + "pattern");
|
||||
optgroup->append_single_option_line("support_material_with_sheath", category_path + "with-sheath-around-the-support");
|
||||
optgroup->append_single_option_line("support_material_spacing", category_path + "pattern-spacing-0-inf");
|
||||
optgroup->append_single_option_line("support_material_angle", category_path + "pattern-angle");
|
||||
optgroup->append_single_option_line("support_material_interface_layers", category_path + "interface-layers");
|
||||
optgroup->append_single_option_line("support_material_bottom_interface_layers", category_path + "interface-layers");
|
||||
optgroup->append_single_option_line("support_material_interface_pattern", category_path + "interface-pattern");
|
||||
optgroup->append_single_option_line("support_material_interface_spacing", category_path + "interface-pattern-spacing");
|
||||
optgroup->append_single_option_line("support_material_interface_contact_loops", category_path + "interface-loops");
|
||||
|
@ -2528,7 +2531,7 @@ PageShp TabPrinter::build_kinematics_page()
|
|||
ConfigOptionDef def;
|
||||
def.type = coString;
|
||||
def.width = Field::def_width();
|
||||
def.gui_type = "legend";
|
||||
def.gui_type = ConfigOptionDef::GUIType::legend;
|
||||
def.mode = comAdvanced;
|
||||
def.tooltip = L("Values in this column are for Normal mode");
|
||||
def.set_default_value(new ConfigOptionString{ _(L("Normal")).ToUTF8().data() });
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue