mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-15 11:51:33 +00:00
Merge remote-tracking branch 'upstream/main' into feedback
This commit is contained in:
@@ -301,6 +301,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/KBShortcutsDialog.hpp
|
||||
GUI/LibVGCode/LibVGCodeWrapper.hpp
|
||||
GUI/LibVGCode/LibVGCodeWrapper.cpp
|
||||
GUI/LinuxDisplayBackend.cpp
|
||||
GUI/LinuxDisplayBackend.hpp
|
||||
GUI/MainFrame.cpp
|
||||
GUI/MainFrame.hpp
|
||||
GUI/MarkdownTip.cpp
|
||||
@@ -736,7 +738,7 @@ else()
|
||||
set(_opengl_link_lib OpenGL::GL)
|
||||
endif()
|
||||
|
||||
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo libvgcode md4c-html GLEW::GLEW OpenGL::GL hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto noise::noise)
|
||||
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo libvgcode md4c-html glad ${_opengl_link_lib} hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto noise::noise)
|
||||
|
||||
|
||||
if (MSVC)
|
||||
@@ -787,16 +789,24 @@ if (UNIX AND NOT APPLE)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(GTK${SLIC3R_GTK} REQUIRED)
|
||||
pkg_check_modules(LIBSECRET REQUIRED libsecret-1)
|
||||
pkg_check_modules(webkit2gtk REQUIRED webkit2gtk-4.1)
|
||||
if (FLATPAK)
|
||||
# I don't know why this is needed, but for whatever reason slic3r isn't
|
||||
# linking to X11 and webkit2gtk. force it.
|
||||
find_package(X11 REQUIRED)
|
||||
pkg_check_modules(webkit2gtk REQUIRED webkit2gtk-4.1)
|
||||
target_link_libraries(libslic3r_gui ${X11_LIBRARIES} ${webkit2gtk_LIBRARIES})
|
||||
endif()
|
||||
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${GTK${SLIC3R_GTK}_INCLUDE_DIRS} ${LIBSECRET_INCLUDE_DIRS})
|
||||
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${GTK${SLIC3R_GTK}_INCLUDE_DIRS} ${LIBSECRET_INCLUDE_DIRS} ${webkit2gtk_INCLUDE_DIRS})
|
||||
target_link_libraries(libslic3r_gui ${GTK${SLIC3R_GTK}_LIBRARIES} fontconfig ${LIBSECRET_LIBRARIES})
|
||||
|
||||
# Propagate GDK backend detection results as compile definitions so that
|
||||
# LinuxDisplayBackend.cpp can include the right GDK headers.
|
||||
if (wxHAVE_GDK_X11)
|
||||
target_compile_definitions(libslic3r_gui PRIVATE wxHAVE_GDK_X11)
|
||||
endif ()
|
||||
if (wxHAVE_GDK_WAYLAND)
|
||||
target_compile_definitions(libslic3r_gui PRIVATE wxHAVE_GDK_WAYLAND)
|
||||
endif ()
|
||||
|
||||
# We add GStreamer for bambu:/// support.
|
||||
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "Plater.hpp"
|
||||
#include "Camera.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include "3DScene.hpp"
|
||||
#include "GLShader.hpp"
|
||||
|
||||
@@ -94,7 +94,7 @@ void CopyrightsDialog::fill_entries()
|
||||
{ "Eigen3", "", "http://eigen.tuxfamily.org" },
|
||||
{ "Expat", "", "http://www.libexpat.org" },
|
||||
{ "fast_float", "", "https://github.com/fastfloat/fast_float" },
|
||||
{ "GLEW (The OpenGL Extension Wrangler Library)", "", "http://glew.sourceforge.net" },
|
||||
{ "GLAD (Multi-Language GL Loader-Generator)", "", "https://github.com/Dav1dde/glad" },
|
||||
{ "GLFW", "", "https://www.glfw.org" },
|
||||
{ "GNU gettext", "", "https://www.gnu.org/software/gettext" },
|
||||
{ "ImGUI", "", "https://github.com/ocornut/imgui" },
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include "I18N.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "GUI.hpp"
|
||||
#ifdef __WXGTK__
|
||||
#include "LinuxDisplayBackend.hpp"
|
||||
#endif
|
||||
#include "wxExtensions.hpp"
|
||||
#include "Plater.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
@@ -56,9 +59,9 @@ CenteredTitle::CenteredTitle(wxWindow* parent)
|
||||
wxString ellipsized = wxControl::Ellipsize(m_title, dc, wxELLIPSIZE_END, wxMax(0, rect.GetWidth() - FromDIP(8)));
|
||||
|
||||
int y = rect.y + (rect.height - textHeight) / 2;
|
||||
int x = rect.x + (ellipsized != m_title) // is ellipsized
|
||||
int x = rect.x + ((ellipsized != m_title) // is ellipsized
|
||||
? FromDIP(4) // align to left when clipped
|
||||
: (rect.width - dc.GetTextExtent(m_title).GetWidth()) / 2; // centered when has available space
|
||||
: (rect.width - dc.GetTextExtent(m_title).GetWidth()) / 2); // centered when has available space
|
||||
|
||||
dc.DrawText(ellipsized, x, y);
|
||||
});
|
||||
@@ -126,9 +129,10 @@ void BBLTopbarArt::DrawButton(wxDC& dc, wxWindow* wnd, const wxAuiToolBarItem& i
|
||||
int bmpX = 0, bmpY = 0;
|
||||
int textX = 0, textY = 0;
|
||||
|
||||
const wxBitmap& bmp = item.GetState() & wxAUI_BUTTON_STATE_DISABLED
|
||||
? item.GetDisabledBitmap()
|
||||
: item.GetBitmap();
|
||||
// ORCA resolves the toolbar item bitmap using the actual window DPI context used for painting.
|
||||
// GetBitmap() / GetDisabledBitmap() was using internal window pointer (m_window), not the paint-time wnd
|
||||
// m_window was created before final DPI context was known so items not scales properly
|
||||
const wxBitmap bmp = item.GetCurrentBitmapFor(wnd);
|
||||
|
||||
const wxSize bmpSize = bmp.IsOk() ? bmp.GetScaledSize() : wxSize(0, 0);
|
||||
|
||||
@@ -346,6 +350,10 @@ void BBLTopbar::Init(wxFrame* parent)
|
||||
this->Bind(wxEVT_LEFT_DCLICK, &BBLTopbar::OnMouseLeftDClock, this);
|
||||
this->Bind(wxEVT_LEFT_DOWN, &BBLTopbar::OnMouseLeftDown, this);
|
||||
this->Bind(wxEVT_LEFT_UP, &BBLTopbar::OnMouseLeftUp, this);
|
||||
this->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& event) {
|
||||
m_last_mouse_position = wxDefaultPosition;
|
||||
event.Skip();
|
||||
});
|
||||
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnOpenProject, this, wxID_OPEN);
|
||||
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnSaveProject, this, wxID_SAVE);
|
||||
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnRedo, this, wxID_REDO);
|
||||
@@ -589,8 +597,9 @@ void BBLTopbar::OnCloseFrame(wxAuiToolBarEvent& event)
|
||||
|
||||
void BBLTopbar::OnMouseLeftDClock(wxMouseEvent& mouse)
|
||||
{
|
||||
wxPoint mouse_pos = ::wxGetMousePosition();
|
||||
wxAuiToolBarItem* item = this->FindToolByCurrentPosition();
|
||||
m_last_mouse_position = mouse.GetPosition();
|
||||
wxPoint mouse_pos = this->ClientToScreen(mouse.GetPosition());
|
||||
wxAuiToolBarItem* item = this->FindToolByPosition(mouse.GetX(), mouse.GetY());
|
||||
// check whether mouse is not on any tool item
|
||||
if (item != NULL && item->GetWindow() != m_title_ctrl) {
|
||||
mouse.Skip();
|
||||
@@ -658,9 +667,12 @@ void BBLTopbar::OnCalibToolItem(wxAuiToolBarEvent &evt)
|
||||
|
||||
void BBLTopbar::OnMouseLeftDown(wxMouseEvent& event)
|
||||
{
|
||||
wxPoint mouse_pos = ::wxGetMousePosition();
|
||||
m_last_mouse_position = event.GetPosition();
|
||||
// Use event-relative coords converted to screen, instead of wxGetMousePosition()
|
||||
// which returns (0,0) on Wayland for global screen coordinates.
|
||||
wxPoint mouse_pos = this->ClientToScreen(event.GetPosition());
|
||||
wxPoint frame_pos = m_frame->GetScreenPosition();
|
||||
wxAuiToolBarItem* item = this->FindToolByCurrentPosition();
|
||||
wxAuiToolBarItem* item = this->FindToolByPosition(event.GetX(), event.GetY());
|
||||
m_delta = mouse_pos - frame_pos;
|
||||
|
||||
if (item == NULL || item->GetWindow() == m_title_ctrl)
|
||||
@@ -688,7 +700,8 @@ void BBLTopbar::OnMouseLeftDown(wxMouseEvent& event)
|
||||
|
||||
void BBLTopbar::OnMouseLeftUp(wxMouseEvent& event)
|
||||
{
|
||||
wxPoint mouse_pos = ::wxGetMousePosition();
|
||||
m_last_mouse_position = event.GetPosition();
|
||||
wxPoint mouse_pos = this->ClientToScreen(event.GetPosition());
|
||||
if (HasCapture())
|
||||
{
|
||||
ReleaseMouse();
|
||||
@@ -699,7 +712,10 @@ void BBLTopbar::OnMouseLeftUp(wxMouseEvent& event)
|
||||
|
||||
void BBLTopbar::OnMouseMotion(wxMouseEvent& event)
|
||||
{
|
||||
wxPoint mouse_pos = ::wxGetMousePosition();
|
||||
m_last_mouse_position = event.GetPosition();
|
||||
// Use event-relative coords converted to screen, instead of wxGetMousePosition()
|
||||
// which returns (0,0) on Wayland for global screen coordinates.
|
||||
wxPoint mouse_pos = this->ClientToScreen(event.GetPosition());
|
||||
|
||||
if (!HasCapture()) {
|
||||
//m_frame->OnMouseMotion(event);
|
||||
@@ -743,12 +759,20 @@ void BBLTopbar::OnMenuClose(wxMenuEvent& event)
|
||||
|
||||
wxAuiToolBarItem* BBLTopbar::FindToolByCurrentPosition()
|
||||
{
|
||||
if (m_last_mouse_position != wxDefaultPosition && GetClientRect().Contains(m_last_mouse_position))
|
||||
return this->FindToolByPosition(m_last_mouse_position.x, m_last_mouse_position.y);
|
||||
|
||||
#ifdef __WXGTK__
|
||||
if (Slic3r::GUI::is_running_on_wayland())
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
wxPoint mouse_pos = ::wxGetMousePosition();
|
||||
wxPoint client_pos = this->ScreenToClient(mouse_pos);
|
||||
return this->FindToolByPosition(client_pos.x, client_pos.y);
|
||||
}
|
||||
|
||||
#ifdef __WIN32__
|
||||
#ifdef __WXMSW__
|
||||
WXLRESULT CenteredTitle::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
|
||||
{
|
||||
switch (nMsg) {
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
wxSize DoGetBestSize() const override;
|
||||
|
||||
protected:
|
||||
#ifdef __WIN32__
|
||||
#ifdef __WXMSW__
|
||||
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override;
|
||||
#endif
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
void ShowCalibrationButton(bool show = true);
|
||||
|
||||
protected:
|
||||
#ifdef __WIN32__
|
||||
#ifdef __WXMSW__
|
||||
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override;
|
||||
#endif
|
||||
|
||||
@@ -85,6 +85,7 @@ private:
|
||||
wxAuiToolBarItem* m_dropdown_menu_item;
|
||||
wxRect m_normalRect;
|
||||
wxPoint m_delta;
|
||||
wxPoint m_last_mouse_position{wxDefaultPosition};
|
||||
wxMenu m_top_menu;
|
||||
wxMenu* m_file_menu;
|
||||
wxMenu m_calib_menu;
|
||||
|
||||
@@ -50,7 +50,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para
|
||||
def.min = 0;
|
||||
def.max = 214700;
|
||||
def.width = 10; // increase width for large scale printers with 4 digit values
|
||||
def.sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
def.sidetext = L("mm"); // millimeters, CIS languages need translation
|
||||
def.label = get_option_label(param);
|
||||
def.tooltip = L("Size in X and Y of the rectangular plate.");
|
||||
key = "rect_size";
|
||||
@@ -61,7 +61,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para
|
||||
def.min = -107350;
|
||||
def.max = 107350;
|
||||
def.width = 10; // increase width for large scale printers with 4 digit values
|
||||
def.sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
def.sidetext = L("mm"); // millimeters, CIS languages need translation
|
||||
def.label = get_option_label(param);
|
||||
def.tooltip = L("Distance of the 0,0 G-code coordinate from the front left corner of the rectangle.");
|
||||
key = "rect_origin";
|
||||
@@ -70,7 +70,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para
|
||||
def.type = coFloat;
|
||||
def.set_default_value(new ConfigOptionFloat(200));
|
||||
def.width = 10; // match size
|
||||
def.sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
def.sidetext = L("mm"); // millimeters, CIS languages need translation
|
||||
def.label = get_option_label(param);
|
||||
def.tooltip = L("Diameter of the print bed. It is assumed that origin (0,0) is located in the center.");
|
||||
key = "diameter";
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <wx/mstream.h>
|
||||
#include <wx/rawbmp.h>
|
||||
#endif /* __WXGTK2__ */
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#define NANOSVG_IMPLEMENTATION
|
||||
#include "nanosvg/nanosvg.h"
|
||||
#define NANOSVGRAST_IMPLEMENTATION
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "Plater.hpp"
|
||||
#endif // ENABLE_CAMERA_STATISTICS
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
@@ -209,7 +209,7 @@ bool DesktopIntegrationDialog::is_integrated()
|
||||
if (path.empty())
|
||||
return false;
|
||||
|
||||
// confirmation that OrcaSlicer.desktop exists
|
||||
// confirmation that com.orcaslicer.OrcaSlicer.desktop exists
|
||||
struct stat buffer;
|
||||
return (stat (path.c_str(), &buffer) == 0);
|
||||
}
|
||||
@@ -336,19 +336,21 @@ void DesktopIntegrationDialog::perform_desktop_integration()
|
||||
"Exec=\"%3%\" %%F\n"
|
||||
"Terminal=false\n"
|
||||
"Type=Application\n"
|
||||
"PrefersNonDefaultGPU=true\n"
|
||||
"X-KDE-RunOnDiscreteGpu=true\n"
|
||||
"MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;\n"
|
||||
"Categories=Graphics;3DGraphics;Engineering;\n"
|
||||
"Keywords=3D;Printing;Slicer;slice;3D;printer;convert;gcode;stl;obj;amf;SLA\n"
|
||||
"StartupNotify=false\n"
|
||||
"StartupWMClass=orca-slicer\n", name_suffix, version_suffix, excutable_path);
|
||||
|
||||
std::string path = GUI::format("%1%/applications/OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix);
|
||||
std::string path = GUI::format("%1%/applications/com.orcaslicer.OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix);
|
||||
if (create_desktop_file(path, desktop_file)){
|
||||
BOOST_LOG_TRIVIAL(debug) << "OrcaSlicer.desktop file installation success.";
|
||||
BOOST_LOG_TRIVIAL(debug) << "com.orcaslicer.OrcaSlicer.desktop file installation success.";
|
||||
break;
|
||||
} else {
|
||||
// write failed - try another path
|
||||
BOOST_LOG_TRIVIAL(debug) << "Attempt to OrcaSlicer.desktop file installation failed. failed path: " << target_candidates[i];
|
||||
BOOST_LOG_TRIVIAL(debug) << "Attempt to com.orcaslicer.OrcaSlicer.desktop file installation failed. failed path: " << target_candidates[i];
|
||||
target_dir_desktop.clear();
|
||||
}
|
||||
// if all failed - try creating default home folder
|
||||
@@ -357,7 +359,7 @@ void DesktopIntegrationDialog::perform_desktop_integration()
|
||||
create_path(into_u8(wxFileName::GetHomeDir()), ".local/share/applications");
|
||||
// create desktop file
|
||||
target_dir_desktop = GUI::format("%1%/.local/share",wxFileName::GetHomeDir());
|
||||
std::string path = GUI::format("%1%/applications/OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix);
|
||||
std::string path = GUI::format("%1%/applications/com.orcaslicer.OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix);
|
||||
if (contains_path_dir(target_dir_desktop, "applications")) {
|
||||
if (!create_desktop_file(path, desktop_file)) {
|
||||
// Desktop file not written - end desktop integration
|
||||
@@ -379,7 +381,7 @@ void DesktopIntegrationDialog::perform_desktop_integration()
|
||||
return;
|
||||
}
|
||||
// save path to desktop file
|
||||
app_config->set("desktop_integration_app_path", GUI::format("%1%/applications/OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix));
|
||||
app_config->set("desktop_integration_app_path", GUI::format("%1%/applications/com.orcaslicer.OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix));
|
||||
|
||||
// Repeat for Gcode viewer - use same paths as for slicer files
|
||||
// Do NOT add gcode viewer desktop file on ChromeOS
|
||||
@@ -405,6 +407,8 @@ void DesktopIntegrationDialog::perform_desktop_integration()
|
||||
"Exec=\"%3%\" --gcodeviewer %%F\n"
|
||||
"Terminal=false\n"
|
||||
"Type=Application\n"
|
||||
"PrefersNonDefaultGPU=true\n"
|
||||
"X-KDE-RunOnDiscreteGpu=true\n"
|
||||
"MimeType=text/x.gcode;\n"
|
||||
"Categories=Graphics;3DGraphics;\n"
|
||||
"Keywords=3D;Printing;Slicer;\n"
|
||||
|
||||
@@ -18,7 +18,7 @@ public:
|
||||
|
||||
// methods that actually do / undo desktop integration. Static to be accesible from anywhere.
|
||||
|
||||
// returns true if path to OrcaSlicer.desktop is stored in App Config and existence of desktop file.
|
||||
// returns true if path to com.orcaslicer.OrcaSlicer.desktop is stored in App Config and existence of desktop file.
|
||||
// Does not check if desktop file leads to this binary or existence of icons and viewer desktop file.
|
||||
static bool is_integrated();
|
||||
// true if appimage
|
||||
|
||||
@@ -4,16 +4,15 @@
|
||||
#include "wx/dcgraph.h"
|
||||
#include "I18N.hpp"
|
||||
#include "PartPlate.hpp"
|
||||
#include "Widgets/HyperLink.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
static const wxColour LabelEnableColor = wxColour("#262E30");
|
||||
static const wxColour LabelDisableColor = wxColour("#ACACAC");
|
||||
static const wxColour GreyColor = wxColour("#6B6B6B");
|
||||
static const wxColour GreenColor = wxColour("#009688");
|
||||
static const wxColour BackGroundColor = wxColour("#FFFFFF");
|
||||
|
||||
|
||||
static bool should_pop_up()
|
||||
{
|
||||
const auto &preset_bundle = wxGetApp().preset_bundle;
|
||||
@@ -47,6 +46,37 @@ static void set_prefered_map_mode(FilamentMapMode mode)
|
||||
app_config->set("prefered_filament_map_mode", mode_str);
|
||||
}
|
||||
|
||||
bool play_dual_extruder_slice_video()
|
||||
{
|
||||
if (wxLaunchDefaultBrowser("https://e.bambulab.com/t?c=HDB24RlwSmt77YFH")) {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("Video is being played using the system's default browser.");
|
||||
return true;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format("launch system's default browser failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool play_dual_extruder_print_tpu_video()
|
||||
{
|
||||
const wxString video_url = "https://e.bambulab.com/t?c=fwWqpBg37Liel92N";
|
||||
if (wxLaunchDefaultBrowser(video_url)){
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("Print Tpu Video is being played using the system's default browser.");
|
||||
return true;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format("launch system's default browser failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool open_filament_group_wiki()
|
||||
{
|
||||
if (wxLaunchDefaultBrowser("https://e.bambulab.com/t?c=mOkvsXkJ9pldGYp9")) {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("Wiki is being displayed using the system's default browser.");
|
||||
return true;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format("launch system's default browser failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
void FilamentGroupPopup::CreateBmps()
|
||||
{
|
||||
checked_bmp = create_scaled_bitmap("radio_on", nullptr, 16);; // ORCA match icons
|
||||
@@ -146,16 +176,20 @@ FilamentGroupPopup::FilamentGroupPopup(wxWindow *parent) : PopupWindow(parent, w
|
||||
|
||||
{
|
||||
wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
const std::string wiki_path = Slic3r::resources_dir() + "/wiki/filament_group_wiki_zh.html"; // NEEDFIX this link is broken
|
||||
|
||||
auto* wiki_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wiki_link = new HyperLink(this, _L("Wiki Guide"), wxString(wiki_path.c_str())); // ORCA
|
||||
wiki_sizer->Add(wiki_link, 0, wxALIGN_CENTER | wxALL, FromDIP(3));
|
||||
|
||||
button_sizer->Add(wiki_sizer, 0, wxLEFT, horizontal_margin);
|
||||
// ORCA Unified hyperlinks
|
||||
video_link = new HyperLink(this, _L("Video tutorial"));
|
||||
video_link->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent& e)
|
||||
{
|
||||
play_dual_extruder_slice_video();
|
||||
wxGetApp().app_config->set("play_slicing_video", "false");
|
||||
});
|
||||
button_sizer->Add(video_link, 0, wxLEFT, horizontal_margin + FromDIP(3));
|
||||
button_sizer->AddStretchSpacer();
|
||||
|
||||
wiki_link = new HyperLink(this, _L("Wiki Guide"));
|
||||
wiki_link->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent&) { open_filament_group_wiki(); });
|
||||
button_sizer->Add(wiki_link, 0, wxLEFT, horizontal_margin);
|
||||
|
||||
top_sizer->Add(button_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, horizontal_margin);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,10 @@ class PartPlate;
|
||||
class Plater;
|
||||
|
||||
|
||||
bool play_dual_extruder_slice_video();
|
||||
bool play_dual_extruder_print_tpu_video();
|
||||
bool open_filament_group_wiki();
|
||||
|
||||
class FilamentGroupPopup : public PopupWindow
|
||||
{
|
||||
public:
|
||||
@@ -69,6 +73,7 @@ private:
|
||||
|
||||
|
||||
wxStaticText *wiki_link;
|
||||
wxStaticText *video_link;
|
||||
|
||||
PartPlate* partplate_ref{ nullptr };
|
||||
Plater* plater_ref{ nullptr };
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "GLCanvas3D.hpp"
|
||||
#include "FilamentGroupPopup.hpp"
|
||||
#include "GLToolbar.hpp"
|
||||
#include "GUI_Preview.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
@@ -33,7 +34,7 @@
|
||||
#endif // ENABLE_ACTUAL_SPEED_DEBUG
|
||||
#include <imgui/imgui_internal.h>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
@@ -3081,13 +3082,12 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding)
|
||||
|
||||
auto link_filament_group_wiki = [&](const std::string& label) {
|
||||
ImVec2 wiki_part_size = ImGui::CalcTextSize(label.c_str());
|
||||
|
||||
ImColor HyperColor = ImColor(0, 150, 136, 255).Value;
|
||||
ImColor HyperColor = ImColor(0, 150, 136, 255); // ORCA match color
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, HyperColor.Value);
|
||||
imgui.text(label.c_str());
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
// underline
|
||||
// ORCA use underline to match hyperlink style
|
||||
ImVec2 lineEnd = ImGui::GetItemRectMax();
|
||||
lineEnd.y -= 2.0f;
|
||||
ImVec2 lineStart = lineEnd;
|
||||
@@ -3096,8 +3096,7 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding)
|
||||
// click behavior
|
||||
if (ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), true)) {
|
||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
||||
std::string wiki_path = Slic3r::resources_dir() + "/wiki/filament_group_wiki_zh.html";
|
||||
wxLaunchDefaultBrowser(wxString(wiki_path.c_str()));
|
||||
open_filament_group_wiki();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -3304,8 +3303,9 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding)
|
||||
link_text(_u8L("Regroup filament"));
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetWindowContentRegionWidth() - window_padding - ImGui::CalcTextSize("Tips").x);
|
||||
link_filament_group_wiki(_u8L("Tips"));
|
||||
std::string wiki_str = _u8L("Wiki Guide"); // ORCA
|
||||
ImGui::SetCursorPosX(ImGui::GetWindowContentRegionWidth() - window_padding - ImGui::CalcTextSize(wiki_str.c_str()).x);
|
||||
link_filament_group_wiki(wiki_str);
|
||||
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
+168
-130
@@ -44,7 +44,7 @@
|
||||
#include "slic3r/Utils/RetinaHelper.hpp"
|
||||
#endif
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <wx/glcanvas.h>
|
||||
#include <wx/bitmap.h>
|
||||
@@ -2194,8 +2194,12 @@ void GLCanvas3D::render(bool only_init)
|
||||
|
||||
wxGetApp().imgui()->render();
|
||||
|
||||
m_canvas->SwapBuffers();
|
||||
m_render_stats.increment_fps_counter();
|
||||
// On Wayland, eglSwapBuffers blocks when the canvas is hidden or
|
||||
// occluded. Skip the swap to avoid stalling the render loop.
|
||||
if (m_canvas->IsShownOnScreen()) {
|
||||
m_canvas->SwapBuffers();
|
||||
m_render_stats.increment_fps_counter();
|
||||
}
|
||||
}
|
||||
|
||||
void GLCanvas3D::render_thumbnail(ThumbnailData & thumbnail_data,
|
||||
@@ -2354,6 +2358,13 @@ void GLCanvas3D::ensure_on_bed(unsigned int object_idx, bool allow_negative_z)
|
||||
InstancesToZMap instances_min_z;
|
||||
|
||||
for (GLVolume* volume : m_volumes.volumes) {
|
||||
ModelObject* mo = m_model->objects[volume->object_idx()];
|
||||
ModelInstance* mi = mo->instances[volume->instance_idx()];
|
||||
|
||||
if (!mi->auto_drop) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (volume->object_idx() == (int)object_idx && !volume->is_modifier) {
|
||||
double min_z = volume->transformed_convex_hull_bounding_box().min.z();
|
||||
std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
|
||||
@@ -4817,14 +4828,13 @@ Vec2d GLCanvas3D::get_local_mouse_position() const
|
||||
if (m_canvas == nullptr)
|
||||
return Vec2d::Zero();
|
||||
|
||||
wxPoint mouse_pos = m_canvas->ScreenToClient(wxGetMousePosition());
|
||||
const double factor =
|
||||
#if ENABLE_RETINA_GL
|
||||
m_retina_helper->get_scale_factor();
|
||||
#else
|
||||
1.0;
|
||||
#endif
|
||||
return Vec2d(factor * mouse_pos.x, factor * mouse_pos.y);
|
||||
// Use the cached mouse position from event handlers (m_mouse.position)
|
||||
// instead of wxGetMousePosition() + ScreenToClient(), because
|
||||
// wxGetMousePosition() returns (0,0) on Wayland for global coords.
|
||||
// m_mouse.position already stores local canvas coordinates (set from
|
||||
// event.GetX(), event.GetY()) and is already scaled by the retina factor
|
||||
// in on_mouse(), so we can return it directly.
|
||||
return m_mouse.position;
|
||||
}
|
||||
|
||||
void GLCanvas3D::set_tooltip(const std::string& tooltip)
|
||||
@@ -4865,28 +4875,30 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
|
||||
|
||||
// Move instances/volumes
|
||||
ModelObject* model_object = m_model->objects[object_idx];
|
||||
if (model_object != nullptr) {
|
||||
if (selection_mode == Selection::Instance) {
|
||||
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
|
||||
if ((model_object->instances[instance_idx]->get_assemble_offset() - v->get_instance_offset()).norm() > 1e-2) {
|
||||
model_object->instances[instance_idx]->set_assemble_transformation(v->get_instance_transformation());
|
||||
}
|
||||
} else {
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
}
|
||||
}
|
||||
else if (selection_mode == Selection::Volume) {
|
||||
auto cur_mv = model_object->volumes[volume_idx];
|
||||
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
|
||||
cur_mv->set_transformation(v->get_volume_transformation());
|
||||
// BBS: backup
|
||||
Slic3r::save_object_mesh(*model_object);
|
||||
}
|
||||
}
|
||||
if (model_object == nullptr)
|
||||
continue;
|
||||
|
||||
object_moved = true;
|
||||
model_object->invalidate_bounding_box();
|
||||
if (selection_mode == Selection::Instance) {
|
||||
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
|
||||
if ((model_object->instances[instance_idx]->get_assemble_offset() - v->get_instance_offset()).norm() > 1e-2) {
|
||||
model_object->instances[instance_idx]->set_assemble_transformation(v->get_instance_transformation());
|
||||
}
|
||||
} else {
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
}
|
||||
}
|
||||
else if (selection_mode == Selection::Volume) {
|
||||
auto cur_mv = model_object->volumes[volume_idx];
|
||||
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
|
||||
cur_mv->set_transformation(v->get_volume_transformation());
|
||||
// BBS: backup
|
||||
Slic3r::save_object_mesh(*model_object);
|
||||
}
|
||||
}
|
||||
|
||||
object_moved = true;
|
||||
model_object->invalidate_bounding_box();
|
||||
|
||||
}
|
||||
else if (object_idx >= 1000 && object_idx < 1000 + n_plates) {
|
||||
// Move a wipe tower proxy.
|
||||
@@ -4897,20 +4909,27 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
|
||||
//BBS: notify instance updates to part plater list
|
||||
m_selection.notify_instance_update(-1, 0);
|
||||
|
||||
// Fixes flying instances
|
||||
// Fixes sinking/flying instances (snaps object to buildplate)
|
||||
for (const std::pair<int, int>& i : done) {
|
||||
ModelObject* m = m_model->objects[i.first];
|
||||
const double shift_z = m->get_instance_min_z(i.second);
|
||||
ModelObject* mo = m_model->objects[i.first];
|
||||
ModelInstance* mi = mo->instances[i.second];
|
||||
|
||||
if (!mi->auto_drop) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const double shift_z = mo->get_instance_min_z(i.second);
|
||||
//BBS: don't call translate if the z is zero
|
||||
if ((current_printer_technology() == ptSLA || shift_z > SINKING_Z_THRESHOLD) && (shift_z != 0.0f)) {
|
||||
const Vec3d shift(0.0, 0.0, -shift_z);
|
||||
m_selection.translate(i.first, i.second, shift);
|
||||
m->translate_instance(i.second, shift);
|
||||
mo->translate_instance(i.second, shift);
|
||||
//BBS: notify instance updates to part plater list
|
||||
m_selection.notify_instance_update(i.first, i.second);
|
||||
}
|
||||
wxGetApp().obj_list()->update_info_items(static_cast<size_t>(i.first));
|
||||
}
|
||||
|
||||
//BBS: nofity object list to update
|
||||
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
|
||||
|
||||
@@ -4984,40 +5003,47 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
|
||||
|
||||
// Rotate instances/volumes.
|
||||
ModelObject* model_object = m_model->objects[object_idx];
|
||||
if (model_object != nullptr) {
|
||||
if (selection_mode == Selection::Instance) {
|
||||
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
|
||||
model_object->instances[instance_idx]->set_assemble_from_transform(v->get_instance_transformation().get_matrix());
|
||||
} else {
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
}
|
||||
if (model_object == nullptr)
|
||||
continue;
|
||||
|
||||
if (selection_mode == Selection::Instance) {
|
||||
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
|
||||
model_object->instances[instance_idx]->set_assemble_from_transform(v->get_instance_transformation().get_matrix());
|
||||
} else {
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
}
|
||||
else if (selection_mode == Selection::Volume) {
|
||||
auto cur_mv = model_object->volumes[volume_idx];
|
||||
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
|
||||
cur_mv->set_transformation(v->get_volume_transformation());
|
||||
// BBS: backup
|
||||
Slic3r::save_object_mesh(*model_object);
|
||||
}
|
||||
}
|
||||
model_object->invalidate_bounding_box();
|
||||
}
|
||||
else if (selection_mode == Selection::Volume) {
|
||||
auto cur_mv = model_object->volumes[volume_idx];
|
||||
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
|
||||
cur_mv->set_transformation(v->get_volume_transformation());
|
||||
// BBS: backup
|
||||
Slic3r::save_object_mesh(*model_object);
|
||||
}
|
||||
}
|
||||
model_object->invalidate_bounding_box();
|
||||
}
|
||||
|
||||
//BBS: notify instance updates to part plater list
|
||||
m_selection.notify_instance_update(-1, -1);
|
||||
|
||||
if (m_canvas_type != CanvasAssembleView) {
|
||||
// Fixes sinking/flying instances
|
||||
// Fixes sinking/flying instances (snaps object to buildplate)
|
||||
for (const std::pair<int, int> &i : done) {
|
||||
ModelObject *m = m_model->objects[i.first];
|
||||
ModelObject *mo = m_model->objects[i.first];
|
||||
ModelInstance* mi = mo->instances[i.second];
|
||||
|
||||
if (!mi->auto_drop) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// BBS: don't call translate if the z is zero
|
||||
const double shift_z = m->get_instance_min_z(i.second);
|
||||
const double shift_z = mo->get_instance_min_z(i.second);
|
||||
// leave sinking instances as sinking
|
||||
if ((min_zs.find({i.first, i.second})->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) && (shift_z != 0.0f)) {
|
||||
const Vec3d shift(0.0, 0.0, -shift_z);
|
||||
m_selection.translate(i.first, i.second, shift);
|
||||
m->translate_instance(i.second, shift);
|
||||
mo->translate_instance(i.second, shift);
|
||||
// BBS: notify instance updates to part plater list
|
||||
m_selection.notify_instance_update(i.first, i.second);
|
||||
}
|
||||
@@ -5025,6 +5051,7 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
|
||||
wxGetApp().obj_list()->update_info_items(static_cast<size_t>(i.first));
|
||||
}
|
||||
}
|
||||
|
||||
//BBS: nofity object list to update
|
||||
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
|
||||
|
||||
@@ -5072,42 +5099,49 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
|
||||
|
||||
// Rotate instances/volumes
|
||||
ModelObject* model_object = m_model->objects[object_idx];
|
||||
if (model_object != nullptr) {
|
||||
if (selection_mode == Selection::Instance) {
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
}
|
||||
else if (selection_mode == Selection::Volume) {
|
||||
auto cur_mv = model_object->volumes[volume_idx];
|
||||
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
cur_mv->set_transformation(v->get_volume_transformation());
|
||||
// BBS: backup
|
||||
Slic3r::save_object_mesh(*model_object);
|
||||
}
|
||||
}
|
||||
model_object->invalidate_bounding_box();
|
||||
if (model_object == nullptr)
|
||||
continue;
|
||||
|
||||
if (selection_mode == Selection::Instance) {
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
}
|
||||
else if (selection_mode == Selection::Volume) {
|
||||
auto cur_mv = model_object->volumes[volume_idx];
|
||||
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
cur_mv->set_transformation(v->get_volume_transformation());
|
||||
// BBS: backup
|
||||
Slic3r::save_object_mesh(*model_object);
|
||||
}
|
||||
}
|
||||
model_object->invalidate_bounding_box();
|
||||
}
|
||||
|
||||
//BBS: notify instance updates to part plater list
|
||||
m_selection.notify_instance_update(-1, -1);
|
||||
|
||||
// Fixes sinking/flying instances
|
||||
// Fixes sinking/flying instances (snaps object to buildplate)
|
||||
for (const std::pair<int, int>& i : done) {
|
||||
ModelObject* m = m_model->objects[i.first];
|
||||
ModelObject* mo = m_model->objects[i.first];
|
||||
ModelInstance* mi = mo->instances[i.second];
|
||||
|
||||
if (!mi->auto_drop) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//BBS: don't call translate if the z is zero
|
||||
double shift_z = m->get_instance_min_z(i.second);
|
||||
double shift_z = mo->get_instance_min_z(i.second);
|
||||
// leave sinking instances as sinking
|
||||
if ((min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) && (shift_z != 0.0f)) {
|
||||
Vec3d shift(0.0, 0.0, -shift_z);
|
||||
m_selection.translate(i.first, i.second, shift);
|
||||
m->translate_instance(i.second, shift);
|
||||
mo->translate_instance(i.second, shift);
|
||||
//BBS: notify instance updates to part plater list
|
||||
m_selection.notify_instance_update(i.first, i.second);
|
||||
}
|
||||
wxGetApp().obj_list()->update_info_items(static_cast<size_t>(i.first));
|
||||
}
|
||||
|
||||
//BBS: nofity object list to update
|
||||
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
|
||||
//BBS: notify object info update
|
||||
@@ -5177,35 +5211,41 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
|
||||
|
||||
// Mirror instances/volumes
|
||||
ModelObject* model_object = m_model->objects[object_idx];
|
||||
if (model_object != nullptr) {
|
||||
if (selection_mode == Selection::Instance)
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
else if (selection_mode == Selection::Volume) {
|
||||
if (model_object->volumes[volume_idx]->get_transformation() != v->get_volume_transformation()) {
|
||||
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
|
||||
// BBS: backup
|
||||
Slic3r::save_object_mesh(*model_object);
|
||||
}
|
||||
}
|
||||
if (model_object == nullptr)
|
||||
continue;
|
||||
|
||||
model_object->invalidate_bounding_box();
|
||||
if (selection_mode == Selection::Instance)
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
else if (selection_mode == Selection::Volume) {
|
||||
if (model_object->volumes[volume_idx]->get_transformation() != v->get_volume_transformation()) {
|
||||
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
|
||||
// BBS: backup
|
||||
Slic3r::save_object_mesh(*model_object);
|
||||
}
|
||||
}
|
||||
|
||||
model_object->invalidate_bounding_box();
|
||||
}
|
||||
|
||||
//BBS: notify instance updates to part plater list
|
||||
m_selection.notify_instance_update(-1, -1);
|
||||
|
||||
// Fixes sinking/flying instances
|
||||
// Fixes sinking/flying instances (snaps object to buildplate)
|
||||
for (const std::pair<int, int>& i : done) {
|
||||
ModelObject* m = m_model->objects[i.first];
|
||||
ModelObject* mo = m_model->objects[i.first];
|
||||
ModelInstance* mi = mo->instances[i.second];
|
||||
|
||||
if (!mi->auto_drop) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//BBS: don't call translate if the z is zero
|
||||
double shift_z = m->get_instance_min_z(i.second);
|
||||
double shift_z = mo->get_instance_min_z(i.second);
|
||||
// leave sinking instances as sinking
|
||||
if ((min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD)&&(shift_z != 0.0f)) {
|
||||
Vec3d shift(0.0, 0.0, -shift_z);
|
||||
m_selection.translate(i.first, i.second, shift);
|
||||
m->translate_instance(i.second, shift);
|
||||
mo->translate_instance(i.second, shift);
|
||||
//BBS: notify instance updates to part plater list
|
||||
m_selection.notify_instance_update(i.first, i.second);
|
||||
}
|
||||
@@ -5214,10 +5254,8 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
|
||||
//BBS: notify instance updates to part plater list
|
||||
PartPlateList &plate_list = wxGetApp().plater()->get_partplate_list();
|
||||
plate_list.notify_instance_update(i.first, i.second);
|
||||
|
||||
//BBS: nofity object list to update
|
||||
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
|
||||
}
|
||||
}
|
||||
|
||||
//BBS: nofity object list to update
|
||||
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
|
||||
|
||||
@@ -6388,21 +6426,21 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data,
|
||||
// glsafe(::glEnable(GL_MULTISAMPLE));
|
||||
|
||||
GLint max_samples;
|
||||
glsafe(::glGetIntegerv(GL_MAX_SAMPLES_EXT, &max_samples));
|
||||
glsafe(::glGetIntegerv(GL_MAX_SAMPLES, &max_samples));
|
||||
GLsizei num_samples = max_samples / 2;
|
||||
|
||||
GLuint render_fbo;
|
||||
glsafe(::glGenFramebuffersEXT(1, &render_fbo));
|
||||
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, render_fbo));
|
||||
glsafe(::glGenFramebuffers(1, &render_fbo));
|
||||
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, render_fbo));
|
||||
|
||||
GLuint render_tex = 0;
|
||||
GLuint render_tex_buffer = 0;
|
||||
if (multisample) {
|
||||
// use renderbuffer instead of texture to avoid the need to use glTexImage2DMultisample which is available only since OpenGL 3.2
|
||||
glsafe(::glGenRenderbuffersEXT(1, &render_tex_buffer));
|
||||
glsafe(::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_tex_buffer));
|
||||
glsafe(::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, num_samples, GL_RGBA8, w, h));
|
||||
glsafe(::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, render_tex_buffer));
|
||||
glsafe(::glGenRenderbuffers(1, &render_tex_buffer));
|
||||
glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, render_tex_buffer));
|
||||
glsafe(::glRenderbufferStorageMultisample(GL_RENDERBUFFER, num_samples, GL_RGBA8, w, h));
|
||||
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, render_tex_buffer));
|
||||
}
|
||||
else {
|
||||
glsafe(::glGenTextures(1, &render_tex));
|
||||
@@ -6410,31 +6448,31 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data,
|
||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, render_tex, 0));
|
||||
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render_tex, 0));
|
||||
}
|
||||
|
||||
GLuint render_depth;
|
||||
glsafe(::glGenRenderbuffersEXT(1, &render_depth));
|
||||
glsafe(::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_depth));
|
||||
glsafe(::glGenRenderbuffers(1, &render_depth));
|
||||
glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, render_depth));
|
||||
if (multisample)
|
||||
glsafe(::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, num_samples, GL_DEPTH_COMPONENT24, w, h));
|
||||
glsafe(::glRenderbufferStorageMultisample(GL_RENDERBUFFER, num_samples, GL_DEPTH_COMPONENT24, w, h));
|
||||
else
|
||||
glsafe(::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, w, h));
|
||||
glsafe(::glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h));
|
||||
|
||||
glsafe(::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, render_depth));
|
||||
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_depth));
|
||||
|
||||
GLenum drawBufs[] = { GL_COLOR_ATTACHMENT0 };
|
||||
glsafe(::glDrawBuffers(1, drawBufs));
|
||||
|
||||
if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT) {
|
||||
if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
|
||||
render_thumbnail_internal(thumbnail_data, thumbnail_params, partplate_list, model_objects, volumes, extruder_colors, shader, camera_type, camera_view_angle_type,
|
||||
for_picking,
|
||||
ban_light);
|
||||
|
||||
if (multisample) {
|
||||
GLuint resolve_fbo;
|
||||
glsafe(::glGenFramebuffersEXT(1, &resolve_fbo));
|
||||
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, resolve_fbo));
|
||||
glsafe(::glGenFramebuffers(1, &resolve_fbo));
|
||||
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, resolve_fbo));
|
||||
|
||||
GLuint resolve_tex;
|
||||
glsafe(::glGenTextures(1, &resolve_tex));
|
||||
@@ -6442,21 +6480,21 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data,
|
||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
glsafe(::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, resolve_tex, 0));
|
||||
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolve_tex, 0));
|
||||
|
||||
glsafe(::glDrawBuffers(1, drawBufs));
|
||||
|
||||
if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT) {
|
||||
glsafe(::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, render_fbo));
|
||||
glsafe(::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, resolve_fbo));
|
||||
glsafe(::glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR));
|
||||
if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
|
||||
glsafe(::glBindFramebuffer(GL_READ_FRAMEBUFFER, render_fbo));
|
||||
glsafe(::glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo));
|
||||
glsafe(::glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR));
|
||||
|
||||
glsafe(::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, resolve_fbo));
|
||||
glsafe(::glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo));
|
||||
glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
|
||||
}
|
||||
|
||||
glsafe(::glDeleteTextures(1, &resolve_tex));
|
||||
glsafe(::glDeleteFramebuffersEXT(1, &resolve_fbo));
|
||||
glsafe(::glDeleteFramebuffers(1, &resolve_fbo));
|
||||
}
|
||||
else
|
||||
glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
|
||||
@@ -6466,13 +6504,13 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data,
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
|
||||
}
|
||||
|
||||
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
|
||||
glsafe(::glDeleteRenderbuffersEXT(1, &render_depth));
|
||||
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
glsafe(::glDeleteRenderbuffers(1, &render_depth));
|
||||
if (render_tex_buffer != 0)
|
||||
glsafe(::glDeleteRenderbuffersEXT(1, &render_tex_buffer));
|
||||
glsafe(::glDeleteRenderbuffers(1, &render_tex_buffer));
|
||||
if (render_tex != 0)
|
||||
glsafe(::glDeleteTextures(1, &render_tex));
|
||||
glsafe(::glDeleteFramebuffersEXT(1, &render_fbo));
|
||||
glsafe(::glDeleteFramebuffers(1, &render_fbo));
|
||||
|
||||
//if (!multisample)
|
||||
// glsafe(::glDisable(GL_MULTISAMPLE));
|
||||
@@ -7249,8 +7287,8 @@ void GLCanvas3D::_rectangular_selection_picking_pass()
|
||||
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, render_fbo));
|
||||
}
|
||||
else {
|
||||
glsafe(::glGenFramebuffersEXT(1, &render_fbo));
|
||||
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, render_fbo));
|
||||
glsafe(::glGenFramebuffers(1, &render_fbo));
|
||||
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, render_fbo));
|
||||
}
|
||||
glsafe(::glGenTextures(1, &render_tex));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, render_tex));
|
||||
@@ -7265,11 +7303,11 @@ void GLCanvas3D::_rectangular_selection_picking_pass()
|
||||
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_depth));
|
||||
}
|
||||
else {
|
||||
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, render_tex, 0));
|
||||
glsafe(::glGenRenderbuffersEXT(1, &render_depth));
|
||||
glsafe(::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_depth));
|
||||
glsafe(::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height));
|
||||
glsafe(::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, render_depth));
|
||||
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render_tex, 0));
|
||||
glsafe(::glGenRenderbuffers(1, &render_depth));
|
||||
glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, render_depth));
|
||||
glsafe(::glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height));
|
||||
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_depth));
|
||||
}
|
||||
const GLenum drawBufs[] = { GL_COLOR_ATTACHMENT0 };
|
||||
glsafe(::glDrawBuffers(1, drawBufs));
|
||||
@@ -7278,7 +7316,7 @@ void GLCanvas3D::_rectangular_selection_picking_pass()
|
||||
use_framebuffer = false;
|
||||
}
|
||||
else {
|
||||
if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||
if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
use_framebuffer = false;
|
||||
}
|
||||
}
|
||||
@@ -7389,11 +7427,11 @@ void GLCanvas3D::_rectangular_selection_picking_pass()
|
||||
glsafe(::glDeleteFramebuffers(1, &render_fbo));
|
||||
}
|
||||
else if (framebuffers_type == OpenGLManager::EFramebufferType::Ext) {
|
||||
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
|
||||
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
if (render_depth != 0)
|
||||
glsafe(::glDeleteRenderbuffersEXT(1, &render_depth));
|
||||
glsafe(::glDeleteRenderbuffers(1, &render_depth));
|
||||
if (render_fbo != 0)
|
||||
glsafe(::glDeleteFramebuffersEXT(1, &render_fbo));
|
||||
glsafe(::glDeleteFramebuffers(1, &render_fbo));
|
||||
}
|
||||
|
||||
if (render_tex != 0)
|
||||
|
||||
@@ -954,7 +954,7 @@ public:
|
||||
Camera::ViewAngleType camera_view_angle_type = Camera::ViewAngleType::Iso,
|
||||
bool for_picking = false,
|
||||
bool ban_light = false);
|
||||
// render thumbnail using an off-screen framebuffer when GLEW_EXT_framebuffer_object is supported
|
||||
// render thumbnail using an off-screen framebuffer when GL_EXT_framebuffer_object is supported
|
||||
static void render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
||||
PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector<ColorRGBA>& extruder_colors,
|
||||
GLShaderProgram * shader,
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <igl/per_vertex_normals.h>
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "Plater.hpp"
|
||||
#include <igl/project.h>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "libslic3r/Color.hpp"
|
||||
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#include <cassert>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <string_view>
|
||||
using namespace std::literals;
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "GUI_App.hpp"
|
||||
#include "GLModel.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <wx/image.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
@@ -161,6 +161,10 @@ typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS2)(
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG
|
||||
|
||||
#ifdef __WXGTK__
|
||||
#include "LinuxDisplayBackend.hpp"
|
||||
#endif
|
||||
|
||||
// Needed for forcing menu icons back under gtk2 and gtk3
|
||||
#if defined(__WXGTK20__) || defined(__WXGTK3__)
|
||||
#include <gtk/gtk.h>
|
||||
@@ -909,6 +913,8 @@ void GUI_App::post_init()
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << "Found glcontext not ready, postpone the init";
|
||||
plater_->canvas3D()->enable_render(true);
|
||||
plater_->canvas3D()->set_as_dirty();
|
||||
}
|
||||
//#endif
|
||||
if (is_editor())
|
||||
@@ -2303,7 +2309,8 @@ bool GUI_App::init_opengl()
|
||||
{
|
||||
#ifdef __linux__
|
||||
bool status = m_opengl_mgr.init_gl();
|
||||
m_opengl_initialized = true;
|
||||
if (status)
|
||||
m_opengl_initialized = true;
|
||||
return status;
|
||||
#else
|
||||
return m_opengl_mgr.init_gl();
|
||||
@@ -3091,6 +3098,20 @@ bool GUI_App::on_init_inner()
|
||||
// Let the libslic3r know the callback, which will translate messages on demand.
|
||||
Slic3r::I18N::set_translate_callback(libslic3r_translate_callback);
|
||||
|
||||
#if defined(__WXGTK__) && wxHAS_EGL
|
||||
// Configure GL backend before any wxGLCanvas is created.
|
||||
// On X11, prefer GLX for maximum driver compatibility.
|
||||
// On Wayland, EGL is used by default (only option).
|
||||
if (Slic3r::GUI::is_running_on_x11()) {
|
||||
wxGLCanvas::PreferGLX();
|
||||
BOOST_LOG_TRIVIAL(info) << "X11 detected, using GLX for OpenGL context";
|
||||
} else if (Slic3r::GUI::is_running_on_wayland()) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Wayland detected, using EGL for OpenGL context";
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Unknown display backend, defaulting to EGL";
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "create the main window";
|
||||
mainframe = new MainFrame();
|
||||
// hide settings tabs after first Layout
|
||||
@@ -7708,7 +7729,12 @@ bool GUI_App::window_pos_restore(wxTopLevelWindow* window, const std::string &na
|
||||
}
|
||||
|
||||
const wxRect& rect = metrics->get_rect();
|
||||
window->SetPosition(rect.GetPosition());
|
||||
#if defined(__WXGTK__)
|
||||
// On Wayland, SetPosition() is a no-op for top-level windows.
|
||||
// Only restore size and maximize state.
|
||||
if (!Slic3r::GUI::is_running_on_wayland())
|
||||
#endif
|
||||
window->SetPosition(rect.GetPosition());
|
||||
window->SetSize(rect.GetSize());
|
||||
window->Maximize(metrics->get_maximized());
|
||||
return true;
|
||||
|
||||
@@ -855,6 +855,23 @@ wxMenuItem* MenuFactory::append_menu_item_printable(wxMenu* menu)
|
||||
return menu_item_printable;
|
||||
}
|
||||
|
||||
wxMenuItem* MenuFactory::append_menu_item_auto_drop(wxMenu* menu)
|
||||
{
|
||||
wxString menu_text = _L("Auto Drop");
|
||||
wxString menu_tooltip = _L("Automatically drops the selected object to the build plate");
|
||||
wxMenuItem* menu_item_auto_drop = append_menu_check_item(
|
||||
menu, wxID_ANY, menu_text, menu_tooltip,
|
||||
[](wxCommandEvent&) { obj_list()->toggle_auto_drop(); }, menu);
|
||||
|
||||
m_parent->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) {
|
||||
bool check = wxGetApp().plater()->get_selection().get_auto_drop();
|
||||
evt.Check(check);
|
||||
},
|
||||
menu_item_auto_drop->GetId());
|
||||
|
||||
return menu_item_auto_drop;
|
||||
}
|
||||
|
||||
void MenuFactory::append_menu_item_rename(wxMenu* menu)
|
||||
{
|
||||
append_menu_item(menu, wxID_ANY, _L("Rename"), "",
|
||||
@@ -1416,6 +1433,10 @@ void MenuFactory::create_extra_object_menu()
|
||||
// Set filament insert menu item here
|
||||
// Set Printable
|
||||
wxMenuItem* menu_item_printable = append_menu_item_printable(&m_object_menu);
|
||||
m_object_menu.AppendSeparator();
|
||||
wxMenuItem* menu_item_auto_drop = append_menu_item_auto_drop(&m_object_menu);
|
||||
m_object_menu.AppendSeparator();
|
||||
|
||||
append_menu_item_per_object_process(&m_object_menu);
|
||||
// Enter per object parameters
|
||||
append_menu_item_per_object_settings(&m_object_menu);
|
||||
@@ -1845,8 +1866,14 @@ wxMenu* MenuFactory::multi_selection_menu()
|
||||
menu->AppendSeparator();
|
||||
|
||||
append_menu_item_set_printable(menu);
|
||||
menu->AppendSeparator();
|
||||
|
||||
append_menu_item_set_auto_drop(menu);
|
||||
menu->AppendSeparator();
|
||||
|
||||
append_menu_item_per_object_process(menu);
|
||||
menu->AppendSeparator();
|
||||
|
||||
append_menu_items_convert_unit(menu);
|
||||
append_menu_item_replace_all_with_stl(menu);
|
||||
//BBS
|
||||
@@ -2032,7 +2059,7 @@ void MenuFactory::append_menu_item_drop(wxMenu* menu)
|
||||
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
|
||||
return false;
|
||||
else {
|
||||
return (plater()->get_view3D_canvas3D()->get_selection().get_bounding_box().min.z() != 0);
|
||||
return (plater()->get_view3D_canvas3D()->get_selection().get_bounding_box().min.z() > SINKING_Z_THRESHOLD);
|
||||
} //disable if model is on the bed / not in View3D
|
||||
}, m_parent);
|
||||
}
|
||||
@@ -2184,7 +2211,7 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu)
|
||||
void MenuFactory::append_menu_item_set_printable(wxMenu* menu)
|
||||
{
|
||||
const Selection& selection = plater()->canvas3D()->get_selection();
|
||||
bool all_printable = true;
|
||||
bool all_printable = true;
|
||||
ObjectList* list = obj_list();
|
||||
wxDataViewItemArray sels;
|
||||
list->GetSelections(sels);
|
||||
@@ -2212,6 +2239,29 @@ void MenuFactory::append_menu_item_set_printable(wxMenu* menu)
|
||||
}, menu_item_set_printable->GetId());
|
||||
}
|
||||
|
||||
void MenuFactory::append_menu_item_set_auto_drop(wxMenu* menu)
|
||||
{
|
||||
const Selection& selection = plater()->canvas3D()->get_selection();
|
||||
const bool current_auto_drop = selection.get_auto_drop();
|
||||
|
||||
wxString menu_text = _L("Auto Drop");
|
||||
wxString menu_tooltip = _L("Automatically snaps the selected object to the build plate");
|
||||
wxMenuItem* menu_item_set_auto_drop = append_menu_check_item(
|
||||
menu, wxID_ANY, menu_text, menu_tooltip,
|
||||
[this, current_auto_drop](wxCommandEvent&) {
|
||||
Selection& selection = plater()->canvas3D()->get_selection();
|
||||
selection.set_auto_drop(!current_auto_drop);
|
||||
},
|
||||
menu);
|
||||
m_parent->Bind(
|
||||
wxEVT_UPDATE_UI,
|
||||
[current_auto_drop](wxUpdateUIEvent& evt) {
|
||||
evt.Check(current_auto_drop);
|
||||
plater()->set_current_canvas_as_dirty();
|
||||
},
|
||||
menu_item_set_auto_drop->GetId());
|
||||
}
|
||||
|
||||
void MenuFactory::append_menu_item_locked(wxMenu* menu)
|
||||
{
|
||||
const std::vector<wxString> names = { _L("Unlock"), _L("Lock") };
|
||||
|
||||
@@ -137,6 +137,7 @@ private:
|
||||
wxMenuItem* append_menu_item_change_type(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_printable(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_auto_drop(wxMenu* menu);
|
||||
void append_menu_item_rename(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
|
||||
//wxMenuItem* append_menu_item_simplify(wxMenu* menu);
|
||||
@@ -171,6 +172,7 @@ private:
|
||||
void append_menu_item_per_object_settings(wxMenu* menu);
|
||||
void append_menu_item_change_filament(wxMenu* menu);
|
||||
void append_menu_item_set_printable(wxMenu* menu);
|
||||
void append_menu_item_set_auto_drop(wxMenu* menu);
|
||||
void append_menu_item_locked(wxMenu* menu);
|
||||
void append_menu_item_fill_bed(wxMenu *menu);
|
||||
void append_menu_item_plate_name(wxMenu *menu);
|
||||
|
||||
@@ -914,15 +914,15 @@ void ObjectList::object_config_options_changed(const ObjectVolumeID& ov_id)
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectList::printable_state_changed(const std::vector<ObjectVolumeID>& ov_ids)
|
||||
void ObjectList::printable_state_changed(const std::vector<ModelObject*> model_objects)
|
||||
{
|
||||
std::vector<size_t> obj_idxs;
|
||||
for (const ObjectVolumeID ov_id : ov_ids) {
|
||||
if (ov_id.object == nullptr)
|
||||
for (const ModelObject* mo : model_objects) {
|
||||
if (mo == nullptr)
|
||||
continue;
|
||||
|
||||
ModelInstance* mi = ov_id.object->instances[0];
|
||||
wxDataViewItem obj_item = m_objects_model->GetObjectItem(ov_id.object);
|
||||
ModelInstance* mi = mo->instances[0];
|
||||
wxDataViewItem obj_item = m_objects_model->GetObjectItem(mo);
|
||||
m_objects_model->SetObjectPrintableState(mi->printable ? piPrintable : piUnprintable, obj_item);
|
||||
|
||||
int obj_idx = m_objects_model->GetObjectIdByItem(obj_item);
|
||||
@@ -939,6 +939,19 @@ void ObjectList::printable_state_changed(const std::vector<ObjectVolumeID>& ov_i
|
||||
wxGetApp().plater()->update();
|
||||
}
|
||||
|
||||
void ObjectList::printable_state_changed(const std::vector<ObjectVolumeID>& ov_ids)
|
||||
{
|
||||
std::vector<ModelObject*> model_objects;
|
||||
model_objects.reserve(ov_ids.size());
|
||||
|
||||
for (const ObjectVolumeID& ov_id : ov_ids) {
|
||||
if (ov_id.object != nullptr)
|
||||
model_objects.emplace_back(ov_id.object);
|
||||
}
|
||||
|
||||
printable_state_changed(model_objects);
|
||||
}
|
||||
|
||||
void ObjectList::assembly_plate_object_name()
|
||||
{
|
||||
m_objects_model->assembly_name();
|
||||
@@ -1153,6 +1166,7 @@ void ObjectList::update_name_in_list(int obj_idx, int vol_idx) const
|
||||
|
||||
void ObjectList::selection_changed()
|
||||
{
|
||||
if (wxGetApp().is_closing()) return;
|
||||
if (m_prevent_list_events) return;
|
||||
|
||||
fix_multiselection_conflicts();
|
||||
@@ -1747,6 +1761,8 @@ void ObjectList::key_event(wxKeyEvent& event)
|
||||
decrease_instances();
|
||||
else if (event.GetUnicodeKey() == 'p')
|
||||
toggle_printable_state();
|
||||
else if (event.GetUnicodeKey() == 'd')
|
||||
toggle_auto_drop();
|
||||
else if (filaments_count() > 1) {
|
||||
std::vector<wxChar> numbers = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
|
||||
wxChar key_char = event.GetUnicodeKey();
|
||||
@@ -3043,6 +3059,17 @@ void ObjectList::merge(bool to_multipart_object)
|
||||
volume->config.set_key_value("extruder", option->clone());
|
||||
}
|
||||
|
||||
// merge printable and auto_drop values
|
||||
// non-default have priority -> if one object has printable == false,
|
||||
// then merged object will also have printable == false
|
||||
if (object->instances[0]->printable == false) {
|
||||
new_object->printable = false;
|
||||
new_object->instances[0]->printable = false;
|
||||
}
|
||||
if (object->instances[0]->auto_drop == false) {
|
||||
new_object->instances[0]->auto_drop = false;
|
||||
}
|
||||
|
||||
// merge layers
|
||||
for (const auto& range : object->layer_config_ranges)
|
||||
new_object->layer_config_ranges.emplace(range);
|
||||
@@ -3076,6 +3103,9 @@ void ObjectList::merge(bool to_multipart_object)
|
||||
|
||||
// Add new object(merged) to the object_list
|
||||
add_object_to_list(m_objects->size() - 1);
|
||||
if (new_object->printable == false) {
|
||||
wxGetApp().obj_list()->printable_state_changed({new_object});
|
||||
}
|
||||
select_item(m_objects_model->GetItemById(m_objects->size() - 1));
|
||||
update_selections_on_canvas();
|
||||
}
|
||||
@@ -3456,6 +3486,9 @@ void ObjectList::changed_object(const int obj_idx/* = -1*/) const
|
||||
|
||||
void ObjectList::part_selection_changed()
|
||||
{
|
||||
if (wxGetApp().is_closing())
|
||||
return;
|
||||
|
||||
if (m_extruder_editor) m_extruder_editor->Hide();
|
||||
int obj_idx = -1;
|
||||
int volume_id = -1;
|
||||
@@ -4656,6 +4689,9 @@ int ObjectList::get_selected_layers_range_idx() const
|
||||
|
||||
void ObjectList::update_selections()
|
||||
{
|
||||
if (wxGetApp().is_closing())
|
||||
return;
|
||||
|
||||
const Selection& selection = scene_selection();
|
||||
wxDataViewItemArray sels;
|
||||
|
||||
@@ -6593,6 +6629,52 @@ void ObjectList::toggle_printable_state()
|
||||
wxGetApp().plater()->reload_paint_after_background_process_apply();
|
||||
}
|
||||
|
||||
void ObjectList::toggle_auto_drop()
|
||||
{
|
||||
wxDataViewItemArray sels;
|
||||
GetSelections(sels);
|
||||
if (sels.IsEmpty())
|
||||
return;
|
||||
|
||||
for (auto item : sels) {
|
||||
ItemType type = m_objects_model->GetItemType(item);
|
||||
if (!(type & (itObject | itInstance)))
|
||||
return;
|
||||
}
|
||||
|
||||
const bool current_auto_drop = wxGetApp().plater()->get_selection().get_auto_drop();
|
||||
|
||||
take_snapshot("");
|
||||
|
||||
std::vector<size_t> obj_idxs;
|
||||
for (auto item : sels) {
|
||||
int obj_idx = m_objects_model->GetObjectIdByItem(item);
|
||||
ModelObject* obj = object(obj_idx);
|
||||
|
||||
obj_idxs.emplace_back(static_cast<size_t>(obj_idx));
|
||||
|
||||
ItemType type = m_objects_model->GetItemType(item);
|
||||
// set auto_drop value for selected instance/instances in object
|
||||
if (type == itInstance) {
|
||||
int inst_idx = m_objects_model->GetInstanceIdByItem(item);
|
||||
obj->instances[inst_idx]->auto_drop = !current_auto_drop;
|
||||
} else {
|
||||
for (auto inst : obj->instances)
|
||||
inst->auto_drop = !current_auto_drop;
|
||||
|
||||
if (current_auto_drop == false)
|
||||
obj->ensure_on_bed();
|
||||
}
|
||||
}
|
||||
|
||||
sort(obj_idxs.begin(), obj_idxs.end());
|
||||
obj_idxs.erase(unique(obj_idxs.begin(), obj_idxs.end()), obj_idxs.end());
|
||||
|
||||
// update scene
|
||||
wxGetApp().plater()->update();
|
||||
wxGetApp().plater()->reload_paint_after_background_process_apply();
|
||||
}
|
||||
|
||||
void ObjectList::enable_layers_editing()
|
||||
{
|
||||
wxDataViewItemArray sels;
|
||||
|
||||
@@ -449,6 +449,7 @@ public:
|
||||
//update printable state for item from objects model
|
||||
void update_printable_state(int obj_idx, int instance_idx);
|
||||
void toggle_printable_state();
|
||||
void toggle_auto_drop();
|
||||
void enable_layers_editing();
|
||||
|
||||
//BBS: remove const qualifier
|
||||
@@ -463,6 +464,7 @@ public:
|
||||
void on_plate_selected(int plate_index);
|
||||
void notify_instance_updated(int obj_idx);
|
||||
void object_config_options_changed(const ObjectVolumeID& ov_id);
|
||||
void printable_state_changed(const std::vector<ModelObject*> model_objects);
|
||||
void printable_state_changed(const std::vector<ObjectVolumeID>& ov_ids);
|
||||
|
||||
// search objectlist
|
||||
|
||||
@@ -86,6 +86,9 @@ bool ObjectSettings::update_settings_list()
|
||||
m_settings_list_sizer->Clear(true);
|
||||
m_og_settings.resize(0);
|
||||
|
||||
if (wxGetApp().is_closing())
|
||||
return false;
|
||||
|
||||
auto objects_ctrl = wxGetApp().obj_list();
|
||||
auto objects_model = wxGetApp().obj_list()->GetModel();
|
||||
auto config = wxGetApp().obj_list()->config();
|
||||
|
||||
@@ -1520,12 +1520,7 @@ void ObjectGridTable::update_value_to_object(Model* model, ObjectGridRow* grid_r
|
||||
object->printable = grid_row->printable.value;
|
||||
object->instances[0]->printable = object->printable;
|
||||
|
||||
std::vector<ObjectVolumeID> object_volume_ids;
|
||||
ObjectVolumeID object_volume_id;
|
||||
object_volume_id.object = object;
|
||||
object_volume_id.volume = nullptr;
|
||||
object_volume_ids.push_back(object_volume_id);
|
||||
wxGetApp().obj_list()->printable_state_changed(object_volume_ids);
|
||||
wxGetApp().obj_list()->printable_state_changed({object});
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", change object %1%'s printable to %2%")%object->module_name %object->printable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "GLGizmoAdvancedCut.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <numeric>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <future>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "GLGizmoBase.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "GLGizmoBrimEars.hpp"
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/Camera.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "GLGizmoCut.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
#include <cereal/types/string.hpp>
|
||||
#include <cereal/archives/binary.hpp>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#include <chrono> // measure enumeration of fonts
|
||||
|
||||
// uncomment for easier debug
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "libslic3r/TextConfiguration.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
class wxFont;
|
||||
namespace Slic3r{
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "slic3r/GUI/ImGuiWrapper.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include <windows.h>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include <numeric>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "slic3r/GUI/Camera.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectSettings.hpp"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <numeric>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <wx/utils.h>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Camera.hpp"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
#include <cereal/types/vector.hpp>
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include <wx/display.h> // detection of change DPI
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#include <chrono> // measure enumeration of fonts
|
||||
#include <sstream> // save for svg
|
||||
#include <array>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
namespace Slic3r{
|
||||
class ModelVolume;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <wx/utils.h>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/QuadricEdgeCollapse.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "slic3r/GUI/MainFrame.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/settings.h>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
@@ -242,7 +242,7 @@ int HMSQuery::save_to_local(std::string lang, std::string hms_type, std::string
|
||||
std::string dir_str = (hms_folder / filename).make_preferred().string();
|
||||
std::ofstream json_file(encode_path(dir_str.c_str()));
|
||||
if (json_file.is_open()) {
|
||||
json_file << std::setw(4) << save_json << std::endl;
|
||||
json_file << save_json.dump(1, '\t') << std::endl;
|
||||
json_file.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "IMToolbar.hpp"
|
||||
|
||||
#include "3DScene.hpp"
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#include <imgui/imgui_internal.h>
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
@@ -87,7 +87,7 @@ bool IMReturnToolbar::init()
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
glsafe(::glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
|
||||
if (compress && GLEW_EXT_texture_compression_s3tc)
|
||||
if (compress && GLAD_GL_EXT_texture_compression_s3tc)
|
||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, data.width, data.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
else
|
||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data.width, data.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "libslic3r/Utils.hpp" // ScopeGuard
|
||||
|
||||
#include "3DScene.hpp" // glsafe
|
||||
#include "GL/glew.h"
|
||||
#include <glad/gl.h>
|
||||
|
||||
#define STB_RECT_PACK_IMPLEMENTATION
|
||||
#include "imgui/imstb_rectpack.h" // distribute rectangles
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <wx/clipbrd.h>
|
||||
#include <wx/debug.h>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
@@ -2839,7 +2839,7 @@ void ImGuiWrapper::init_font(bool compress)
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
glsafe(::glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
|
||||
if (compress && GLEW_EXT_texture_compression_s3tc)
|
||||
if (compress && GLAD_GL_EXT_texture_compression_s3tc)
|
||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
else
|
||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/fontenc.h>
|
||||
#include "Job.hpp"
|
||||
|
||||
@@ -219,7 +219,7 @@ void create_volume(TriangleMesh &&mesh, const ObjectID& object_id, const ModelVo
|
||||
/// Create projection for cut surface from mesh
|
||||
/// </summary>
|
||||
/// <param name="tr">Volume transformation in object</param>
|
||||
/// <param name="shape_scale">Convert shape to milimeters</param>
|
||||
/// <param name="shape_scale">Convert shape to millimeters</param>
|
||||
/// <param name="z_range">Bounding box 3d of model volume for projection ranges</param>
|
||||
/// <returns>Orthogonal cut_projection</returns>
|
||||
OrthoProject create_projection_for_cut(Transform3d tr, double shape_scale, const std::pair<float, float> &z_range);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#include "LinuxDisplayBackend.hpp"
|
||||
|
||||
#if defined(__WXGTK__)
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#ifdef wxHAVE_GDK_X11
|
||||
#include <gdk/gdkx.h>
|
||||
#endif
|
||||
|
||||
#ifdef wxHAVE_GDK_WAYLAND
|
||||
#include <gdk/gdkwayland.h>
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
LinuxDisplayBackend get_linux_display_backend()
|
||||
{
|
||||
static const LinuxDisplayBackend backend = []() -> LinuxDisplayBackend {
|
||||
GdkDisplay *display = gdk_display_get_default();
|
||||
if (!display)
|
||||
return LinuxDisplayBackend::Unknown;
|
||||
|
||||
#ifdef wxHAVE_GDK_WAYLAND
|
||||
if (GDK_IS_WAYLAND_DISPLAY(display))
|
||||
return LinuxDisplayBackend::Wayland;
|
||||
#endif
|
||||
|
||||
#ifdef wxHAVE_GDK_X11
|
||||
if (GDK_IS_X11_DISPLAY(display))
|
||||
return LinuxDisplayBackend::X11;
|
||||
#endif
|
||||
|
||||
return LinuxDisplayBackend::Unknown;
|
||||
}();
|
||||
return backend;
|
||||
}
|
||||
|
||||
bool is_running_on_wayland()
|
||||
{
|
||||
return get_linux_display_backend() == LinuxDisplayBackend::Wayland;
|
||||
}
|
||||
|
||||
bool is_running_on_x11()
|
||||
{
|
||||
return get_linux_display_backend() == LinuxDisplayBackend::X11;
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // defined(__WXGTK__)
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
#if defined(__WXGTK__)
|
||||
|
||||
enum class LinuxDisplayBackend { X11, Wayland, Unknown };
|
||||
|
||||
// Detect which display backend is in use at runtime.
|
||||
// Must be called after gtk_init() / wxWidgets initialization.
|
||||
LinuxDisplayBackend get_linux_display_backend();
|
||||
|
||||
// Convenience predicates.
|
||||
bool is_running_on_wayland();
|
||||
bool is_running_on_x11();
|
||||
|
||||
#endif // defined(__WXGTK__)
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
@@ -310,6 +310,17 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
|
||||
m_edge_right = new ResizeEdgePanel(this, ResizeEdgePanel::Right);
|
||||
#endif
|
||||
|
||||
#ifdef __WXMSW__
|
||||
if (HWND hWnd = GetHandle(); hWnd != nullptr) {
|
||||
LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE);
|
||||
if ((style & WS_CAPTION) != 0) {
|
||||
SetWindowLongPtr(hWnd, GWL_STYLE, style & ~WS_CAPTION);
|
||||
SetWindowPos(hWnd, nullptr, 0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!wxGetApp().app_config->has("user_mode")) {
|
||||
wxGetApp().app_config->set("user_mode", "simple");
|
||||
wxGetApp().app_config->set_bool("developer_mode", false);
|
||||
@@ -524,6 +535,28 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
|
||||
update_layout();
|
||||
sizer->SetSizeHints(this);
|
||||
|
||||
#ifdef __WXMSW__
|
||||
// SetMaximize causes the window to overlap the taskbar, due to the fact this window has wxMAXIMIZE_BOX off
|
||||
// https://forums.wxwidgets.org/viewtopic.php?t=50634
|
||||
// Fix it here
|
||||
this->Bind(wxEVT_MAXIMIZE, [this](auto &e) {
|
||||
wxDisplay display(this);
|
||||
auto size = display.GetClientArea().GetSize();
|
||||
auto pos = display.GetClientArea().GetPosition();
|
||||
HWND hWnd = GetHandle();
|
||||
RECT borderThickness;
|
||||
SetRectEmpty(&borderThickness);
|
||||
AdjustWindowRectEx(&borderThickness, GetWindowLongPtr(hWnd, GWL_STYLE), FALSE, 0);
|
||||
const auto max_size = size + wxSize{-borderThickness.left + borderThickness.right, -borderThickness.top + borderThickness.bottom};
|
||||
const auto current_size = GetSize();
|
||||
SetSize({std::min(max_size.x, current_size.x), std::min(max_size.y, current_size.y)});
|
||||
Move(pos + wxPoint{borderThickness.left, borderThickness.top});
|
||||
e.Skip();
|
||||
});
|
||||
|
||||
#endif // __WXMSW__
|
||||
|
||||
|
||||
// BBS
|
||||
Fit();
|
||||
|
||||
@@ -586,6 +619,8 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
|
||||
#endif
|
||||
|
||||
MarkdownTip::ExitTip();
|
||||
// Prevent queued selection/UI refresh work from running as normal during reset.
|
||||
wxGetApp().set_closing(true);
|
||||
|
||||
m_plater->reset();
|
||||
this->shutdown();
|
||||
@@ -758,7 +793,7 @@ void MainFrame::bind_diff_dialog()
|
||||
}
|
||||
|
||||
|
||||
#ifdef __WIN32__
|
||||
#ifdef __WXMSW__
|
||||
|
||||
// Orca: Fix maximized window overlaps taskbar when taskbar auto hide is enabled (#8085)
|
||||
// Adopted from https://gist.github.com/MortenChristiansen/6463580
|
||||
|
||||
@@ -204,7 +204,7 @@ protected:
|
||||
virtual void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
virtual void on_sys_color_changed() override;
|
||||
|
||||
#ifdef __WIN32__
|
||||
#ifdef __WXMSW__
|
||||
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "slic3r/GUI/CameraUtils.hpp"
|
||||
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <igl/unproject.h>
|
||||
|
||||
|
||||
@@ -205,8 +205,8 @@ void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable)
|
||||
if (m_printable == printable)
|
||||
return;
|
||||
m_printable = printable;
|
||||
m_printable_icon = m_printable == piUndef ? m_empty_bmp :
|
||||
create_scaled_bitmap(m_printable == piPrintable ? "check_on" : "check_off_focused");
|
||||
m_printable_icon = m_printable == piUndef ?
|
||||
m_empty_bmp : create_scaled_bitmap(m_printable == piPrintable ? "check_on" : "check_off_focused");
|
||||
}
|
||||
|
||||
void ObjectDataViewModelNode::set_variable_height_icon(VaryHeightIndicator vari_height) {
|
||||
|
||||
@@ -241,7 +241,7 @@ public:
|
||||
void SetExtruder(const wxString &extruder) { m_extruder = extruder; }
|
||||
void SetWarningIconName(const std::string& warning_icon_name) { m_warning_icon_name = warning_icon_name; }
|
||||
void SetLock(bool has_lock) { m_has_lock = has_lock; }
|
||||
const wxBitmap& GetBitmap() const { return m_bmp; }
|
||||
const wxBitmap& GetBitmap() const { return m_bmp; }
|
||||
const wxString& GetName() const { return m_name; }
|
||||
ItemType GetType() const { return m_type; }
|
||||
InfoItemType GetInfoItemType() const { return m_info_item_type; }
|
||||
@@ -249,16 +249,16 @@ public:
|
||||
int GetIdx() const { return m_idx; }
|
||||
//BBS: add part plate related logic
|
||||
void SetPlateIdx(const int& idx);
|
||||
int GetPlateIdx() const { return m_plate_idx; }
|
||||
int GetPlateIdx() const { return m_plate_idx; }
|
||||
ModelVolumeType GetVolumeType() { return m_volume_type; }
|
||||
t_layer_height_range GetLayerRange() const { return m_layer_range; }
|
||||
wxString GetExtruder() { return m_extruder; }
|
||||
PrintIndicator IsPrintable() const { return m_printable; }
|
||||
VaryHeightIndicator IsVaribaleHeight() const { return m_variable_height; }
|
||||
VaryHeightIndicator IsVaribaleHeight() const { return m_variable_height; }
|
||||
// BBS
|
||||
bool HasColorPainting() const { return m_color_enable; }
|
||||
bool HasSupportPainting() const { return m_support_enable; }
|
||||
bool HasSinking() const { return m_sink_enable; }
|
||||
bool HasSupportPainting() const { return m_support_enable; }
|
||||
bool HasSinking() const { return m_sink_enable; }
|
||||
bool IsActionEnabled() const { return m_action_enable; }
|
||||
void UpdateExtruderAndColorIcon(wxString extruder = "");
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "libslic3r/Platform.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
@@ -22,16 +22,11 @@
|
||||
#include "../Utils/MacDarkMode.hpp"
|
||||
#endif // __APPLE__
|
||||
|
||||
// Verify GLEW and wxWidgets use the same OpenGL backend (EGL vs GLX).
|
||||
// A mismatch causes rendering failures: GLEW's function loading must match
|
||||
// the context type created by wxWidgets.
|
||||
#if defined(__linux__)
|
||||
#if defined(GLEW_EGL) && (!defined(wxUSE_GLCANVAS_EGL) || !wxUSE_GLCANVAS_EGL)
|
||||
#error "OpenGL backend mismatch: GLEW has EGL support enabled but wxWidgets does not. Ensure GLEW_USE_EGL and wxUSE_GLCANVAS_EGL are both ON or both OFF."
|
||||
#endif
|
||||
#if !defined(GLEW_EGL) && defined(wxUSE_GLCANVAS_EGL) && wxUSE_GLCANVAS_EGL
|
||||
#error "OpenGL backend mismatch: wxWidgets has EGL support enabled but GLEW does not. Ensure GLEW_USE_EGL and wxUSE_GLCANVAS_EGL are both ON or both OFF."
|
||||
#endif
|
||||
#ifdef __WXGTK__
|
||||
#include "LinuxDisplayBackend.hpp"
|
||||
#ifdef wxHAS_EGL
|
||||
#include <EGL/egl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
@@ -121,12 +116,12 @@ void OpenGLManager::GLInfo::detect() const
|
||||
if (Slic3r::total_physical_memory() / (1024 * 1024 * 1024) < 6)
|
||||
*max_tex_size /= 2;
|
||||
|
||||
if (GLEW_EXT_texture_filter_anisotropic) {
|
||||
if (GLAD_GL_EXT_texture_filter_anisotropic) {
|
||||
float* max_anisotropy = const_cast<float*>(&m_max_anisotropy);
|
||||
glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy));
|
||||
}
|
||||
|
||||
if (!GLEW_ARB_compatibility)
|
||||
if (!GLAD_GL_ARB_compatibility)
|
||||
*const_cast<bool*>(&m_core_profile) = true;
|
||||
|
||||
*const_cast<bool*>(&m_detected) = true;
|
||||
@@ -245,24 +240,36 @@ OpenGLManager::~OpenGLManager()
|
||||
bool OpenGLManager::init_gl(bool popup_error)
|
||||
{
|
||||
if (!m_gl_initialized) {
|
||||
glewExperimental = true;
|
||||
GLenum result = glewInit();
|
||||
if (result != GLEW_OK) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Unable to init glew library, Error: " << glewGetErrorString(result);
|
||||
int version = 0;
|
||||
#if defined(__WXGTK__) && defined(wxHAS_EGL)
|
||||
if (is_running_on_wayland()) {
|
||||
// On EGL/Wayland, gladLoaderLoadGL() dlopen's libGL.so then
|
||||
// immediately dlclose's it. Since nothing else holds libGL.so
|
||||
// open (unlike GLX where the context keeps it loaded), the
|
||||
// library gets unmapped and all function pointers become invalid.
|
||||
// Use eglGetProcAddress directly to avoid this.
|
||||
version = gladLoadGL((GLADloadfunc)eglGetProcAddress);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
version = gladLoaderLoadGL();
|
||||
}
|
||||
if (version == 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Unable to init GLAD OpenGL loader";
|
||||
return false;
|
||||
}
|
||||
//BOOST_LOG_TRIVIAL(info) << "glewInit Success."<< std::endl;
|
||||
BOOST_LOG_TRIVIAL(info) << "GLAD loaded OpenGL " << GLAD_VERSION_MAJOR(version) << "." << GLAD_VERSION_MINOR(version);
|
||||
m_gl_initialized = true;
|
||||
if (GLEW_EXT_texture_compression_s3tc)
|
||||
if (GLAD_GL_EXT_texture_compression_s3tc)
|
||||
s_compressed_textures_supported = true;
|
||||
else
|
||||
s_compressed_textures_supported = false;
|
||||
|
||||
if (GLEW_ARB_framebuffer_object) {
|
||||
if (GLAD_GL_ARB_framebuffer_object) {
|
||||
s_framebuffers_type = EFramebufferType::Arb;
|
||||
BOOST_LOG_TRIVIAL(info) << "Found Framebuffer Type ARB."<< std::endl;
|
||||
}
|
||||
else if (GLEW_EXT_framebuffer_object) {
|
||||
else if (GLAD_GL_EXT_framebuffer_object) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Found Framebuffer Type Ext."<< std::endl;
|
||||
s_framebuffers_type = EFramebufferType::Ext;
|
||||
}
|
||||
@@ -438,6 +445,20 @@ void OpenGLManager::detect_multisample(int* attribList)
|
||||
{
|
||||
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER;
|
||||
bool enable_multisample = wxVersion >= 30003;
|
||||
|
||||
#if defined(__WXGTK__)
|
||||
// On Wayland, wxGLCanvas::IsDisplaySupported() requires the EGL backend.
|
||||
// If wxWidgets was built without EGL, the GLX backend will crash trying
|
||||
// to access a non-existent X11 display. Disable multisample in that case.
|
||||
if (is_running_on_wayland()) {
|
||||
#if !defined(wxHAS_EGL) || !wxHAS_EGL
|
||||
BOOST_LOG_TRIVIAL(warning) << "Wayland without EGL: disabling multisample detection";
|
||||
s_multisample = EMultisampleState::Disabled;
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
s_multisample =
|
||||
enable_multisample &&
|
||||
// Disable multi-sampling on ChromeOS, as the OpenGL virtualization swaps Red/Blue channels with multi-sampling enabled,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <set>
|
||||
#include <regex>
|
||||
#include <future>
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
@@ -1678,9 +1678,12 @@ void PartPlate::render_icon_texture(GLModel &buffer, GLTexture &texture)
|
||||
|
||||
void PartPlate::render_plate_name_texture()
|
||||
{
|
||||
if (m_name_texture.get_id() == 0)
|
||||
if (m_plate_name_edit_icon.mesh_raycaster == nullptr)
|
||||
generate_plate_name_texture();
|
||||
|
||||
if (m_name_texture.get_id() == 0)
|
||||
return;
|
||||
|
||||
GLuint tex_id = (GLuint)m_name_texture.get_id();
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id));
|
||||
m_plate_name_icon.render();
|
||||
@@ -2091,6 +2094,9 @@ void PartPlate::render_right_arrow(const ColorRGBA render_color, bool use_lighti
|
||||
|
||||
static void register_model_for_picking(GLCanvas3D &canvas, PickingModel &model, int id)
|
||||
{
|
||||
if (model.mesh_raycaster == nullptr)
|
||||
return;
|
||||
|
||||
canvas.add_raycaster_for_picking(SceneRaycaster::EType::Bed, id, *model.mesh_raycaster, Transform3d::Identity());
|
||||
}
|
||||
|
||||
@@ -2105,7 +2111,10 @@ void PartPlate::register_raycasters_for_picking(GLCanvas3D &canvas)
|
||||
register_model_for_picking(canvas, m_plate_settings_icon, picking_id_component(5));
|
||||
|
||||
canvas.remove_raycasters_for_picking(SceneRaycaster::EType::Bed, picking_id_component(6));
|
||||
register_model_for_picking(canvas, m_plate_name_edit_icon, picking_id_component(6));
|
||||
// Plate-name edit picking is built lazily together with the plate-name texture.
|
||||
// During reset / reload_scene the icon may not have a raycaster yet, which is valid.
|
||||
if (m_plate_name_edit_icon.mesh_raycaster != nullptr)
|
||||
register_model_for_picking(canvas, m_plate_name_edit_icon, picking_id_component(6));
|
||||
register_model_for_picking(canvas, m_move_front_icon, picking_id_component(7));
|
||||
|
||||
// Only register filament map button for H2D (dual-extruder Bambu Lab) printers
|
||||
@@ -2862,7 +2871,7 @@ void PartPlate::clear(bool clear_sliced_result)
|
||||
m_ready_for_slice = true;
|
||||
update_slice_result_valid_state(false);
|
||||
}
|
||||
m_name_texture.reset();
|
||||
invalidate_plate_name_texture();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2952,6 +2961,10 @@ Vec3d PartPlate::get_center_origin()
|
||||
|
||||
void PartPlate::generate_plate_name_texture()
|
||||
{
|
||||
auto canvas = this->m_partplate_list->m_plater->get_view3D_canvas3D();
|
||||
if (canvas == nullptr)
|
||||
return;
|
||||
|
||||
m_plate_name_icon.reset();
|
||||
|
||||
// generate m_name_texture texture from m_name with generate_from_text_string
|
||||
@@ -2964,8 +2977,10 @@ void PartPlate::generate_plate_name_texture()
|
||||
wxFont* font = &l;
|
||||
|
||||
wxColour foreground(0xf2, 0x75, 0x4e, 0xff);
|
||||
if (!m_name_texture.generate_from_text_string(text.ToUTF8().data(), *font, *wxBLACK, foreground))
|
||||
if (!m_name_texture.generate_from_text_string(text.ToUTF8().data(), *font, *wxBLACK, foreground)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "PartPlate::generate_plate_name_texture(): generate_from_text_string() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
ExPolygon poly;
|
||||
auto bed_ext = get_extents(m_shape);
|
||||
@@ -2989,11 +3004,22 @@ void PartPlate::generate_plate_name_texture()
|
||||
if (!init_model_from_poly(m_plate_name_icon, poly, GROUND_Z))
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n";
|
||||
|
||||
auto canvas = this->m_partplate_list->m_plater->get_view3D_canvas3D();
|
||||
canvas->remove_raycasters_for_picking(SceneRaycaster::EType::Bed, picking_id_component(6));
|
||||
calc_vertex_for_plate_name_edit_icon(&m_name_texture, 0, m_plate_name_edit_icon);
|
||||
register_model_for_picking(*canvas, m_plate_name_edit_icon, picking_id_component(6));
|
||||
}
|
||||
|
||||
void PartPlate::invalidate_plate_name_texture()
|
||||
{
|
||||
m_plate_name_edit_icon.mesh_raycaster.reset();
|
||||
|
||||
auto canvas = (m_plater != nullptr) ? m_plater->get_view3D_canvas3D() : nullptr;
|
||||
if (canvas != nullptr) {
|
||||
canvas->remove_raycasters_for_picking(SceneRaycaster::EType::Bed, picking_id_component(6));
|
||||
canvas->set_as_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
void PartPlate::set_plate_name(const std::string& name)
|
||||
{
|
||||
// compare if name equal to m_name, case sensitive
|
||||
@@ -3004,7 +3030,7 @@ void PartPlate::set_plate_name(const std::string& name)
|
||||
if (m_print != nullptr)
|
||||
m_print->set_plate_name(name);
|
||||
|
||||
generate_plate_name_texture();
|
||||
invalidate_plate_name_texture();
|
||||
}
|
||||
|
||||
//get the print's object, result and index
|
||||
@@ -3816,7 +3842,7 @@ bool PartPlate::set_shape(const Pointfs& shape, const Pointfs& exclude_areas, co
|
||||
|
||||
calc_vertex_for_number(0, false, m_plate_idx_icon);
|
||||
// calc vertex for plate name
|
||||
generate_plate_name_texture();
|
||||
invalidate_plate_name_texture();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -217,6 +217,7 @@ private:
|
||||
void render_icons(bool bottom, bool only_name = false, int hover_id = -1);
|
||||
void render_only_numbers(bool bottom);
|
||||
void render_plate_name_texture();
|
||||
void invalidate_plate_name_texture();
|
||||
void register_raycasters_for_picking(GLCanvas3D& canvas);
|
||||
int picking_id_component(int idx) const;
|
||||
|
||||
|
||||
+178
-30
@@ -76,6 +76,9 @@
|
||||
#include "GUI_App.hpp"
|
||||
#include "GuiColor.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#ifdef __WXGTK__
|
||||
#include "LinuxDisplayBackend.hpp"
|
||||
#endif
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "GUI_Factories.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
@@ -349,6 +352,57 @@ void SlicedInfo::SetTextAndShow(SlicedInfoIdx idx, const wxString& text, const w
|
||||
|
||||
static wxString temp_dir;
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef __WXGTK__
|
||||
wxString sanitize_window_layout_for_wayland(const wxString& layout, bool* removed_floating_state = nullptr)
|
||||
{
|
||||
if (!Slic3r::GUI::is_running_on_wayland() || layout.empty()) {
|
||||
if (removed_floating_state != nullptr)
|
||||
*removed_floating_state = false;
|
||||
return layout;
|
||||
}
|
||||
|
||||
static const std::regex state_pattern(R"(state=(\d+);)");
|
||||
constexpr unsigned int disabled_wayland_flags =
|
||||
static_cast<unsigned int>(wxAuiPaneInfo::optionFloating) |
|
||||
static_cast<unsigned int>(wxAuiPaneInfo::optionFloatable);
|
||||
|
||||
const std::string input = layout.utf8_string();
|
||||
std::string output;
|
||||
output.reserve(input.size());
|
||||
|
||||
bool modified = false;
|
||||
std::smatch match;
|
||||
auto search_start = input.cbegin();
|
||||
|
||||
while (std::regex_search(search_start, input.cend(), match, state_pattern)) {
|
||||
output.append(search_start, match[0].first);
|
||||
|
||||
try {
|
||||
const unsigned long state = std::stoul(match[1].str());
|
||||
const unsigned long sanitized_state = state & ~static_cast<unsigned long>(disabled_wayland_flags);
|
||||
modified = modified || sanitized_state != state;
|
||||
|
||||
output += "state=" + std::to_string(sanitized_state) + ";";
|
||||
} catch (const std::exception&) {
|
||||
output += match[0].str();
|
||||
}
|
||||
|
||||
search_start = match[0].second;
|
||||
}
|
||||
|
||||
output.append(search_start, input.cend());
|
||||
|
||||
if (removed_floating_state != nullptr)
|
||||
*removed_floating_state = modified;
|
||||
|
||||
return modified ? wxString::FromUTF8(output) : layout;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
// Sidebar / private
|
||||
|
||||
enum class ActionButtonType : int {
|
||||
@@ -1782,7 +1836,11 @@ Sidebar::Sidebar(Plater *parent)
|
||||
e.Skip();
|
||||
});
|
||||
w->Bind(wxEVT_LEAVE_WINDOW, [this, panel_color](wxMouseEvent &e) {
|
||||
wxWindow* next_w = wxFindWindowAtPoint(wxGetMousePosition());
|
||||
// Use event-relative coords instead of wxGetMousePosition() which
|
||||
// returns (0,0) on Wayland for global screen coordinates.
|
||||
wxWindow* evtObj = dynamic_cast<wxWindow*>(e.GetEventObject());
|
||||
wxPoint screenPos = evtObj ? evtObj->ClientToScreen(e.GetPosition()) : wxGetMousePosition();
|
||||
wxWindow* next_w = wxFindWindowAtPoint(screenPos);
|
||||
if (!next_w || !p->panel_printer_preset->IsDescendant(next_w)){
|
||||
if(!p->combo_printer->HasFocus())
|
||||
p->panel_printer_preset->SetBorderColor(panel_color.bd_normal);
|
||||
@@ -1844,7 +1902,11 @@ Sidebar::Sidebar(Plater *parent)
|
||||
e.Skip();
|
||||
});
|
||||
w->Bind(wxEVT_LEAVE_WINDOW, [this, panel_color](wxMouseEvent &e) {
|
||||
wxWindow* next_w = wxFindWindowAtPoint(wxGetMousePosition());
|
||||
// Use event-relative coords instead of wxGetMousePosition() which
|
||||
// returns (0,0) on Wayland for global screen coordinates.
|
||||
wxWindow* evtObj = dynamic_cast<wxWindow*>(e.GetEventObject());
|
||||
wxPoint screenPos = evtObj ? evtObj->ClientToScreen(e.GetPosition()) : wxGetMousePosition();
|
||||
wxWindow* next_w = wxFindWindowAtPoint(screenPos);
|
||||
if (!p->combo_nozzle_dia->HasFocus() && (!next_w || !p->panel_nozzle_dia->IsDescendant(next_w)))
|
||||
p->panel_nozzle_dia->SetBorderColor(panel_color.bd_normal);
|
||||
e.Skip();
|
||||
@@ -1914,7 +1976,11 @@ Sidebar::Sidebar(Plater *parent)
|
||||
e.Skip();
|
||||
});
|
||||
w->Bind(wxEVT_LEAVE_WINDOW, [this, w, panel_color](wxMouseEvent &e) {
|
||||
wxWindow* next_w = wxFindWindowAtPoint(wxGetMousePosition());
|
||||
// Use event-relative coords instead of wxGetMousePosition() which
|
||||
// returns (0,0) on Wayland for global screen coordinates.
|
||||
wxWindow* evtObj = dynamic_cast<wxWindow*>(e.GetEventObject());
|
||||
wxPoint screenPos = evtObj ? evtObj->ClientToScreen(e.GetPosition()) : wxGetMousePosition();
|
||||
wxWindow* next_w = wxFindWindowAtPoint(screenPos);
|
||||
if (!p->combo_printer_bed->HasFocus() && (!next_w || !p->panel_printer_bed->IsDescendant(next_w)))
|
||||
p->panel_printer_bed->SetBorderColor(panel_color.bd_normal);
|
||||
if(w == p->image_printer_bed)
|
||||
@@ -4442,7 +4508,7 @@ struct Plater::priv
|
||||
|
||||
// BBS: backup & restore
|
||||
std::vector<size_t> load_files(const std::vector<fs::path>& input_files, LoadStrategy strategy, bool ask_multi = false);
|
||||
std::vector<size_t> load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false, bool split_object = false);
|
||||
std::vector<size_t> load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false, bool split_object = false, bool auto_drop = true);
|
||||
|
||||
fs::path get_export_file_path(GUI::FileType file_type);
|
||||
wxString get_export_file(GUI::FileType file_type);
|
||||
@@ -4473,7 +4539,8 @@ struct Plater::priv
|
||||
void center_selection();
|
||||
void drop_selection();
|
||||
void mirror(Axis axis);
|
||||
void split_object();
|
||||
void split_object(bool auto_drop = true);
|
||||
void split_object(int obj_idx, bool auto_drop = true);
|
||||
void split_volume();
|
||||
void scale_selection_to_fit_print_volume();
|
||||
|
||||
@@ -4837,8 +4904,16 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
{
|
||||
m_is_dark = wxGetApp().app_config->get("dark_color_mode") == "1";
|
||||
|
||||
#ifdef __WXGTK__
|
||||
const bool disable_wayland_floating = Slic3r::GUI::is_running_on_wayland();
|
||||
#endif
|
||||
|
||||
m_aui_mgr.SetManagedWindow(q);
|
||||
m_aui_mgr.SetDockSizeConstraint(1, 1);
|
||||
#ifdef __WXGTK__
|
||||
if (disable_wayland_floating)
|
||||
m_aui_mgr.SetFlags(m_aui_mgr.GetFlags() & ~wxAUI_MGR_ALLOW_FLOATING);
|
||||
#endif
|
||||
//m_aui_mgr.GetArtProvider()->SetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE, 0);
|
||||
//m_aui_mgr.GetArtProvider()->SetMetric(wxAUI_DOCKART_SASH_SIZE, 2);
|
||||
m_aui_mgr.GetArtProvider()->SetMetric(wxAUI_DOCKART_CAPTION_SIZE, 18);
|
||||
@@ -4930,7 +5005,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
.CloseButton(false)
|
||||
.TopDockable(false)
|
||||
.BottomDockable(false)
|
||||
.Floatable(true)
|
||||
.BestSize(wxSize(39 * wxGetApp().em_unit(), 90 * wxGetApp().em_unit())));
|
||||
|
||||
auto* panel_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
@@ -4949,7 +5023,19 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
const auto cfg = wxGetApp().app_config;
|
||||
wxString layout = wxString::FromUTF8(cfg->get("window_layout"));
|
||||
if (!layout.empty()) {
|
||||
m_aui_mgr.LoadPerspective(layout, false);
|
||||
bool removed_floating_state = false;
|
||||
#ifdef __WXGTK__
|
||||
if (disable_wayland_floating)
|
||||
layout = sanitize_window_layout_for_wayland(layout, &removed_floating_state);
|
||||
#endif
|
||||
|
||||
if (!m_aui_mgr.LoadPerspective(layout, false)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Failed to restore saved window layout";
|
||||
m_aui_mgr.LoadPerspective(m_default_window_layout, false);
|
||||
} else if (removed_floating_state) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Removed floating AUI state from saved window layout for Wayland";
|
||||
}
|
||||
|
||||
sidebar_layout.is_collapsed = !sidebar.IsShown();
|
||||
}
|
||||
|
||||
@@ -6632,14 +6718,37 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
if (new_model != nullptr && new_model->objects.size() > 1) {
|
||||
//BBS do not popup this dialog
|
||||
|
||||
bool new_model_auto_drop = true;
|
||||
int single_object_answer = false;
|
||||
if (ask_multi) {
|
||||
MessageDialog msg_dlg(q, _L("Load these files as a single object with multiple parts?\n"), _L("Object with multiple parts was detected"),
|
||||
wxICON_WARNING | wxYES | wxNO);
|
||||
if (msg_dlg.ShowModal() == wxID_YES) { new_model->convert_multipart_object(filaments_cnt); }
|
||||
RichMessageDialog dlg(q, _L("Load these files as a single object with multiple parts?\n"),
|
||||
_L("Object with multiple parts was detected"), wxICON_QUESTION | wxYES_NO);
|
||||
|
||||
dlg.ShowCheckBox(_L("Auto-Drop"), true);
|
||||
single_object_answer = dlg.ShowModal();
|
||||
|
||||
if (dlg.IsCheckBoxChecked() == false)
|
||||
new_model_auto_drop = false;
|
||||
|
||||
// convert to multipart and split after load_model_objects
|
||||
// to keep relative positioning if auto_drop == false
|
||||
if (single_object_answer == wxID_YES || new_model_auto_drop == false)
|
||||
new_model->convert_multipart_object(filaments_cnt);
|
||||
}
|
||||
|
||||
auto loaded_idxs = load_model_objects(new_model->objects);
|
||||
// TODO
|
||||
// DONE always convert to multipart, split afterwards to retain relative position
|
||||
// DONE if !auto_drop move all objects over the z-position 0, so that none are clipped by the bed.
|
||||
// DONE retain auto_drop (and printable) state when assembling or splitting objects.
|
||||
// DONE when manually split to object ask users if looks_like_multipart and none have auto_drob disabled if they want to disable auto_drop for all resulting objects.
|
||||
// - add icon in object list, similar to fuzzy painting, etc.
|
||||
|
||||
auto loaded_idxs = load_model_objects(new_model->objects, false, false, new_model_auto_drop);
|
||||
obj_idxs.insert(obj_idxs.end(), loaded_idxs.begin(), loaded_idxs.end());
|
||||
|
||||
if (single_object_answer == wxID_NO && new_model_auto_drop == false) {
|
||||
split_object(loaded_idxs[0], new_model_auto_drop);
|
||||
}
|
||||
}
|
||||
|
||||
if (load_config) {
|
||||
@@ -6806,7 +6915,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
|
||||
#define AUTOPLACEMENT_ON_LOAD
|
||||
|
||||
std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z, bool split_object)
|
||||
std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z, bool split_object, bool auto_drop)
|
||||
{
|
||||
const Vec3d bed_size = Slic3r::to_3d(this->bed.build_volume().bounding_volume2d().size(), 1.0) - 2.0 * Vec3d::Ones();
|
||||
|
||||
@@ -6833,7 +6942,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
|
||||
#else /* AUTOPLACEMENT_ON_LOAD */
|
||||
// if object has no defined position(s) we need to rearrange everything after loading
|
||||
// need_arrange = true;
|
||||
// add a default instance and center object around origin
|
||||
// add a default instance and center object around origin
|
||||
object->center_around_origin(); // also aligns object to Z = 0
|
||||
ModelInstance* instance = object->add_instance();
|
||||
|
||||
@@ -6842,7 +6951,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
|
||||
instance->set_offset(Slic3r::to_3d(this->bed.build_volume().bed_center(), -object->origin_translation(2)));
|
||||
#endif /* AUTOPLACEMENT_ON_LOAD */
|
||||
}
|
||||
|
||||
|
||||
//BBS: when the object is too large, let the user choose whether to scale it down
|
||||
for (size_t i = 0; i < object->instances.size(); ++i) {
|
||||
ModelInstance* instance = object->instances[i];
|
||||
@@ -6872,7 +6981,20 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
|
||||
}
|
||||
}
|
||||
|
||||
object->ensure_on_bed(allow_negative_z);
|
||||
if (!auto_drop) {
|
||||
for (size_t i = 0; i < object->instances.size(); ++i) {
|
||||
ModelInstance* instance = object->instances[i];
|
||||
instance->auto_drop = auto_drop;
|
||||
}
|
||||
|
||||
// if under the bed, move over the bed
|
||||
double dist_to_bed = std::min(object->min_z(), double(0));
|
||||
object->translate_instances(Vec3d(0, 0, -dist_to_bed));
|
||||
}
|
||||
else {
|
||||
object->ensure_on_bed(allow_negative_z);
|
||||
}
|
||||
|
||||
if (!split_object) {
|
||||
//BBS initial assemble transformation
|
||||
for (ModelObject* model_object : model.objects) {
|
||||
@@ -6882,7 +7004,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
|
||||
model_object->instances[i]->set_assemble_transformation(model_object->instances[i]->get_transformation());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6949,7 +7071,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
|
||||
// which is updated after a view3D->reload_scene(false, flags & (unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH) call
|
||||
for (const size_t idx : obj_idxs)
|
||||
wxGetApp().obj_list()->update_info_items(idx);
|
||||
|
||||
|
||||
object_list_changed();
|
||||
|
||||
this->schedule_background_process();
|
||||
@@ -7401,9 +7523,16 @@ void Plater::find_new_position(const ModelInstancePtrs &instances)
|
||||
m.apply();
|
||||
}
|
||||
|
||||
void Plater::priv::split_object()
|
||||
{
|
||||
// split selected object into multiple objects by its volumes
|
||||
void Plater::priv::split_object(bool auto_drop /* = true */)
|
||||
{
|
||||
int obj_idx = get_selected_object_idx();
|
||||
priv::split_object(obj_idx, auto_drop);
|
||||
}
|
||||
|
||||
// split provided object into multiple objects by its volumes
|
||||
void Plater::priv::split_object(int obj_idx, bool auto_drop /* = true */)
|
||||
{
|
||||
if (obj_idx == -1)
|
||||
return;
|
||||
|
||||
@@ -7429,12 +7558,30 @@ void Plater::priv::split_object()
|
||||
|
||||
Plater::TakeSnapshot snapshot(q, "Split to Objects");
|
||||
|
||||
auto is_atleast_one_floating = [new_objects]() {
|
||||
for (ModelObject* new_object : new_objects) {
|
||||
if (new_object->get_instance_min_z(0) >= SINKING_MIN_Z_THRESHOLD)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
bool split_auto_drop = auto_drop;
|
||||
if (current_model_object->instances[0]->auto_drop && is_atleast_one_floating()) {
|
||||
MessageDialog dlg(q, _L("Disable Auto-Drop to preserve z positioning?\n"),
|
||||
_L("Object with floating parts was detected"), wxICON_QUESTION | wxYES_NO);
|
||||
|
||||
if (dlg.ShowModal() == wxID_YES)
|
||||
split_auto_drop = false;
|
||||
}
|
||||
|
||||
remove(obj_idx);
|
||||
|
||||
// load all model objects at once, otherwise the plate would be rearranged after each one
|
||||
// causing original positions not to be kept
|
||||
//BBS: set split_object to true to avoid re-compute assemble matrix
|
||||
std::vector<size_t> idxs = load_model_objects(new_objects, false, true);
|
||||
std::vector<size_t> idxs = load_model_objects(new_objects, false, true, split_auto_drop);
|
||||
|
||||
wxGetApp().plater()->get_view3D_canvas3D()->update_instance_printable_state_for_objects(idxs);
|
||||
|
||||
// select newly added objects
|
||||
for (size_t idx : idxs)
|
||||
@@ -8897,11 +9044,9 @@ void Plater::priv::set_current_panel(wxPanel* panel, bool no_slice)
|
||||
wxPanel* old_panel = current_panel;
|
||||
//#if BBL_HAS_FIRST_PAGE
|
||||
if (!old_panel) {
|
||||
//BBS: only switch to the first panel when visible
|
||||
// Wayland may report the first canvas as not yet shown while the frame is still mapping.
|
||||
// Keep the panel switch anyway so handlers are bound and the first paint can initialize GL later.
|
||||
panel->Show();
|
||||
//dynamic_cast<View3D *>(panel)->get_canvas3d()->render();
|
||||
if (!panel->IsShownOnScreen())
|
||||
return;
|
||||
}
|
||||
//#endif
|
||||
current_panel = panel;
|
||||
@@ -10221,6 +10366,9 @@ void Plater::priv::on_action_split_volumes(SimpleEvent&)
|
||||
|
||||
void Plater::priv::on_object_select(SimpleEvent& evt)
|
||||
{
|
||||
if (wxGetApp().is_closing())
|
||||
return;
|
||||
|
||||
wxGetApp().obj_list()->update_selections();
|
||||
selection_changed();
|
||||
}
|
||||
@@ -16752,7 +16900,7 @@ const GLCanvas3D* Plater::canvas3D() const
|
||||
|
||||
GLCanvas3D* Plater::get_view3D_canvas3D()
|
||||
{
|
||||
return p->view3D->get_canvas3d();
|
||||
return p ? p->view3D->get_canvas3d() : nullptr;
|
||||
}
|
||||
|
||||
GLCanvas3D* Plater::get_preview_canvas3D()
|
||||
@@ -16943,11 +17091,11 @@ void Plater::suppress_background_process(const bool stop_background_process)
|
||||
this->p->suppressed_backround_processing_update = true;
|
||||
}
|
||||
|
||||
void Plater::center_selection() { p->center_selection(); }
|
||||
void Plater::drop_selection() { p->drop_selection(); }
|
||||
void Plater::mirror(Axis axis) { p->mirror(axis); }
|
||||
void Plater::split_object() { p->split_object(); }
|
||||
void Plater::split_volume() { p->split_volume(); }
|
||||
void Plater::center_selection() { p->center_selection(); }
|
||||
void Plater::drop_selection() { p->drop_selection(); }
|
||||
void Plater::mirror(Axis axis) { p->mirror(axis); }
|
||||
void Plater::split_object(bool auto_drop) { p->split_object(auto_drop); }
|
||||
void Plater::split_volume() { p->split_volume(); }
|
||||
void Plater::optimize_rotation()
|
||||
{
|
||||
auto &w = get_ui_job_worker();
|
||||
|
||||
@@ -643,7 +643,8 @@ public:
|
||||
void drop_selection();
|
||||
void search(bool plater_is_active, Preset::Type type, wxWindow *tag, TextInput *etag, wxWindow *stag);
|
||||
void mirror(Axis axis);
|
||||
void split_object();
|
||||
void split_object(bool auto_drop = true);
|
||||
void split_object(int obj_idx, bool auto_drop = true);
|
||||
void split_volume();
|
||||
void optimize_rotation();
|
||||
// find all empty cells on the plate and won't overlap with exclusion areas
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
#include <slic3r/GUI/Widgets/WebView.hpp>
|
||||
#include <wx/webview.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <webkit2/webkit2.h>
|
||||
#endif
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
namespace Slic3r {
|
||||
@@ -33,6 +37,14 @@ PrinterWebView::PrinterWebView(wxWindow *parent)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
auto cookiesPath = boost::filesystem::path(data_dir() + "/cache/cookies.db");
|
||||
auto wv = static_cast<WebKitWebView*>(m_browser->GetNativeBackend());
|
||||
auto wv_ctx = webkit_web_view_get_context(wv);
|
||||
auto cookieManager = webkit_web_context_get_cookie_manager(wv_ctx);
|
||||
webkit_cookie_manager_set_persistent_storage(cookieManager, cookiesPath.c_str(), WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE);
|
||||
#endif
|
||||
|
||||
m_browser->Bind(wxEVT_WEBVIEW_ERROR, &PrinterWebView::OnError, this);
|
||||
m_browser->Bind(wxEVT_WEBVIEW_LOADED, &PrinterWebView::OnLoaded, this);
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
|
||||
#include "imgui/imconfig.h"
|
||||
|
||||
#if defined(__WXGTK__)
|
||||
#include "LinuxDisplayBackend.hpp"
|
||||
#endif
|
||||
|
||||
using boost::optional;
|
||||
|
||||
namespace Slic3r {
|
||||
@@ -33,6 +37,17 @@ wxDEFINE_EVENT(wxCUSTOMEVT_JUMP_TO_OBJECT, wxCommandEvent);
|
||||
using GUI::from_u8;
|
||||
using GUI::into_u8;
|
||||
|
||||
namespace {
|
||||
|
||||
bool focus_left_popup(wxWindow* popup, wxWindow* focus_window, wxWindow* related_window_1 = nullptr,
|
||||
wxWindow* related_window_2 = nullptr, wxWindow* related_window_3 = nullptr)
|
||||
{
|
||||
return focus_window != popup && !popup->IsDescendant(focus_window) && focus_window != related_window_1 &&
|
||||
focus_window != related_window_2 && focus_window != related_window_3;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace Search {
|
||||
|
||||
static char marker_by_type(Preset::Type type, PrinterTechnology pt)
|
||||
@@ -674,11 +689,24 @@ void SearchDialog::OnDismiss() { }
|
||||
|
||||
void SearchDialog::Dismiss()
|
||||
{
|
||||
auto pos = wxGetMousePosition();
|
||||
auto focus_window = wxWindow::FindFocus();
|
||||
if (!focus_window)
|
||||
if (!focus_window) {
|
||||
Die();
|
||||
else if (!m_event_tag->GetScreenRect().Contains(pos) && !this->GetScreenRect().Contains(pos) && !m_search_item_tag->GetScreenRect().Contains(pos)) {
|
||||
return;
|
||||
}
|
||||
#if defined(__WXGTK__)
|
||||
// On Wayland, wxGetMousePosition() returns unreliable global coords.
|
||||
// Rely on focus tracking instead: if focus moved to a window outside
|
||||
// this dialog and its related controls, dismiss.
|
||||
if (Slic3r::GUI::is_running_on_wayland()) {
|
||||
if (focus_left_popup(this, focus_window, m_event_tag, m_search_item_tag, search_line)) {
|
||||
Die();
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
auto pos = wxGetMousePosition();
|
||||
if (!m_event_tag->GetScreenRect().Contains(pos) && !this->GetScreenRect().Contains(pos) && !m_search_item_tag->GetScreenRect().Contains(pos)) {
|
||||
Die();
|
||||
}
|
||||
}
|
||||
@@ -904,11 +932,24 @@ void SearchObjectDialog::OnDismiss() {}
|
||||
|
||||
void SearchObjectDialog::Dismiss()
|
||||
{
|
||||
auto pos = wxGetMousePosition();
|
||||
auto focus_window = wxWindow::FindFocus();
|
||||
if (!focus_window)
|
||||
if (!focus_window) {
|
||||
Die();
|
||||
else if (!search_line->GetScreenRect().Contains(pos) && !this->GetScreenRect().Contains(pos)) {
|
||||
return;
|
||||
}
|
||||
#if defined(__WXGTK__)
|
||||
// On Wayland, wxGetMousePosition() returns unreliable global coords.
|
||||
// Rely on focus tracking instead: if focus moved to a window outside
|
||||
// this dialog and its related controls, dismiss.
|
||||
if (Slic3r::GUI::is_running_on_wayland()) {
|
||||
if (focus_left_popup(this, focus_window, search_line)) {
|
||||
Die();
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
auto pos = wxGetMousePosition();
|
||||
if (!search_line->GetScreenRect().Contains(pos) && !this->GetScreenRect().Contains(pos)) {
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
+206
-79
@@ -18,7 +18,7 @@
|
||||
#include "libslic3r/BuildVolume.hpp"
|
||||
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
@@ -525,8 +525,32 @@ void Selection::center()
|
||||
|
||||
void Selection::drop()
|
||||
{
|
||||
if (this->get_bounding_box().min.z() < SINKING_Z_THRESHOLD) {
|
||||
return; // shouldnt happen, but better check anyways, already checked in append_menu_item_drop()
|
||||
}
|
||||
|
||||
wxGetApp().plater()->take_snapshot(L("Move Object"));
|
||||
|
||||
this->move_to_center(Vec3d(0, 0, -this->get_bounding_box().min.z()));
|
||||
wxGetApp().plater()->get_view3D_canvas3D()->do_move(L("Move Object"));
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
GLVolume& volume = *(*m_volumes)[i];
|
||||
ModelObject* model_object = m_model->objects[volume.object_idx()];
|
||||
|
||||
if (model_object != nullptr) {
|
||||
if (m_mode == Volume) {
|
||||
ModelVolume* cur_mv = model_object->volumes[volume.volume_idx()];
|
||||
cur_mv->set_transformation(volume.get_volume_transformation());
|
||||
} else if (m_mode == Instance) {
|
||||
model_object->instances[volume.instance_idx()]->set_transformation(volume.get_instance_transformation());
|
||||
}
|
||||
|
||||
model_object->invalidate_bounding_box();
|
||||
this->notify_instance_update(volume.object_idx(), volume.instance_idx());
|
||||
}
|
||||
}
|
||||
|
||||
wxGetApp().plater()->get_view3D_canvas3D()->post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MOVED));
|
||||
}
|
||||
|
||||
void Selection::center_plate(const int plate_idx) {
|
||||
@@ -550,11 +574,9 @@ void Selection::set_printable(bool printable)
|
||||
return;
|
||||
|
||||
std::set<std::pair<int, int>> instances_idxs;
|
||||
for (ObjectIdxsToInstanceIdxsMap::iterator obj_it = m_cache.content.begin(); obj_it != m_cache.content.end(); ++obj_it)
|
||||
{
|
||||
for (InstanceIdxsList::reverse_iterator inst_it = obj_it->second.rbegin(); inst_it != obj_it->second.rend(); ++inst_it)
|
||||
{
|
||||
instances_idxs.insert(std::make_pair(obj_it->first, *inst_it));
|
||||
for (const auto& [obj_idx, inst_list] : m_cache.content) {
|
||||
for (int inst_idx : inst_list) {
|
||||
instances_idxs.insert({obj_idx, inst_idx});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -562,15 +584,68 @@ void Selection::set_printable(bool printable)
|
||||
wxGetApp().plater()->take_snapshot(snapshot_text);
|
||||
|
||||
// set printable value for all instances in object
|
||||
for (const std::pair<int, int>& i : instances_idxs)
|
||||
for (const auto& [obj_idx, inst_idx] : instances_idxs)
|
||||
{
|
||||
ModelObject* object = m_model->objects[i.first];
|
||||
ModelObject* object = m_model->objects[obj_idx];
|
||||
for (auto inst : object->instances)
|
||||
inst->printable = printable;
|
||||
wxGetApp().obj_list()->update_printable_state(i.first, i.second);
|
||||
wxGetApp().obj_list()->update_printable_state(obj_idx, inst_idx);
|
||||
|
||||
//update printable state on canvas
|
||||
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object((size_t)i.first);
|
||||
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object((size_t) obj_idx);
|
||||
}
|
||||
|
||||
// update scene
|
||||
wxGetApp().plater()->update();
|
||||
}
|
||||
|
||||
bool Selection::get_auto_drop() const {
|
||||
// The wipe tower is not a ModelObject and has no per-instance auto_drop;
|
||||
// return the default to avoid indexing m_model->objects with its synthetic id.
|
||||
if (!m_valid || is_wipe_tower())
|
||||
return true;
|
||||
|
||||
std::set<std::pair<int, int>> instances_idxs;
|
||||
for (const auto& [obj_idx, inst_list] : m_cache.content) {
|
||||
for (int inst_idx : inst_list) {
|
||||
instances_idxs.insert({obj_idx, inst_idx});
|
||||
}
|
||||
}
|
||||
|
||||
// return false, if one of the instances in the selection has auto_drop disabled, otherwise return true
|
||||
for (const auto& [obj_idx, inst_idx] : instances_idxs) {
|
||||
ModelObject* object = m_model->objects[obj_idx];
|
||||
for (const auto* inst : object->instances) {
|
||||
if (!inst->auto_drop) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Selection::set_auto_drop(bool enabled)
|
||||
{
|
||||
if (!m_valid)
|
||||
return;
|
||||
|
||||
std::set<std::pair<int, int>> instances_idxs;
|
||||
for (const auto& [obj_idx, inst_list] : m_cache.content) {
|
||||
for (int inst_idx : inst_list) {
|
||||
instances_idxs.insert({obj_idx, inst_idx});
|
||||
}
|
||||
}
|
||||
|
||||
std::string snapshot_text = (boost::format("%1%") % (enabled ? "Set Selection Auto-Drop Enabled" : "Set Selection Auto-Drop Disabled")).str();
|
||||
wxGetApp().plater()->take_snapshot(snapshot_text);
|
||||
|
||||
// set auto_drop value for all instances in object
|
||||
for (const auto& [obj_idx, inst_idx] : instances_idxs) {
|
||||
ModelObject* object = m_model->objects[obj_idx];
|
||||
for (auto* inst : object->instances) {
|
||||
inst->auto_drop = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
// update scene
|
||||
@@ -1601,7 +1676,6 @@ void Selection::scale_and_translate(const Vec3d &scale, const Vec3d &world_trans
|
||||
synchronize_unselected_volumes();
|
||||
#endif // !DISABLE_INSTANCES_SYNCH
|
||||
|
||||
ensure_on_bed();
|
||||
set_bounding_boxes_dirty();
|
||||
if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
|
||||
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
||||
@@ -1612,7 +1686,6 @@ void Selection::mirror(Axis axis, TransformationType transformation_type)
|
||||
{
|
||||
const Vec3d mirror((axis == X) ? -1.0 : 1.0, (axis == Y) ? -1.0 : 1.0, (axis == Z) ? -1.0 : 1.0);
|
||||
scale_and_translate(mirror, Vec3d::Zero(), transformation_type);
|
||||
|
||||
}
|
||||
|
||||
void Selection::translate(unsigned int object_idx, const Vec3d& displacement)
|
||||
@@ -1927,7 +2000,8 @@ void Selection::render(float scale_factor)
|
||||
m_scale_factor = scale_factor;
|
||||
// render cumulative bounding box of selected volumes
|
||||
const auto& [box, trafo] = get_bounding_box_in_current_reference_system();
|
||||
render_bounding_box(box, trafo,
|
||||
const bool auto_drop = get_auto_drop();
|
||||
render_bounding_box(box, trafo, auto_drop,
|
||||
wxGetApp().plater()->canvas3D()->get_canvas_type() == GLCanvas3D::ECanvasType::CanvasAssembleView ? ColorRGB::YELLOW(): ColorRGB::WHITE());
|
||||
render_synchronized_volumes();
|
||||
}
|
||||
@@ -2530,86 +2604,128 @@ void Selection::render_synchronized_volumes()
|
||||
box = v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix());
|
||||
trafo = v.get_instance_transformation().get_matrix();
|
||||
}
|
||||
render_bounding_box(box, trafo, ColorRGB::YELLOW());
|
||||
const bool auto_drop = get_auto_drop();
|
||||
render_bounding_box(box, trafo, auto_drop, ColorRGB::YELLOW());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Selection::render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const ColorRGB& color)
|
||||
void Selection::render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const bool auto_drop, const ColorRGB& color)
|
||||
{
|
||||
const BoundingBoxf3& curr_box = m_box.get_bounding_box();
|
||||
const bool curr_auto_drop = m_auto_drop;
|
||||
|
||||
if (!m_box.is_initialized() || !is_approx(box.min, curr_box.min) || !is_approx(box.max, curr_box.max)) {
|
||||
if (!m_box.is_initialized() || !is_approx(box.min, curr_box.min) || !is_approx(box.max, curr_box.max) || curr_auto_drop != auto_drop) {
|
||||
m_box.reset();
|
||||
m_auto_drop = auto_drop;
|
||||
|
||||
const Vec3f b_min = box.min.cast<float>();
|
||||
const Vec3f b_max = box.max.cast<float>();
|
||||
const Vec3f size = 0.2f * box.size().cast<float>();
|
||||
|
||||
// 48 brackets + (24 if auto_drop == false)
|
||||
int total_vertices = 48 + (auto_drop ? 0 : 24);
|
||||
|
||||
GLModel::Geometry init_data;
|
||||
init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 };
|
||||
init_data.reserve_vertices(48);
|
||||
init_data.reserve_indices(48);
|
||||
init_data.reserve_vertices(total_vertices);
|
||||
init_data.reserve_indices(total_vertices);
|
||||
|
||||
// vertices
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y() + size.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z() + size.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y() + size.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z() + size.z()));
|
||||
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y() + size.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z() + size.z()));
|
||||
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y() - size.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z() + size.z()));
|
||||
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y() - size.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z() + size.z()));
|
||||
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y() + size.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z() - size.z()));
|
||||
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y() + size.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z() - size.z()));
|
||||
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y() - size.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z() - size.z()));
|
||||
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y() - size.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z() - size.z()));
|
||||
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y() + size.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z() + size.z()));
|
||||
// Indicate that auto_drop == false, by drawing an arrow on bottom corners
|
||||
if (!auto_drop) {
|
||||
float visual_scale = m_scale_factor;
|
||||
float head_s = 2.0f * visual_scale; // Width of the arrowhead wings
|
||||
float z_gap = 1.0f * visual_scale; // Gap between box and arrow tip
|
||||
float arrow_h = 5.0f * visual_scale; // Total height of the arrow stem
|
||||
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y() - size.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z() + size.z()));
|
||||
// 4 bottom corners
|
||||
std::vector<Vec3f> corners = {{b_min.x(), b_min.y(), b_min.z()},
|
||||
{b_max.x(), b_min.y(), b_min.z()},
|
||||
{b_max.x(), b_max.y(), b_min.z()},
|
||||
{b_min.x(), b_max.y(), b_min.z()}};
|
||||
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y() - size.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z() + size.z()));
|
||||
for (const auto& pt : corners) {
|
||||
Vec3f tip = {pt.x(), pt.y(), pt.z() - z_gap};
|
||||
Vec3f base = {pt.x(), pt.y(), tip.z() - arrow_h};
|
||||
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y() + size.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z() - size.z()));
|
||||
// Stem
|
||||
init_data.add_vertex(base);
|
||||
init_data.add_vertex(tip);
|
||||
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y() + size.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z() - size.z()));
|
||||
// Wings
|
||||
// Determine direction to the center of the footprint
|
||||
float dirX = (pt.x() == b_min.x()) ? head_s : -head_s;
|
||||
float dirY = (pt.y() == b_min.y()) ? head_s : -head_s;
|
||||
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y() - size.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z() - size.z()));
|
||||
// Wing 1 (X-Inward)
|
||||
init_data.add_vertex(tip);
|
||||
init_data.add_vertex(Vec3f(tip.x() + dirX, tip.y(), tip.z() - head_s));
|
||||
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y() - size.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z()));
|
||||
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z() - size.z()));
|
||||
// Wing 2 (Y-Inward)
|
||||
init_data.add_vertex(tip);
|
||||
init_data.add_vertex(Vec3f(tip.x(), tip.y() + dirY, tip.z() - head_s));
|
||||
}
|
||||
}
|
||||
|
||||
// indices
|
||||
for (unsigned int i = 0; i < 48; ++i) {
|
||||
// Finalize indices
|
||||
for (unsigned int i = 0; i < init_data.vertices_count(); ++i) {
|
||||
init_data.add_index(i);
|
||||
}
|
||||
|
||||
@@ -2941,8 +3057,11 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
|
||||
}
|
||||
else if (sync_rotation_type != SyncRotationType::NONE || mirrored)
|
||||
new_inst_trafo_j.linear() = (old_inst_trafo_j.linear() * old_inst_trafo_i.linear().inverse()) * curr_inst_trafo_i.linear();
|
||||
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
|
||||
|
||||
bool should_synchronize_z = m_model->objects[volume_j->object_idx()]->instances[volume_j->instance_idx()]->auto_drop == false;
|
||||
if (should_synchronize_z && wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
|
||||
new_inst_trafo_j.translation().z() = curr_inst_trafo_i.translation().z();
|
||||
|
||||
assert(is_rotation_xy_synchronized(curr_inst_trafo_i, new_inst_trafo_j));
|
||||
volume_j->set_instance_transformation(new_inst_trafo_j);
|
||||
done.insert(j);
|
||||
@@ -2985,17 +3104,25 @@ void Selection::ensure_on_bed()
|
||||
InstancesToZMap instances_min_z;
|
||||
|
||||
for (size_t i = 0; i < m_volumes->size(); ++i) {
|
||||
GLVolume* volume = (*m_volumes)[i];
|
||||
if (!volume->is_wipe_tower && !volume->is_modifier &&
|
||||
std::find(m_cache.sinking_volumes.begin(), m_cache.sinking_volumes.end(), i) == m_cache.sinking_volumes.end()) {
|
||||
const double min_z = volume->transformed_convex_hull_bounding_box().min.z();
|
||||
std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
|
||||
InstancesToZMap::iterator it = instances_min_z.find(instance);
|
||||
if (it == instances_min_z.end())
|
||||
it = instances_min_z.insert(InstancesToZMap::value_type(instance, DBL_MAX)).first;
|
||||
GLVolume* volume = (*m_volumes)[i];
|
||||
ModelObject* mo = m_model->objects[volume->object_idx()];
|
||||
ModelInstance* mi = mo->instances[volume->instance_idx()];
|
||||
|
||||
it->second = std::min(it->second, min_z);
|
||||
if (mi->auto_drop == false
|
||||
|| volume->is_wipe_tower
|
||||
|| volume->is_modifier
|
||||
|| std::find(m_cache.sinking_volumes.begin(), m_cache.sinking_volumes.end(), i) != m_cache.sinking_volumes.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const double min_z = volume->transformed_convex_hull_bounding_box().min.z();
|
||||
std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
|
||||
InstancesToZMap::iterator it = instances_min_z.find(instance);
|
||||
if (it == instances_min_z.end())
|
||||
it = instances_min_z.insert(InstancesToZMap::value_type(instance, DBL_MAX)).first;
|
||||
|
||||
it->second = std::min(it->second, min_z);
|
||||
}
|
||||
|
||||
for (GLVolume* volume : *m_volumes) {
|
||||
|
||||
@@ -181,6 +181,7 @@ private:
|
||||
GLModel m_arrow;
|
||||
GLModel m_curved_arrow;
|
||||
GLModel m_box;
|
||||
bool m_auto_drop = true;
|
||||
struct Planes
|
||||
{
|
||||
std::array<Vec3f, 2> check_points{ Vec3f::Zero(), Vec3f::Zero() };
|
||||
@@ -237,6 +238,8 @@ public:
|
||||
void drop();
|
||||
void center_plate(const int plate_idx);
|
||||
void set_printable(bool printable);
|
||||
bool get_auto_drop() const;
|
||||
void set_auto_drop(bool enabled);
|
||||
|
||||
void add_all();
|
||||
void remove_all();
|
||||
@@ -370,7 +373,7 @@ public:
|
||||
|
||||
void render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color, float scale) {
|
||||
m_scale_factor = scale;
|
||||
render_bounding_box(box, Transform3d::Identity(), color);
|
||||
render_bounding_box(box, Transform3d::Identity(), get_auto_drop(), color);
|
||||
}
|
||||
|
||||
//BBS
|
||||
@@ -414,7 +417,7 @@ private:
|
||||
m_bounding_sphere.reset();
|
||||
}
|
||||
void render_synchronized_volumes();
|
||||
void render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const ColorRGB& color);
|
||||
void render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const bool auto_drop, const ColorRGB& color);
|
||||
void render_sidebar_position_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix);
|
||||
void render_sidebar_rotation_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix);
|
||||
//BBS: GUI refactor: add uniform_scale from gizmo
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#include "GUI_App.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "I18N.hpp"
|
||||
#ifdef __WXGTK__
|
||||
#include "LinuxDisplayBackend.hpp"
|
||||
#endif
|
||||
#include "MainFrame.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "OpenGLManager.hpp"
|
||||
@@ -28,7 +31,7 @@
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/uuid/detail/md5.hpp>
|
||||
|
||||
#include "GL/glew.h"
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include <wx/display.h>
|
||||
#include <wx/htmllbox.h>
|
||||
@@ -420,6 +423,28 @@ static std::string generate_system_info_json()
|
||||
data_node.put("Linux_DistroID", distro_id);
|
||||
data_node.put("Linux_DistroVer", distro_ver);
|
||||
data_node.put("Linux_Wayland", wxGetEnv("WAYLAND_DISPLAY", nullptr));
|
||||
#ifdef __WXGTK__
|
||||
const LinuxDisplayBackend display_backend = get_linux_display_backend();
|
||||
const char* display_backend_name = "unknown";
|
||||
const char* gl_backend_hint = "Unknown";
|
||||
switch (display_backend) {
|
||||
case LinuxDisplayBackend::Wayland:
|
||||
display_backend_name = "wayland";
|
||||
gl_backend_hint = "EGL";
|
||||
break;
|
||||
case LinuxDisplayBackend::X11:
|
||||
display_backend_name = "x11";
|
||||
gl_backend_hint = "GLX";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
data_node.put("Linux_DisplayBackend", display_backend_name);
|
||||
data_node.put("Linux_GLBackendHint", gl_backend_hint);
|
||||
#else
|
||||
data_node.put("Linux_DisplayBackend", "unknown");
|
||||
data_node.put("Linux_GLBackendHint", "Unknown");
|
||||
#endif
|
||||
#endif
|
||||
data_node.put("wxWidgets", wxVERSION_NUM_DOT_STRING);
|
||||
#ifdef __WXGTK__
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#include "SkipPartCanvas.hpp"
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "TextLines.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
|
||||
@@ -516,7 +516,9 @@ void Button::OnParentMotion(wxMouseEvent& event)
|
||||
tipWindow->SetLabel(tip);
|
||||
}
|
||||
|
||||
tipWindow->Position(wxGetMousePosition(), wxSize(0, 0));
|
||||
// Position tooltip relative to the button widget itself rather than
|
||||
// using wxGetMousePosition() which returns (0,0) on Wayland.
|
||||
tipWindow->Position(this->ClientToScreen(wxPoint(0, 0)), this->GetSize());
|
||||
tipWindow->Popup();
|
||||
}
|
||||
else
|
||||
|
||||
@@ -138,6 +138,10 @@ void SwitchButton::Rescale()
|
||||
memdc.SelectObject(bmp);
|
||||
#endif
|
||||
memdc.SetFont(dc.GetFont());
|
||||
#ifdef __WXMSW__
|
||||
const double scale = GetDPIScaleFactor();
|
||||
fontScale = scale;
|
||||
#endif
|
||||
if (fontScale) {
|
||||
memdc.SetFont(dc.GetFont().Scaled(fontScale));
|
||||
textSize[0] = memdc.GetTextExtent(labels[0]);
|
||||
@@ -176,6 +180,8 @@ void SwitchButton::Rescale()
|
||||
memdc.SelectObject(wxNullBitmap);
|
||||
#ifdef __WXOSX__
|
||||
bmp = wxBitmap(bmp.ConvertToImage(), -1, scale);
|
||||
#elif defined(__WXMSW__)
|
||||
bmp.SetScaleFactor(scale); // ORCA
|
||||
#endif
|
||||
(i == 0 ? m_off : m_on).bmp() = bmp;
|
||||
}
|
||||
|
||||
@@ -1407,8 +1407,8 @@ void Cornering_Test_Dlg::on_start(wxCommandEvent& event) {
|
||||
!preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("machine_max_junction_deviation")->values.empty() &&
|
||||
preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("machine_max_junction_deviation")->values[0] > 0) {
|
||||
// Using Junction Deviation (mm)
|
||||
max_end_value = 1.0;
|
||||
warning_threshold = 0.3;
|
||||
max_end_value = 0.3;
|
||||
warning_threshold = 0.25;
|
||||
}
|
||||
|
||||
if (!read_double || m_params.start < 0 || m_params.end > max_end_value || m_params.start >= m_params.end) {
|
||||
|
||||
@@ -468,6 +468,10 @@ wxBitmap create_scaled_bitmap( const std::string& bmp_name_in,
|
||||
throw Slic3r::RuntimeError("Could not load bitmap: " + bmp_name);
|
||||
}
|
||||
|
||||
#ifdef __WXMSW__
|
||||
// ORCA MSW needs to set scale factor for bitmaps loaded from cache because they arent auto scaled by wxBitmapBundle like bitmaps
|
||||
bmp->SetScaleFactor(win ? win->GetDPIScaleFactor() : (wxWindow::FromDIP(100, nullptr) / 100.0));
|
||||
#endif
|
||||
return *bmp;
|
||||
}
|
||||
|
||||
@@ -487,6 +491,10 @@ wxBitmap create_scaled_bitmap2(const std::string& bmp_name_in, Slic3r::GUI::Bitm
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Could not load bitmap: " << bmp_name;
|
||||
throw Slic3r::RuntimeError("Could not load bitmap: " + bmp_name);
|
||||
}
|
||||
#ifdef __WXMSW__
|
||||
// ORCA MSW needs to set scale factor for bitmaps loaded from cache because they arent auto scaled by wxBitmapBundle like bitmaps
|
||||
bmp->SetScaleFactor(win ? win->GetDPIScaleFactor() : (wxWindow::FromDIP(100, nullptr) / 100.0));
|
||||
#endif
|
||||
return *bmp;
|
||||
}
|
||||
|
||||
@@ -500,7 +508,8 @@ wxBitmap* get_default_extruder_color_icon(bool thin_icon/* = false*/)
|
||||
const int icon_height = lround(2 * em);
|
||||
bool dark_mode = Slic3r::GUI::wxGetApp().dark_mode();
|
||||
|
||||
wxClientDC cdc((wxWindow*)Slic3r::GUI::wxGetApp().mainframe);
|
||||
auto win = (wxWindow*)Slic3r::GUI::wxGetApp().mainframe;
|
||||
wxClientDC cdc(win);
|
||||
wxMemoryDC dc(&cdc);
|
||||
dc.SetFont(::Label::Body_12);
|
||||
|
||||
@@ -526,6 +535,12 @@ wxBitmap* get_default_extruder_color_icon(bool thin_icon/* = false*/)
|
||||
dc.SelectObject(wxNullBitmap);
|
||||
}
|
||||
|
||||
#ifdef __WXMSW__
|
||||
// ORCA MSW needs to set scale factor for bitmaps loaded from cache because they arent auto scaled by wxBitmapBundle like bitmaps
|
||||
double scale = win ? win->GetDPIScaleFactor() : (wxWindow::FromDIP(100, nullptr) / 100.0);
|
||||
bitmap->SetScaleFactor(scale);
|
||||
#endif
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
@@ -633,6 +648,9 @@ wxBitmap *get_extruder_color_icon(std::vector<std::string> colors, bool is_gradi
|
||||
bitmap_key += "h" + std::to_string(icon_height) + "-w" + std::to_string(icon_width) + "-i" + label;
|
||||
|
||||
wxBitmap *bitmap = bmp_cache.find(bitmap_key);
|
||||
#ifdef __WXMSW__
|
||||
auto win = (wxWindow *) Slic3r::GUI::wxGetApp().mainframe;
|
||||
#endif
|
||||
if (bitmap == nullptr) {
|
||||
|
||||
std::vector<wxColour> wx_colors;
|
||||
@@ -656,8 +674,11 @@ wxBitmap *get_extruder_color_icon(std::vector<std::string> colors, bool is_gradi
|
||||
#ifndef __WXMSW__
|
||||
wxMemoryDC dc(base_bitmap);
|
||||
#else
|
||||
wxClientDC cdc((wxWindow *) Slic3r::GUI::wxGetApp().mainframe);
|
||||
wxClientDC cdc(win);
|
||||
wxMemoryDC dc(&cdc);
|
||||
// ORCA MSW needs to set scale factor for bitmaps loaded from cache because they arent auto scaled by wxBitmapBundle like bitmaps
|
||||
double scale = win ? win->GetDPIScaleFactor() : (wxWindow::FromDIP(100, nullptr) / 100.0);
|
||||
base_bitmap.SetScaleFactor(scale);
|
||||
dc.SelectObject(base_bitmap);
|
||||
#endif
|
||||
|
||||
@@ -694,6 +715,11 @@ wxBitmap *get_extruder_color_icon(std::vector<std::string> colors, bool is_gradi
|
||||
// cache result
|
||||
bitmap = bmp_cache.insert(bitmap_key, base_bitmap);
|
||||
}
|
||||
#ifdef __WXMSW__
|
||||
// ORCA MSW needs to set scale factor for bitmaps loaded from cache because they arent auto scaled by wxBitmapBundle like bitmaps
|
||||
double scale = win ? win->GetDPIScaleFactor() : (wxWindow::FromDIP(100, nullptr) / 100.0);
|
||||
bitmap->SetScaleFactor(scale);
|
||||
#endif
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
@@ -704,6 +730,9 @@ wxBitmap *get_extruder_color_icon(std::string color, std::string label, int icon
|
||||
std::string bitmap_key = color + "-h" + std::to_string(icon_height) + "-w" + std::to_string(icon_width) + "-i" + label;
|
||||
|
||||
wxBitmap *bitmap = bmp_cache.find(bitmap_key);
|
||||
#ifdef __WXMSW__
|
||||
auto win = (wxWindow *) Slic3r::GUI::wxGetApp().mainframe;
|
||||
#endif
|
||||
if (bitmap == nullptr) {
|
||||
// Paint the color icon.
|
||||
// Slic3r::GUI::BitmapCache::parse_color(color, rgb);
|
||||
@@ -714,7 +743,7 @@ wxBitmap *get_extruder_color_icon(std::string color, std::string label, int icon
|
||||
bitmap->UseAlpha();
|
||||
wxMemoryDC dc(*bitmap);
|
||||
#elif defined(__WXMSW__)
|
||||
wxClientDC cdc((wxWindow *) Slic3r::GUI::wxGetApp().mainframe);
|
||||
wxClientDC cdc(win);
|
||||
wxMemoryDC dc(&cdc);
|
||||
dc.SelectObject(*bitmap);
|
||||
#else
|
||||
@@ -748,6 +777,11 @@ wxBitmap *get_extruder_color_icon(std::string color, std::string label, int icon
|
||||
dc.DrawText(label, (icon_width - size.x) / 2, (icon_height - size.y) / 2);
|
||||
dc.SelectObject(wxNullBitmap);
|
||||
}
|
||||
#ifdef __WXMSW__
|
||||
// ORCA MSW needs to set scale factor for bitmaps loaded from cache because they arent auto scaled by wxBitmapBundle like bitmaps
|
||||
double scale = win ? win->GetDPIScaleFactor() : (wxWindow::FromDIP(100, nullptr) / 100.0);
|
||||
bitmap->SetScaleFactor(scale);
|
||||
#endif
|
||||
return bitmap;
|
||||
}
|
||||
void apply_extruder_selector(Slic3r::GUI::BitmapComboBox** ctrl,
|
||||
|
||||
@@ -458,8 +458,14 @@ static void read_model_from_file(const std::string& input_file, Model& model)
|
||||
&is_bbl_3mf, &file_version, nullptr, nullptr, nullptr, plate_to_slice);
|
||||
|
||||
model.add_default_instances();
|
||||
for (auto object : model.objects)
|
||||
object->ensure_on_bed();
|
||||
|
||||
const std::string extension = fs::path(input_file).extension().string();
|
||||
const bool is_project_file = extension == ".3mf" || extension == ".3MF" || extension == ".amf" || extension == ".AMF";
|
||||
for (auto object : model.objects) {
|
||||
if (!is_project_file)
|
||||
object->center_around_origin(false);
|
||||
object->ensure_on_bed(is_project_file);
|
||||
}
|
||||
}
|
||||
|
||||
std::array<Vec3d, 4> get_cut_plane_points(const BoundingBoxf3 &bbox, const double &cut_height)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "EmbossStyleManager.hpp"
|
||||
#include <optional>
|
||||
#include <GL/glew.h> // Imgui texture
|
||||
#include <glad/gl.h> // Imgui texture
|
||||
#include <imgui/imgui_internal.h> // ImTextCharFromUtf8
|
||||
#include <libslic3r/AppConfig.hpp>
|
||||
#include <libslic3r/Utils.hpp> // ScopeGuard
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <functional>
|
||||
#include <imgui/imgui.h>
|
||||
#include <wx/font.h>
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#include <libslic3r/BoundingBox.hpp>
|
||||
#include <libslic3r/Emboss.hpp>
|
||||
#include <libslic3r/TextConfiguration.hpp>
|
||||
|
||||
@@ -627,7 +627,7 @@ void PresetUpdater::priv::sync_resources(std::string http_url, std::map<std::str
|
||||
|
||||
boost::nowide::ofstream c;
|
||||
c.open(changelog_file, std::ios::out | std::ios::trunc);
|
||||
c << std::setw(4) << j << std::endl;
|
||||
c << j.dump(1, '\t') << std::endl;
|
||||
c.close();
|
||||
}
|
||||
catch(std::exception &err) {
|
||||
|
||||
@@ -166,7 +166,7 @@ void SimplyPrint::save_oauth_credential(const GUI::OAuthResult& cred) const
|
||||
|
||||
boost::nowide::ofstream c;
|
||||
c.open(cred_file, std::ios::out | std::ios::trunc);
|
||||
c << std::setw(4) << j << std::endl;
|
||||
c << j.dump(1, '\t') << std::endl;
|
||||
c.close();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user