diff --git a/resources/icons/view_toolbar.png b/resources/icons/view_toolbar.png new file mode 100644 index 0000000000..349d0bd094 Binary files /dev/null and b/resources/icons/view_toolbar.png differ diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c958cd18f0..2b9022bf97 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -26,7 +26,11 @@ #include #include #include +#if ENABLE_REMOVE_TABS_FROM_PLATER +#include +#else #include +#endif // ENABLE_REMOVE_TABS_FROM_PLATER #include // Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx. @@ -3360,6 +3364,9 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const } } +#if ENABLE_REMOVE_TABS_FROM_PLATER +wxDEFINE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent); @@ -3379,6 +3386,9 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) , m_context(nullptr) , m_in_render(false) , m_toolbar(*this) +#if ENABLE_REMOVE_TABS_FROM_PLATER + , m_view_toolbar(nullptr) +#endif // ENABLE_REMOVE_TABS_FROM_PLATER , m_use_clipping_planes(false) , m_config(nullptr) , m_process(nullptr) @@ -3522,6 +3532,10 @@ bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl) if (!_init_toolbar()) return false; +#if ENABLE_REMOVE_TABS_FROM_PLATER + post_event(SimpleEvent(EVT_GLCANVAS_INIT)); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER + m_initialized = true; return true; @@ -3845,7 +3859,9 @@ void GLCanvas3D::render() float theta = m_camera.get_theta(); bool is_custom_bed = m_bed.is_custom(); +#if !ENABLE_REMOVE_TABS_FROM_PLATER set_tooltip(""); +#endif // !ENABLE_REMOVE_TABS_FROM_PLATER #if ENABLE_IMGUI wxGetApp().imgui()->new_frame(); @@ -3889,7 +3905,13 @@ void GLCanvas3D::render() _render_gizmos_overlay(); _render_warning_texture(); _render_legend_texture(); +#if ENABLE_REMOVE_TABS_FROM_PLATER + _resize_toolbars(); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER _render_toolbar(); +#if ENABLE_REMOVE_TABS_FROM_PLATER + _render_view_toolbar(); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER _render_layer_editing_overlay(); #if ENABLE_IMGUI @@ -4575,6 +4597,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_layers_editing.last_object_id = layer_editing_object_idx; bool gizmos_overlay_contains_mouse = m_gizmos.overlay_contains_mouse(*this, m_mouse.position); int toolbar_contains_mouse = m_toolbar.contains_mouse(m_mouse.position); +#if ENABLE_REMOVE_TABS_FROM_PLATER + int view_toolbar_contains_mouse = (m_view_toolbar != nullptr) ? m_view_toolbar->contains_mouse(m_mouse.position, *this) : -1; +#endif // ENABLE_REMOVE_TABS_FROM_PLATER if (evt.Entering()) { @@ -4660,6 +4685,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (m_gizmos.get_current_type() == Gizmos::SlaSupports) m_gizmos.delete_current_grabber(); } +#if ENABLE_REMOVE_TABS_FROM_PLATER + else if (view_toolbar_contains_mouse != -1) + { + if (m_view_toolbar != nullptr) + m_view_toolbar->do_action((unsigned int)view_toolbar_contains_mouse, *this); + } +#endif // ENABLE_REMOVE_TABS_FROM_PLATER else if (toolbar_contains_mouse != -1) { m_toolbar_action_running = true; @@ -4936,7 +4968,31 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } else if (evt.Moving()) { - m_mouse.position = Vec2d((double)pos(0), (double)pos(1)); + m_mouse.position = pos.cast(); +#if ENABLE_REMOVE_TABS_FROM_PLATER + std::string tooltip = ""; + + // updates gizmos overlay + if (!m_selection.is_empty()) + tooltip = m_gizmos.update_hover_state(*this, m_mouse.position, m_selection); + else + m_gizmos.reset_all_states(); + + // updates toolbar overlay + if (tooltip.empty()) + tooltip = m_toolbar.update_hover_state(m_mouse.position); + + // updates view toolbar overlay + if (tooltip.empty() && (m_view_toolbar != nullptr)) + { + tooltip = m_view_toolbar->update_hover_state(m_mouse.position, *this); + if (!tooltip.empty()) + m_dirty = true; + } + + set_tooltip(tooltip); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER + // Only refresh if picking is enabled, in that case the objects may get highlighted if the mouse cursor hovers over. if (m_picking_enabled) m_dirty = true; @@ -5660,6 +5716,7 @@ void GLCanvas3D::_picking_pass() const _update_volumes_hover_state(); +#if !ENABLE_REMOVE_TABS_FROM_PLATER // updates gizmos overlay if (!m_selection.is_empty()) { @@ -5671,6 +5728,7 @@ void GLCanvas3D::_picking_pass() const m_gizmos.reset_all_states(); m_toolbar.update_hover_state(pos); +#endif // !ENABLE_REMOVE_TABS_FROM_PLATER } } @@ -5899,10 +5957,20 @@ void GLCanvas3D::_render_gizmos_overlay() const void GLCanvas3D::_render_toolbar() const { +#if !ENABLE_REMOVE_TABS_FROM_PLATER _resize_toolbar(); +#endif // !ENABLE_REMOVE_TABS_FROM_PLATER m_toolbar.render(); } +#if ENABLE_REMOVE_TABS_FROM_PLATER +void GLCanvas3D::_render_view_toolbar() const +{ + if (m_view_toolbar != nullptr) + m_view_toolbar->render(*this); +} +#endif // ENABLE_REMOVE_TABS_FROM_PLATER + #if ENABLE_SHOW_CAMERA_TARGET void GLCanvas3D::_render_camera_target() const { @@ -7495,7 +7563,11 @@ bool GLCanvas3D::_is_any_volume_outside() const return false; } +#if ENABLE_REMOVE_TABS_FROM_PLATER +void GLCanvas3D::_resize_toolbars() const +#else void GLCanvas3D::_resize_toolbar() const +#endif // ENABLE_REMOVE_TABS_FROM_PLATER { Size cnv_size = get_canvas_size(); float zoom = get_camera_zoom(); @@ -7524,6 +7596,15 @@ void GLCanvas3D::_resize_toolbar() const break; } } + +#if ENABLE_REMOVE_TABS_FROM_PLATER + if (m_view_toolbar != nullptr) + { + float top = (-0.5f * (float)cnv_size.get_height() + m_view_toolbar->get_height()) * inv_zoom; + float left = -0.5f * (float)cnv_size.get_width() * inv_zoom; + m_view_toolbar->set_position(top, left); + } +#endif // ENABLE_REMOVE_TABS_FROM_PLATER } const Print* GLCanvas3D::fff_print() const diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 7270d87579..8b19da8664 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -94,6 +94,9 @@ template using Vec2dsEvent = ArrayEvent; using Vec3dEvent = Event; template using Vec3dsEvent = ArrayEvent; +#if ENABLE_REMOVE_TABS_FROM_PLATER +wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent); @@ -737,6 +740,9 @@ private: Mouse m_mouse; mutable Gizmos m_gizmos; mutable GLToolbar m_toolbar; +#if ENABLE_REMOVE_TABS_FROM_PLATER + GLRadioToolbar* m_view_toolbar; +#endif // ENABLE_REMOVE_TABS_FROM_PLATER ClippingPlane m_clipping_planes[2]; bool m_use_clipping_planes; mutable SlaCap m_sla_caps[2]; @@ -787,6 +793,10 @@ public: wxGLCanvas* get_wxglcanvas() { return m_canvas; } +#if ENABLE_REMOVE_TABS_FROM_PLATER + void set_view_toolbar(GLRadioToolbar* toolbar) { m_view_toolbar = toolbar; } +#endif // ENABLE_REMOVE_TABS_FROM_PLATER + bool init(bool useVBOs, bool use_legacy_opengl); void post_event(wxEvent &&event); @@ -958,6 +968,9 @@ private: void _render_current_gizmo() const; void _render_gizmos_overlay() const; void _render_toolbar() const; +#if ENABLE_REMOVE_TABS_FROM_PLATER + void _render_view_toolbar() const; +#endif // ENABLE_REMOVE_TABS_FROM_PLATER #if ENABLE_SHOW_CAMERA_TARGET void _render_camera_target() const; #endif // ENABLE_SHOW_CAMERA_TARGET @@ -1021,7 +1034,11 @@ private: bool _is_any_volume_outside() const; +#if ENABLE_REMOVE_TABS_FROM_PLATER + void _resize_toolbars() const; +#else void _resize_toolbar() const; +#endif // ENABLE_REMOVE_TABS_FROM_PLATER static std::vector _parse_colors(const std::vector& colors); diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index 0e99f88ff8..c06c0fa7b5 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -26,6 +26,8 @@ wxDEFINE_EVENT(EVT_GLTOOLBAR_SPLIT_OBJECTS, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_SPLIT_VOLUMES, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_LAYERSEDITING, SimpleEvent); +wxDEFINE_EVENT(EVT_GLVIEWTOOLBAR_3D, SimpleEvent); +wxDEFINE_EVENT(EVT_GLVIEWTOOLBAR_PREVIEW, SimpleEvent); GLToolbarItem::Data::Data() : name("") @@ -121,7 +123,7 @@ GLTexture::Quad_UVs GLToolbarItem::get_uvs(unsigned int texture_size, unsigned i return uvs; } -GLToolbar::ItemsIconsTexture::ItemsIconsTexture() +ItemsIconsTexture::ItemsIconsTexture() : items_icon_size(0) , items_icon_border_size(0) , items_icon_gap_size(0) @@ -289,14 +291,27 @@ bool GLToolbar::is_item_pressed(const std::string& name) const return false; } +#if ENABLE_REMOVE_TABS_FROM_PLATER +std::string GLToolbar::update_hover_state(const Vec2d& mouse_pos) +#else void GLToolbar::update_hover_state(const Vec2d& mouse_pos) +#endif // ENABLE_REMOVE_TABS_FROM_PLATER { +#if ENABLE_REMOVE_TABS_FROM_PLATER + if (!m_enabled) + return ""; +#else if (!m_enabled) return; +#endif // ENABLE_REMOVE_TABS_FROM_PLATER switch (m_layout.type) { default: +#if ENABLE_REMOVE_TABS_FROM_PLATER + case Layout::Horizontal: { return update_hover_state_horizontal(mouse_pos); } + case Layout::Vertical: { return update_hover_state_vertical(mouse_pos); } +#else case Layout::Horizontal: { update_hover_state_horizontal(mouse_pos); @@ -307,6 +322,7 @@ void GLToolbar::update_hover_state(const Vec2d& mouse_pos) update_hover_state_vertical(mouse_pos); break; } +#endif // ENABLE_REMOVE_TABS_FROM_PLATER } } @@ -428,7 +444,11 @@ float GLToolbar::get_main_size() const return size; } +#if ENABLE_REMOVE_TABS_FROM_PLATER +std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos) +#else void GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos) +#endif // ENABLE_REMOVE_TABS_FROM_PLATER { float zoom = m_parent.get_camera_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; @@ -505,11 +525,19 @@ void GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos) } } +#if ENABLE_REMOVE_TABS_FROM_PLATER + return tooltip; +#else if (!tooltip.empty()) m_parent.set_tooltip(tooltip); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER } +#if ENABLE_REMOVE_TABS_FROM_PLATER +std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos) +#else void GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos) +#endif // ENABLE_REMOVE_TABS_FROM_PLATER { float zoom = m_parent.get_camera_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; @@ -586,7 +614,11 @@ void GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos) } } +#if ENABLE_REMOVE_TABS_FROM_PLATER + return tooltip; +#else m_parent.set_tooltip(tooltip); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER } int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos) const @@ -739,5 +771,297 @@ void GLToolbar::render_vertical() const } } +GLRadioToolbarItem::Data::Data() + : name("") + , tooltip("") + , sprite_id(-1) +{ +} + +GLRadioToolbarItem::GLRadioToolbarItem(const GLRadioToolbarItem::Data& data) + : m_state(Normal) + , m_data(data) +{ +} + +GLRadioToolbarItem::EState GLRadioToolbarItem::get_state() const +{ + return m_state; +} + +void GLRadioToolbarItem::set_state(GLRadioToolbarItem::EState state) +{ + m_state = state; +} + +const std::string& GLRadioToolbarItem::get_name() const +{ + return m_data.name; +} + +const std::string& GLRadioToolbarItem::get_tooltip() const +{ + return m_data.tooltip; +} + +bool GLRadioToolbarItem::is_hovered() const +{ + return (m_state == Hover) || (m_state == HoverPressed); +} + +bool GLRadioToolbarItem::is_pressed() const +{ + return (m_state == Pressed) || (m_state == HoverPressed); +} + +void GLRadioToolbarItem::do_action(wxEvtHandler *target) +{ + wxPostEvent(target, SimpleEvent(m_data.action_event)); +} + +void GLRadioToolbarItem::render(unsigned int tex_id, float left, float right, float bottom, float top, unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const +{ + GLTexture::render_sub_texture(tex_id, left, right, bottom, top, get_uvs(texture_size, border_size, icon_size, gap_size)); +} + +GLTexture::Quad_UVs GLRadioToolbarItem::get_uvs(unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const +{ + GLTexture::Quad_UVs uvs; + + float inv_texture_size = (texture_size != 0) ? 1.0f / (float)texture_size : 0.0f; + + float scaled_icon_size = (float)icon_size * inv_texture_size; + float scaled_border_size = (float)border_size * inv_texture_size; + float scaled_gap_size = (float)gap_size * inv_texture_size; + float stride = scaled_icon_size + scaled_gap_size; + + float left = scaled_border_size + (float)m_state * stride; + float right = left + scaled_icon_size; + float top = scaled_border_size + (float)m_data.sprite_id * stride; + float bottom = top + scaled_icon_size; + + uvs.left_top = { left, top }; + uvs.left_bottom = { left, bottom }; + uvs.right_bottom = { right, bottom }; + uvs.right_top = { right, top }; + + return uvs; +} + +GLRadioToolbar::GLRadioToolbar() + : m_top(0.0f) + , m_left(0.0f) +{ +} + +GLRadioToolbar::~GLRadioToolbar() +{ + for (GLRadioToolbarItem* item : m_items) + { + delete item; + } +} + +bool GLRadioToolbar::init(const std::string& icons_texture_filename, unsigned int items_icon_size, unsigned int items_icon_border_size, unsigned int items_icon_gap_size) +{ + if (m_icons_texture.texture.get_id() != 0) + return true; + + std::string path = resources_dir() + "/icons/"; + bool res = !icons_texture_filename.empty() && m_icons_texture.texture.load_from_file(path + icons_texture_filename, false); + if (res) + { + m_icons_texture.items_icon_size = items_icon_size; + m_icons_texture.items_icon_border_size = items_icon_border_size; + m_icons_texture.items_icon_gap_size = items_icon_gap_size; + } + + return res; +} + +bool GLRadioToolbar::add_item(const GLRadioToolbarItem::Data& data) +{ + GLRadioToolbarItem* item = new GLRadioToolbarItem(data); + if (item == nullptr) + return false; + + m_items.push_back(item); + return true; +} + +float GLRadioToolbar::get_height() const +{ + return m_icons_texture.items_icon_size; +} + +void GLRadioToolbar::set_position(float top, float left) +{ + m_top = top; + m_left = left; +} + +void GLRadioToolbar::set_selection(const std::string& name) +{ + for (GLRadioToolbarItem* item : m_items) + { + item->set_state((item->get_name() == name) ? GLRadioToolbarItem::Pressed : GLRadioToolbarItem::Normal); + } +} + +int GLRadioToolbar::contains_mouse(const Vec2d& mouse_pos, const GLCanvas3D& parent) const +{ + float zoom = parent.get_camera_zoom(); + float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + + Size cnv_size = parent.get_canvas_size(); + Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom); + + float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom; + + float left = m_left; + float top = m_top; + + int id = -1; + + for (GLRadioToolbarItem* item : m_items) + { + ++id; + + float right = left + scaled_icons_size; + float bottom = top - scaled_icons_size; + + if ((left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top)) + return id; + + left += scaled_icons_size; + } + + return -1; +} + +std::string GLRadioToolbar::update_hover_state(const Vec2d& mouse_pos, const GLCanvas3D& parent) +{ + float zoom = parent.get_camera_zoom(); + float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + + Size cnv_size = parent.get_canvas_size(); + Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom); + + float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom; + + float left = m_left; + float top = m_top; + + std::string tooltip = ""; + + for (GLRadioToolbarItem* item : m_items) + { + float right = left + scaled_icons_size; + float bottom = top - scaled_icons_size; + + GLRadioToolbarItem::EState state = item->get_state(); + bool inside = (left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top); + + switch (state) + { + case GLRadioToolbarItem::Normal: + { + if (inside) + item->set_state(GLRadioToolbarItem::Hover); + + break; + } + case GLRadioToolbarItem::Hover: + { + if (inside) + tooltip = item->get_tooltip(); + else + item->set_state(GLRadioToolbarItem::Normal); + + break; + } + case GLRadioToolbarItem::Pressed: + { + if (inside) + item->set_state(GLRadioToolbarItem::HoverPressed); + + break; + } + case GLRadioToolbarItem::HoverPressed: + { + if (inside) + tooltip = item->get_tooltip(); + else + item->set_state(GLRadioToolbarItem::Pressed); + + break; + } + default: + { + break; + } + } + + left += scaled_icons_size; + } + + return tooltip; +} + +void GLRadioToolbar::do_action(unsigned int item_id, GLCanvas3D& parent) +{ + for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i) + { + if (i != item_id) + m_items[i]->set_state(GLRadioToolbarItem::Normal); + } + + if (item_id < (unsigned int)m_items.size()) + { + GLRadioToolbarItem* item = m_items[item_id]; + if ((item != nullptr) && item->is_hovered() && !item->is_pressed()) + { + item->set_state(GLRadioToolbarItem::HoverPressed); + item->do_action(parent.get_wxglcanvas()); + } + } + + parent.set_as_dirty(); +} + +void GLRadioToolbar::render(const GLCanvas3D& parent) const +{ + if (m_items.empty()) + return; + + ::glDisable(GL_DEPTH_TEST); + + ::glPushMatrix(); + ::glLoadIdentity(); + + unsigned int tex_id = m_icons_texture.texture.get_id(); + int tex_size = m_icons_texture.texture.get_width(); + + if ((tex_id == 0) || (tex_size <= 0)) + return; + + float zoom = parent.get_camera_zoom(); + float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + + float scaled_icons_size = (float)m_icons_texture.items_icon_size * inv_zoom; + + float left = m_left; + float top = m_top; + + // renders icons + for (const GLRadioToolbarItem* item : m_items) + { + item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_size, m_icons_texture.items_icon_border_size, m_icons_texture.items_icon_size, m_icons_texture.items_icon_gap_size); + left += scaled_icons_size; + } + + ::glPopMatrix(); +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp index dde62c6452..85e606583e 100644 --- a/src/slic3r/GUI/GLToolbar.hpp +++ b/src/slic3r/GUI/GLToolbar.hpp @@ -26,6 +26,9 @@ wxDECLARE_EVENT(EVT_GLTOOLBAR_SPLIT_OBJECTS, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_SPLIT_VOLUMES, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_LAYERSEDITING, SimpleEvent); +wxDECLARE_EVENT(EVT_GLVIEWTOOLBAR_3D, SimpleEvent); +wxDECLARE_EVENT(EVT_GLVIEWTOOLBAR_PREVIEW, SimpleEvent); + class GLToolbarItem { public: @@ -86,25 +89,25 @@ private: GLTexture::Quad_UVs get_uvs(unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const; }; +// items icon textures are assumed to be square and all with the same size in pixels, no internal check is done +// icons are layed-out into the texture starting from the top-left corner in the same order as enum GLToolbarItem::EState +// from left to right +struct ItemsIconsTexture +{ + GLTexture texture; + // size of the square icons, in pixels + unsigned int items_icon_size; + // distance from the border, in pixels + unsigned int items_icon_border_size; + // distance between two adjacent icons (to avoid filtering artifacts), in pixels + unsigned int items_icon_gap_size; + + ItemsIconsTexture(); +}; + class GLToolbar { public: - // items icon textures are assumed to be square and all with the same size in pixels, no internal check is done - // icons are layed-out into the texture starting from the top-left corner in the same order as enum GLToolbarItem::EState - // from left to right - struct ItemsIconsTexture - { - GLTexture texture; - // size of the square icons, in pixels - unsigned int items_icon_size; - // distance from the border, in pixels - unsigned int items_icon_border_size; - // distance between two adjacent icons (to avoid filtering artifacts), in pixels - unsigned int items_icon_gap_size; - - ItemsIconsTexture(); - }; - struct Layout { enum Type : unsigned char @@ -160,7 +163,11 @@ public: bool is_item_pressed(const std::string& name) const; +#if ENABLE_REMOVE_TABS_FROM_PLATER + std::string update_hover_state(const Vec2d& mouse_pos); +#else void update_hover_state(const Vec2d& mouse_pos); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER // returns the id of the item under the given mouse position or -1 if none int contains_mouse(const Vec2d& mouse_pos) const; @@ -175,8 +182,13 @@ private: float get_height_horizontal() const; float get_height_vertical() const; float get_main_size() const; +#if ENABLE_REMOVE_TABS_FROM_PLATER + std::string update_hover_state_horizontal(const Vec2d& mouse_pos); + std::string update_hover_state_vertical(const Vec2d& mouse_pos); +#else void update_hover_state_horizontal(const Vec2d& mouse_pos); void update_hover_state_vertical(const Vec2d& mouse_pos); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER int contains_mouse_horizontal(const Vec2d& mouse_pos) const; int contains_mouse_vertical(const Vec2d& mouse_pos) const; @@ -184,6 +196,85 @@ private: void render_vertical() const; }; +class GLRadioToolbarItem +{ +public: + struct Data + { + std::string name; + std::string tooltip; + unsigned int sprite_id; + wxEventType action_event; + + Data(); + }; + + enum EState : unsigned char + { + Normal, + Pressed, + Hover, + HoverPressed, + Num_States + }; + +private: + EState m_state; + Data m_data; + +public: + GLRadioToolbarItem(const Data& data); + + EState get_state() const; + void set_state(EState state); + + const std::string& get_name() const; + const std::string& get_tooltip() const; + + bool is_hovered() const; + bool is_pressed() const; + + void do_action(wxEvtHandler *target); + + void render(unsigned int tex_id, float left, float right, float bottom, float top, unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const; + +private: + GLTexture::Quad_UVs get_uvs(unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const; +}; + +class GLRadioToolbar +{ + typedef std::vector ItemsList; + + ItemsIconsTexture m_icons_texture; + + ItemsList m_items; + float m_top; + float m_left; + +public: + GLRadioToolbar(); + ~GLRadioToolbar(); + + bool init(const std::string& icons_texture_filename, unsigned int items_icon_size, unsigned int items_icon_border_size, unsigned int items_icon_gap_size); + + bool add_item(const GLRadioToolbarItem::Data& data); + + float get_height() const; + + void set_position(float top, float left); + void set_selection(const std::string& name); + + // returns the id of the item under the given mouse position or -1 if none + int contains_mouse(const Vec2d& mouse_pos, const GLCanvas3D& parent) const; + + std::string update_hover_state(const Vec2d& mouse_pos, const GLCanvas3D& parent); + + void do_action(unsigned int item_id, GLCanvas3D& parent); + + void render(const GLCanvas3D& parent) const; +}; + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index a8ba5ba525..724815076e 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -92,6 +92,12 @@ bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, Ba return true; } +void View3D::set_view_toolbar(GLRadioToolbar* toolbar) +{ + if (m_canvas != nullptr) + m_canvas->set_view_toolbar(toolbar); +} + void View3D::set_as_dirty() { if (m_canvas != nullptr) @@ -358,6 +364,14 @@ Preview::~Preview() } } +#if ENABLE_REMOVE_TABS_FROM_PLATER +void Preview::set_view_toolbar(GLRadioToolbar* toolbar) +{ + if (m_canvas != nullptr) + m_canvas->set_view_toolbar(toolbar); +} +#endif // ENABLE_REMOVE_TABS_FROM_PLATER + void Preview::set_number_extruders(unsigned int number_extruders) { if (m_number_extruders != number_extruders) diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index dd2587d52a..bfccf9a98d 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -28,6 +28,9 @@ class Model; namespace GUI { class GLCanvas3D; +#if ENABLE_REMOVE_TABS_FROM_PLATER +class GLRadioToolbar; +#endif // ENABLE_REMOVE_TABS_FROM_PLATER #if ENABLE_REMOVE_TABS_FROM_PLATER class View3D : public wxPanel @@ -50,6 +53,8 @@ public: wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } GLCanvas3D* get_canvas3d() { return m_canvas; } + void set_view_toolbar(GLRadioToolbar* toolbar); + void set_as_dirty(); void set_bed_shape(const Pointfs& shape); @@ -116,6 +121,10 @@ public: wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } +#if ENABLE_REMOVE_TABS_FROM_PLATER + void set_view_toolbar(GLRadioToolbar* toolbar); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER + void set_number_extruders(unsigned int number_extruders); void reset_gcode_preview_data(); void set_canvas_as_dirty(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e0e9393855..20a9859283 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -931,6 +931,7 @@ struct Plater::priv Sidebar *sidebar; #if ENABLE_REMOVE_TABS_FROM_PLATER View3D* view3D; + GLRadioToolbar view_toolbar; #else #if !ENABLE_IMGUI wxPanel *panel3d; @@ -1031,6 +1032,9 @@ struct Plater::priv private: bool init_object_menu(); +#if ENABLE_REMOVE_TABS_FROM_PLATER + void init_view_toolbar(); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER bool can_delete_object() const; bool can_increase_instances() const; @@ -1201,6 +1205,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_OBJECTS, &priv::on_action_split_objects, this); view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_VOLUMES, &priv::on_action_split_volumes, this); view3D_canvas->Bind(EVT_GLTOOLBAR_LAYERSEDITING, &priv::on_action_layersediting, this); + view3D_canvas->Bind(EVT_GLCANVAS_INIT, [this](SimpleEvent&) { init_view_toolbar(); }); #else // 3DScene events: canvas3Dwidget->Bind(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, [this](SimpleEvent&) { this->schedule_background_process(); }); @@ -1230,9 +1235,16 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) // Preview events: preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_VIEWPORT_CHANGED, &priv::on_viewport_changed, this); +#if ENABLE_REMOVE_TABS_FROM_PLATER + view3D_canvas->Bind(EVT_GLCANVAS_INIT, [this](SimpleEvent&) { init_view_toolbar(); }); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER q->Bind(EVT_SLICING_COMPLETED, &priv::on_slicing_completed, this); q->Bind(EVT_PROCESS_COMPLETED, &priv::on_process_completed, this); +#if ENABLE_REMOVE_TABS_FROM_PLATER + q->Bind(EVT_GLVIEWTOOLBAR_3D, [q](SimpleEvent&) { q->select_view_3D("3D"); }); + q->Bind(EVT_GLVIEWTOOLBAR_PREVIEW, [q](SimpleEvent&) { q->select_view_3D("Preview"); }); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER // Drop target: q->SetDropTarget(new PlaterDropTarget(q)); // if my understanding is right, wxWindow takes the owenership @@ -2462,6 +2474,35 @@ bool Plater::priv::init_object_menu() return true; } +#if ENABLE_REMOVE_TABS_FROM_PLATER +void Plater::priv::init_view_toolbar() +{ + if (!view_toolbar.init("view_toolbar.png", 36, 1, 1)) + return; + + GLRadioToolbarItem::Data item; + + item.name = "3d"; + item.tooltip = GUI::L_str("3D editor view"); + item.sprite_id = 0; + item.action_event = EVT_GLVIEWTOOLBAR_3D; + if (!view_toolbar.add_item(item)) + return; + + item.name = "preview"; + item.tooltip = GUI::L_str("Preview"); + item.sprite_id = 1; + item.action_event = EVT_GLVIEWTOOLBAR_PREVIEW; + if (!view_toolbar.add_item(item)) + return; + + view3D->set_view_toolbar(&view_toolbar); + preview->set_view_toolbar(&view_toolbar); + + view_toolbar.set_selection("3d"); +} +#endif // ENABLE_REMOVE_TABS_FROM_PLATER + bool Plater::priv::can_delete_object() const { int obj_idx = get_selected_object_idx();