Merge branch 'master' into lm_drilling_backend_rebased

This commit is contained in:
Lukas Matena 2020-02-03 15:20:16 +01:00
commit a1d4dab999
63 changed files with 3891 additions and 3327 deletions

View file

@ -147,6 +147,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Mouse3DController.hpp
GUI/DoubleSlider.cpp
GUI/DoubleSlider.hpp
GUI/ObjectDataViewModel.cpp
GUI/ObjectDataViewModel.hpp
Utils/Http.cpp
Utils/Http.hpp
Utils/FixModelByWin10.cpp

View file

@ -10,7 +10,7 @@
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/Slicing.hpp"
#include "libslic3r/GCode/Analyzer.hpp"
#include "slic3r/GUI/PresetBundle.hpp"
#include "slic3r/GUI/BitmapCache.hpp"
#include "libslic3r/Format/STL.hpp"
#include "libslic3r/Utils.hpp"
@ -792,14 +792,14 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* con
for (unsigned int i = 0; i < colors_count; ++i)
{
const std::string& txt_color = config->opt_string("extruder_colour", i);
if (PresetBundle::parse_color(txt_color, rgb))
if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
{
colors[i].set(txt_color, rgb);
}
else
{
const std::string& txt_color = config->opt_string("filament_colour", i);
if (PresetBundle::parse_color(txt_color, rgb))
if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
colors[i].set(txt_color, rgb);
}
}

View file

@ -1,6 +1,9 @@
#include "BitmapCache.hpp"
#include "libslic3r/Utils.hpp"
#include "../Utils/MacDarkMode.hpp"
#include "GUI.hpp"
#include <boost/filesystem.hpp>
#if ! defined(WIN32) && ! defined(__APPLE__)
@ -20,6 +23,16 @@
namespace Slic3r { namespace GUI {
BitmapCache::BitmapCache()
{
#ifdef __APPLE__
// Note: win->GetContentScaleFactor() is not used anymore here because it tends to
// return bogus results quite often (such as 1.0 on Retina or even 0.0).
// We're using the max scaling factor across all screens because it's very likely to be good enough.
m_scale = mac_max_scaling_factor();
#endif
}
void BitmapCache::clear()
{
for (std::pair<const std::string, wxBitmap*> &bitmap : m_map)
@ -55,6 +68,14 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_
auto it = m_map.find(bitmap_key);
if (it == m_map.end()) {
bitmap = new wxBitmap(width, height);
#ifdef __APPLE__
// Contrary to intuition, the `scale` argument isn't "please scale this to such and such"
// but rather "the wxImage is sized for backing scale such and such".
// So, We need to let the Mac OS wxBitmap implementation
// know that the image may already be scaled appropriately for Retina,
// and thereby that it's not supposed to upscale it.
bitmap->CreateScaled(width, height, -1, m_scale);
#endif
m_map[bitmap_key] = bitmap;
} else {
bitmap = it->second;
@ -100,8 +121,13 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg
size_t width = 0;
size_t height = 0;
for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) {
#ifdef __APPLE__
width += bmp->GetScaledWidth();
height = std::max<size_t>(height, bmp->GetScaledHeight());
#else
width += bmp->GetWidth();
height = std::max<size_t>(height, bmp->GetHeight());
#endif
}
#ifdef BROKEN_ALPHA
@ -167,7 +193,12 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg
for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) {
if (bmp->GetWidth() > 0)
memDC.DrawBitmap(*bmp, x, 0, true);
#ifdef __APPLE__
// we should "move" with step equal to non-scaled width
x += bmp->GetScaledWidth();
#else
x += bmp->GetWidth();
#endif
}
memDC.SelectObject(wxNullBitmap);
return bitmap;
@ -175,7 +206,7 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg
#endif
}
wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, float scale /* = 1.0f */, const bool grayscale/* = false*/)
wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, const bool grayscale/* = false*/)
{
wxImage image(width, height);
image.InitAlpha();
@ -192,7 +223,7 @@ wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned w
if (grayscale)
image = image.ConvertToGreyscale(m_gs, m_gs, m_gs);
return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image), scale));
return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image), m_scale));
}
wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned width, unsigned height,
@ -227,12 +258,12 @@ wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned width,
}
wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_width, unsigned target_height,
float scale /* = 1.0f */, const bool grayscale/* = false*/, const bool dark_mode/* = false*/)
const bool grayscale/* = false*/, const bool dark_mode/* = false*/)
{
std::string bitmap_key = bitmap_name + ( target_height !=0 ?
"-h" + std::to_string(target_height) :
"-w" + std::to_string(target_width))
+ (scale != 1.0f ? "-s" + std::to_string(scale) : "")
+ (m_scale != 1.0f ? "-s" + std::to_string(m_scale) : "")
+ (grayscale ? "-gs" : "");
/* For the Dark mode of any platform, we should draw icons in respect to OS background
@ -272,7 +303,7 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_
if (image == nullptr)
return nullptr;
target_height != 0 ? target_height *= scale : target_width *= scale;
target_height != 0 ? target_height *= m_scale : target_width *= m_scale;
float svg_scale = target_height != 0 ?
(float)target_height / image->height : target_width != 0 ?
@ -297,11 +328,16 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_
::nsvgDeleteRasterizer(rast);
::nsvgDelete(image);
return this->insert_raw_rgba(bitmap_key, width, height, data.data(), scale, grayscale);
return this->insert_raw_rgba(bitmap_key, width, height, data.data(), grayscale);
}
wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency)
//we make scaled solid bitmaps only for the cases, when its will be used with scaled SVG icon in one output bitmap
wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency, bool suppress_scaling/* = false*/)
{
double scale = suppress_scaling ? 1.0f : m_scale;
width *= scale;
height *= scale;
wxImage image(width, height);
image.InitAlpha();
unsigned char* imgdata = image.GetData();
@ -312,7 +348,32 @@ wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsi
*imgdata ++ = b;
*imgalpha ++ = transparency;
}
return wxImage_to_wxBitmap_with_alpha(std::move(image));
return wxImage_to_wxBitmap_with_alpha(std::move(image), scale);
}
static inline int hex_digit_to_int(const char c)
{
return
(c >= '0' && c <= '9') ? int(c - '0') :
(c >= 'A' && c <= 'F') ? int(c - 'A') + 10 :
(c >= 'a' && c <= 'f') ? int(c - 'a') + 10 : -1;
}
bool BitmapCache::parse_color(const std::string& scolor, unsigned char* rgb_out)
{
rgb_out[0] = rgb_out[1] = rgb_out[2] = 0;
if (scolor.size() != 7 || scolor.front() != '#')
return false;
const char* c = scolor.data() + 1;
for (size_t i = 0; i < 3; ++i) {
int digit1 = hex_digit_to_int(*c++);
int digit2 = hex_digit_to_int(*c++);
if (digit1 == -1 || digit2 == -1)
return false;
rgb_out[i] = (unsigned char)(digit1 * 16 + digit2);
}
return true;
}
} // namespace GUI

View file

@ -1,24 +1,22 @@
#ifndef SLIC3R_GUI_BITMAP_CACHE_HPP
#define SLIC3R_GUI_BITMAP_CACHE_HPP
#include <map>
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include "libslic3r/libslic3r.h"
#include "libslic3r/Config.hpp"
#include "GUI.hpp"
namespace Slic3r { namespace GUI {
class BitmapCache
{
public:
BitmapCache() {}
BitmapCache();
~BitmapCache() { clear(); }
void clear();
double scale() { return m_scale; }
wxBitmap* find(const std::string &name) { auto it = m_map.find(name); return (it == m_map.end()) ? nullptr : it->second; }
const wxBitmap* find(const std::string &name) const { return const_cast<BitmapCache*>(this)->find(name); }
@ -29,20 +27,23 @@ public:
wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3);
wxBitmap* insert(const std::string &name, const std::vector<wxBitmap> &bmps) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size()); }
wxBitmap* insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end);
wxBitmap* insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, float scale = 1.0f, const bool grayscale = false);
wxBitmap* insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, const bool grayscale = false);
// Load png from resources/icons. bitmap_key is given without the .png suffix. Bitmap will be rescaled to provided height/width if nonzero.
wxBitmap* load_png(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false);
// Load svg from resources/icons. bitmap_key is given without the .svg suffix. SVG will be rasterized to provided height/width.
wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, float scale = 1.0f, const bool grayscale = false, const bool dark_mode = false);
wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false, const bool dark_mode = false);
static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency);
static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); }
static wxBitmap mkclear(size_t width, size_t height) { return mksolid(width, height, 0, 0, 0, wxALPHA_TRANSPARENT); }
/*static */wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency, bool suppress_scaling = false);
/*static */wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3], bool suppress_scaling = false) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); }
/*static */wxBitmap mkclear(size_t width, size_t height) { return mksolid(width, height, 0, 0, 0, wxALPHA_TRANSPARENT); }
static bool parse_color(const std::string& scolor, unsigned char* rgb_out);
private:
std::map<std::string, wxBitmap*> m_map;
double m_gs = 0.2; // value, used for image.ConvertToGreyscale(m_gs, m_gs, m_gs)
double m_gs = 0.2; // value, used for image.ConvertToGreyscale(m_gs, m_gs, m_gs)
double m_scale = 1.0; // value, used for correct scaling of SVG icons on Retina display
};
} // GUI

View file

@ -14,7 +14,9 @@
#include <GL/glew.h>
#if !ENABLE_6DOF_CAMERA
static const float GIMBALL_LOCK_THETA_MAX = 180.0f;
#endif // !ENABLE_6DOF_CAMERA
// phi / theta angles to orient the camera.
static const float VIEW_DEFAULT[2] = { 45.0f, 45.0f };
@ -66,13 +68,10 @@ std::string Camera::get_type_as_string() const
{
switch (m_type)
{
case Unknown:
return "unknown";
case Perspective:
return "perspective";
case Unknown: return "unknown";
case Perspective: return "perspective";
default:
case Ortho:
return "orthographic";
case Ortho: return "orthographic";
};
}
@ -88,10 +87,7 @@ void Camera::set_type(EType type)
void Camera::set_type(const std::string& type)
{
if (type == "1")
set_type(Perspective);
else
set_type(Ortho);
set_type((type == "1") ? Perspective : Ortho);
}
void Camera::select_next_type()
@ -157,17 +153,17 @@ void Camera::select_view(const std::string& direction)
if (direction == "iso")
set_default_orientation();
else if (direction == "left")
m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitX(), m_target, Vec3d::UnitZ());
look_at(m_target - m_distance * Vec3d::UnitX(), m_target, Vec3d::UnitZ());
else if (direction == "right")
m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitX(), m_target, Vec3d::UnitZ());
look_at(m_target + m_distance * Vec3d::UnitX(), m_target, Vec3d::UnitZ());
else if (direction == "top")
m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitZ(), m_target, Vec3d::UnitY());
look_at(m_target + m_distance * Vec3d::UnitZ(), m_target, Vec3d::UnitY());
else if (direction == "bottom")
m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitZ(), m_target, -Vec3d::UnitY());
look_at(m_target - m_distance * Vec3d::UnitZ(), m_target, -Vec3d::UnitY());
else if (direction == "front")
m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitY(), m_target, Vec3d::UnitZ());
look_at(m_target - m_distance * Vec3d::UnitY(), m_target, Vec3d::UnitZ());
else if (direction == "rear")
m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitY(), m_target, Vec3d::UnitZ());
look_at(m_target + m_distance * Vec3d::UnitY(), m_target, Vec3d::UnitZ());
}
#else
bool Camera::select_view(const std::string& direction)
@ -244,17 +240,27 @@ void Camera::apply_view_matrix() const
void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double far_z) const
{
#if !ENABLE_6DOF_CAMERA
set_distance(DefaultDistance);
#endif // !ENABLE_6DOF_CAMERA
double w = 0.0;
double h = 0.0;
#if ENABLE_6DOF_CAMERA
double old_distance = m_distance;
m_frustrum_zs = calc_tight_frustrum_zs_around(box);
if (m_distance != old_distance)
// the camera has been moved re-apply view matrix
apply_view_matrix();
#else
while (true)
{
m_frustrum_zs = calc_tight_frustrum_zs_around(box);
#endif // !ENABLE_6DOF_CAMERA
if (near_z > 0.0)
m_frustrum_zs.first = std::min(m_frustrum_zs.first, near_z);
m_frustrum_zs.first = std::max(std::min(m_frustrum_zs.first, near_z), FrustrumMinNearZ);
if (far_z > 0.0)
m_frustrum_zs.second = std::max(m_frustrum_zs.second, far_z);
@ -262,12 +268,9 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa
w = 0.5 * (double)m_viewport[2];
h = 0.5 * (double)m_viewport[3];
if (m_zoom != 0.0)
{
double inv_zoom = 1.0 / m_zoom;
w *= inv_zoom;
h *= inv_zoom;
}
double inv_zoom = get_inv_zoom();
w *= inv_zoom;
h *= inv_zoom;
switch (m_type)
{
@ -288,6 +291,7 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa
}
}
#if !ENABLE_6DOF_CAMERA
if (m_type == Perspective)
{
double fov_deg = Geometry::rad2deg(2.0 * std::atan(h / m_frustrum_zs.first));
@ -307,6 +311,7 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa
else
break;
}
#endif // !ENABLE_6DOF_CAMERA
glsafe(::glMatrixMode(GL_PROJECTION));
glsafe(::glLoadIdentity());
@ -331,14 +336,22 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa
}
#if ENABLE_THUMBNAIL_GENERATOR
#if ENABLE_6DOF_CAMERA
void Camera::zoom_to_box(const BoundingBoxf3& box, double margin_factor)
#else
void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h, double margin_factor)
#endif // ENABLE_6DOF_CAMERA
#else
void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h)
#endif // ENABLE_THUMBNAIL_GENERATOR
{
// Calculate the zoom factor needed to adjust the view around the given box.
#if ENABLE_THUMBNAIL_GENERATOR
#if ENABLE_6DOF_CAMERA
double zoom = calc_zoom_to_bounding_box_factor(box, margin_factor);
#else
double zoom = calc_zoom_to_bounding_box_factor(box, canvas_w, canvas_h, margin_factor);
#endif // ENABLE_6DOF_CAMERA
#else
double zoom = calc_zoom_to_bounding_box_factor(box, canvas_w, canvas_h);
#endif // ENABLE_THUMBNAIL_GENERATOR
@ -355,10 +368,18 @@ void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h)
}
#if ENABLE_THUMBNAIL_GENERATOR
#if ENABLE_6DOF_CAMERA
void Camera::zoom_to_volumes(const GLVolumePtrs& volumes, double margin_factor)
#else
void Camera::zoom_to_volumes(const GLVolumePtrs& volumes, int canvas_w, int canvas_h, double margin_factor)
#endif // ENABLE_6DOF_CAMERA
{
Vec3d center;
#if ENABLE_6DOF_CAMERA
double zoom = calc_zoom_to_volumes_factor(volumes, center, margin_factor);
#else
double zoom = calc_zoom_to_volumes_factor(volumes, canvas_w, canvas_h, center, margin_factor);
#endif // ENABLE_6DOF_CAMERA
if (zoom > 0.0)
{
m_zoom = zoom;
@ -396,6 +417,7 @@ void Camera::debug_render() const
float deltaZ = farZ - nearZ;
float zoom = (float)m_zoom;
float fov = (float)get_fov();
std::array<int, 4>viewport = get_viewport();
float gui_scale = (float)get_gui_scale();
ImGui::InputText("Type", type.data(), type.length(), ImGuiInputTextFlags_ReadOnly);
@ -415,6 +437,8 @@ void Camera::debug_render() const
ImGui::InputFloat("Zoom", &zoom, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly);
ImGui::InputFloat("Fov", &fov, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly);
ImGui::Separator();
ImGui::InputInt4("Viewport", viewport.data(), ImGuiInputTextFlags_ReadOnly);
ImGui::Separator();
ImGui::InputFloat("GUI scale", &gui_scale, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly);
imgui.end();
}
@ -434,10 +458,31 @@ void Camera::translate_world(const Vec3d& displacement)
void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad)
{
// FIXME -> The following is a HACK !!!
// When the value of the zenit rotation is large enough, the following call to rotate() shows
// numerical instability introducing some scaling into m_view_matrix (verified by checking
// that the camera space unit vectors are no more unit).
// See also https://dev.prusa3d.com/browse/SPE-1082
// We split the zenit rotation into a set of smaller rotations which are then applied.
static const double MAX_ALLOWED = Geometry::deg2rad(0.1);
unsigned int zenit_steps_count = 1 + (unsigned int)(std::abs(delta_zenit_rad) / MAX_ALLOWED);
double zenit_step = delta_zenit_rad / (double)zenit_steps_count;
Vec3d target = m_target;
translate_world(-target);
m_view_matrix.rotate(Eigen::AngleAxisd(delta_zenit_rad, get_dir_right()));
m_view_matrix.rotate(Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ()));
if (zenit_step != 0.0)
{
Vec3d right = get_dir_right();
for (unsigned int i = 0; i < zenit_steps_count; ++i)
{
m_view_matrix.rotate(Eigen::AngleAxisd(zenit_step, right));
}
}
if (delta_azimut_rad != 0.0)
m_view_matrix.rotate(Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ()));
translate_world(target);
}
@ -457,49 +502,77 @@ void Camera::rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& p
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(2), get_dir_forward()));
translate_world(center);
}
#endif // ENABLE_6DOF_CAMERA
double Camera::min_zoom() const
{
return 0.7 * calc_zoom_to_bounding_box_factor(m_scene_box, (int)m_viewport[2], (int)m_viewport[3]);
}
#if ENABLE_6DOF_CAMERA
return 0.7 * calc_zoom_to_bounding_box_factor(m_scene_box);
#else
return 0.7 * calc_zoom_to_bounding_box_factor(m_scene_box, m_viewport[2], m_viewport[3]);
#endif // ENABLE_6DOF_CAMERA
}
std::pair<double, double> Camera::calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const
{
std::pair<double, double> ret;
auto& [near_z, far_z] = ret;
#if !ENABLE_6DOF_CAMERA
while (true)
{
#endif // !ENABLE_6DOF_CAMERA
// box in eye space
BoundingBoxf3 eye_box = box.transformed(m_view_matrix);
ret.first = -eye_box.max(2);
ret.second = -eye_box.min(2);
near_z = -eye_box.max(2);
far_z = -eye_box.min(2);
// apply margin
ret.first -= FrustrumZMargin;
ret.second += FrustrumZMargin;
near_z -= FrustrumZMargin;
far_z += FrustrumZMargin;
// ensure min size
if (ret.second - ret.first < FrustrumMinZRange)
if (far_z - near_z < FrustrumMinZRange)
{
double mid_z = 0.5 * (ret.first + ret.second);
double mid_z = 0.5 * (near_z + far_z);
double half_size = 0.5 * FrustrumMinZRange;
ret.first = mid_z - half_size;
ret.second = mid_z + half_size;
near_z = mid_z - half_size;
far_z = mid_z + half_size;
}
if (ret.first >= FrustrumMinNearZ)
#if ENABLE_6DOF_CAMERA
if (near_z < FrustrumMinNearZ)
{
float delta = FrustrumMinNearZ - near_z;
set_distance(m_distance + delta);
near_z += delta;
far_z += delta;
}
else if ((near_z > 2.0 * FrustrumMinNearZ) && (m_distance > DefaultDistance))
{
float delta = m_distance - DefaultDistance;
set_distance(DefaultDistance);
near_z -= delta;
far_z -= delta;
}
#else
if (near_z >= FrustrumMinNearZ)
break;
// ensure min Near Z
set_distance(m_distance + FrustrumMinNearZ - ret.first);
// ensure min near z
set_distance(m_distance + FrustrumMinNearZ - near_z);
}
#endif // ENABLE_6DOF_CAMERA
return ret;
}
#if ENABLE_THUMBNAIL_GENERATOR
#if ENABLE_6DOF_CAMERA
double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, double margin_factor) const
#else
double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h, double margin_factor) const
#endif // ENABLE_6DOF_CAMERA
#else
double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const
#endif // ENABLE_THUMBNAIL_GENERATOR
@ -511,8 +584,10 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca
// project the box vertices on a plane perpendicular to the camera forward axis
// then calculates the vertices coordinate on this plane along the camera xy axes
#if !ENABLE_6DOF_CAMERA
// ensure that the view matrix is updated
apply_view_matrix();
#endif // !ENABLE_6DOF_CAMERA
Vec3d right = get_dir_right();
Vec3d up = get_dir_up();
@ -569,11 +644,19 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca
dx *= margin_factor;
dy *= margin_factor;
#if ENABLE_6DOF_CAMERA
return std::min((double)m_viewport[2] / dx, (double)m_viewport[3] / dy);
#else
return std::min((double)canvas_w / dx, (double)canvas_h / dy);
#endif // ENABLE_6DOF_CAMERA
}
#if ENABLE_THUMBNAIL_GENERATOR
#if ENABLE_6DOF_CAMERA
double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, Vec3d& center, double margin_factor) const
#else
double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, int canvas_w, int canvas_h, Vec3d& center, double margin_factor) const
#endif // ENABLE_6DOF_CAMERA
{
if (volumes.empty())
return -1.0;
@ -581,8 +664,10 @@ double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, int canv
// project the volumes vertices on a plane perpendicular to the camera forward axis
// then calculates the vertices coordinate on this plane along the camera xy axes
#if !ENABLE_6DOF_CAMERA
// ensure that the view matrix is updated
apply_view_matrix();
#endif // !ENABLE_6DOF_CAMERA
Vec3d right = get_dir_right();
Vec3d up = get_dir_up();
@ -634,46 +719,57 @@ double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, int canv
if ((dx <= 0.0) || (dy <= 0.0))
return -1.0f;
#if ENABLE_6DOF_CAMERA
return std::min((double)m_viewport[2] / dx, (double)m_viewport[3] / dy);
#else
return std::min((double)canvas_w / dx, (double)canvas_h / dy);
#endif // ENABLE_6DOF_CAMERA
}
#endif // ENABLE_THUMBNAIL_GENERATOR
void Camera::set_distance(double distance) const
{
#if ENABLE_6DOF_CAMERA
if (m_distance != distance)
{
m_view_matrix.translate((distance - m_distance) * get_dir_forward());
m_distance = distance;
}
#else
m_distance = distance;
apply_view_matrix();
#endif // ENABLE_6DOF_CAMERA
}
#if ENABLE_6DOF_CAMERA
Transform3d Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up) const
void Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up)
{
Vec3d unit_z = (position - target).normalized();
Vec3d unit_x = up.cross(unit_z).normalized();
Vec3d unit_y = unit_z.cross(unit_x).normalized();
Transform3d matrix;
m_target = target;
Vec3d new_position = m_target + m_distance * unit_z;
matrix(0, 0) = unit_x(0);
matrix(0, 1) = unit_x(1);
matrix(0, 2) = unit_x(2);
matrix(0, 3) = -unit_x.dot(position);
m_view_matrix(0, 0) = unit_x(0);
m_view_matrix(0, 1) = unit_x(1);
m_view_matrix(0, 2) = unit_x(2);
m_view_matrix(0, 3) = -unit_x.dot(new_position);
matrix(1, 0) = unit_y(0);
matrix(1, 1) = unit_y(1);
matrix(1, 2) = unit_y(2);
matrix(1, 3) = -unit_y.dot(position);
m_view_matrix(1, 0) = unit_y(0);
m_view_matrix(1, 1) = unit_y(1);
m_view_matrix(1, 2) = unit_y(2);
m_view_matrix(1, 3) = -unit_y.dot(new_position);
matrix(2, 0) = unit_z(0);
matrix(2, 1) = unit_z(1);
matrix(2, 2) = unit_z(2);
matrix(2, 3) = -unit_z.dot(position);
m_view_matrix(2, 0) = unit_z(0);
m_view_matrix(2, 1) = unit_z(1);
m_view_matrix(2, 2) = unit_z(2);
m_view_matrix(2, 3) = -unit_z.dot(new_position);
matrix(3, 0) = 0.0;
matrix(3, 1) = 0.0;
matrix(3, 2) = 0.0;
matrix(3, 3) = 1.0;
return matrix;
m_view_matrix(3, 0) = 0.0;
m_view_matrix(3, 1) = 0.0;
m_view_matrix(3, 2) = 0.0;
m_view_matrix(3, 3) = 1.0;
}
void Camera::set_default_orientation()

View file

@ -48,11 +48,7 @@ private:
mutable double m_gui_scale;
mutable std::array<int, 4> m_viewport;
#if ENABLE_6DOF_CAMERA
Transform3d m_view_matrix;
#else
mutable Transform3d m_view_matrix;
#endif // ENABLE_6DOF_CAMERA
mutable Transform3d m_projection_matrix;
mutable std::pair<double, double> m_frustrum_zs;
@ -71,7 +67,11 @@ public:
const Vec3d& get_target() const { return m_target; }
void set_target(const Vec3d& target);
#if ENABLE_6DOF_CAMERA
double get_distance() const { return (get_position() - m_target).norm(); }
#else
double get_distance() const { return m_distance; }
#endif // ENABLE_6DOF_CAMERA
double get_gui_scale() const { return m_gui_scale; }
#if !ENABLE_6DOF_CAMERA
@ -115,8 +115,13 @@ public:
void apply_projection(const BoundingBoxf3& box, double near_z = -1.0, double far_z = -1.0) const;
#if ENABLE_THUMBNAIL_GENERATOR
#if ENABLE_6DOF_CAMERA
void zoom_to_box(const BoundingBoxf3& box, double margin_factor = DefaultZoomToBoxMarginFactor);
void zoom_to_volumes(const GLVolumePtrs& volumes, double margin_factor = DefaultZoomToVolumesMarginFactor);
#else
void zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h, double margin_factor = DefaultZoomToBoxMarginFactor);
void zoom_to_volumes(const GLVolumePtrs& volumes, int canvas_w, int canvas_h, double margin_factor = DefaultZoomToVolumesMarginFactor);
#endif // ENABLE_6DOF_CAMERA
#else
void zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h);
#endif // ENABLE_THUMBNAIL_GENERATOR
@ -141,25 +146,29 @@ public:
// returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis
bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; }
#endif // ENABLE_6DOF_CAMERA
double max_zoom() const { return 100.0; }
double min_zoom() const;
#endif // ENABLE_6DOF_CAMERA
private:
// returns tight values for nearZ and farZ plane around the given bounding box
// the camera MUST be outside of the bounding box in eye coordinate of the given box
std::pair<double, double> calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const;
#if ENABLE_THUMBNAIL_GENERATOR
#if ENABLE_6DOF_CAMERA
double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, double margin_factor = DefaultZoomToBoxMarginFactor) const;
double calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, Vec3d& center, double margin_factor = DefaultZoomToVolumesMarginFactor) const;
#else
double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h, double margin_factor = DefaultZoomToBoxMarginFactor) const;
double calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, int canvas_w, int canvas_h, Vec3d& center, double margin_factor = DefaultZoomToVolumesMarginFactor) const;
#endif // ENABLE_6DOF_CAMERA
#else
double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const;
#endif // ENABLE_THUMBNAIL_GENERATOR
void set_distance(double distance) const;
#if ENABLE_6DOF_CAMERA
Transform3d look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up) const;
void look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up);
void set_default_orientation();
Vec3d validate_target(const Vec3d& target) const;
#endif // ENABLE_6DOF_CAMERA

View file

@ -52,28 +52,26 @@ Control::Control( wxWindow *parent,
if (!is_osx)
SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX
const float scale_factor = get_svg_scale_factor(this);
m_bmp_thumb_higher = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "right_half_circle.png") : ScalableBitmap(this, "thumb_up"));
m_bmp_thumb_lower = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "left_half_circle.png" ) : ScalableBitmap(this, "thumb_down"));
m_thumb_size = m_bmp_thumb_lower.bmp().GetSize()*(1.0/scale_factor);
m_thumb_size = m_bmp_thumb_lower.GetBmpSize();
m_bmp_add_tick_on = ScalableBitmap(this, "colorchange_add");
m_bmp_add_tick_off = ScalableBitmap(this, "colorchange_add_f");
m_bmp_del_tick_on = ScalableBitmap(this, "colorchange_del");
m_bmp_del_tick_off = ScalableBitmap(this, "colorchange_del_f");
m_tick_icon_dim = int((float)m_bmp_add_tick_on.bmp().GetSize().x / scale_factor);
m_tick_icon_dim = m_bmp_add_tick_on.GetBmpWidth();
m_bmp_one_layer_lock_on = ScalableBitmap(this, "lock_closed");
m_bmp_one_layer_lock_off = ScalableBitmap(this, "lock_closed_f");
m_bmp_one_layer_unlock_on = ScalableBitmap(this, "lock_open");
m_bmp_one_layer_unlock_off = ScalableBitmap(this, "lock_open_f");
m_lock_icon_dim = int((float)m_bmp_one_layer_lock_on.bmp().GetSize().x / scale_factor);
m_lock_icon_dim = m_bmp_one_layer_lock_on.GetBmpWidth();
m_bmp_revert = ScalableBitmap(this, "undo");
m_revert_icon_dim = int((float)m_bmp_revert.bmp().GetSize().x / scale_factor);
m_revert_icon_dim = m_bmp_revert.GetBmpWidth();
m_bmp_cog = ScalableBitmap(this, "cog");
m_cog_icon_dim = int((float)m_bmp_cog.bmp().GetSize().x / scale_factor);
m_cog_icon_dim = m_bmp_cog.GetBmpWidth();
m_selection = ssUndef;
m_ticks.set_pause_print_msg(_utf8(L("Place bearings in slots and resume")));
@ -554,16 +552,9 @@ void Control::draw_ticks(wxDC& dc)
// Draw icon for "Pause print" or "Custom Gcode"
if (tick.gcode != ColorChangeCode && tick.gcode != ToolChangeCode)
icon = create_scaled_bitmap(this, tick.gcode == PausePrintCode ? "pause_print" : "edit_gcode");
else
{
if ((tick.gcode == ColorChangeCode && (
(m_ticks.mode == t_mode::SingleExtruder && m_mode == t_mode::MultiExtruder ) ||
(m_ticks.mode == t_mode::MultiExtruder && m_mode == t_mode::SingleExtruder) )) ||
(tick.gcode == ToolChangeCode &&
(m_ticks.mode == t_mode::MultiAsSingle && m_mode != t_mode::MultiAsSingle ) ))
icon = create_scaled_bitmap(this, "error_tick");
}
icon = create_scaled_bitmap(tick.gcode == PausePrintCode ? "pause_print" : "edit_gcode");
else if (m_ticks.is_conflict_tick(tick, m_mode, m_only_extruder, m_values[tick.tick]))
icon = create_scaled_bitmap("error_tick");
if (!icon.IsNull())
{
@ -753,7 +744,7 @@ bool Control::is_point_in_rect(const wxPoint& pt, const wxRect& rect)
rect.GetTop() <= pt.y && pt.y <= rect.GetBottom();
}
int Control::is_point_near_tick(const wxPoint& pt)
int Control::get_tick_near_point(const wxPoint& pt)
{
for (auto tick : m_ticks.ticks) {
const wxCoord pos = get_position_from_value(tick.tick);
@ -833,7 +824,7 @@ void Control::OnLeftDown(wxMouseEvent& event)
detect_selected_slider(pos);
if (!m_selection) {
const int tick_val = is_point_near_tick(pos);
const int tick_val = get_tick_near_point(pos);
/* Set current thumb position to the nearest tick (if it is)
* OR to a value corresponding to the mouse click
* */
@ -896,20 +887,70 @@ wxString Control::get_tooltip(IconFocus icon_focus)
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
const auto tick_code_it = m_ticks.ticks.find(TickCode{tick});
tooltip = tick_code_it == m_ticks.ticks.end() ? (m_mode == t_mode::MultiAsSingle ?
_(L("For add change extruder use left mouse button click")) :
_(L("For add color change use left mouse button click")) ) + "\n" +
_(L("For add another code use right mouse button click")) :
tick_code_it->gcode == ColorChangeCode ? ( m_mode == t_mode::SingleExtruder ?
_(L("For Delete color change use left mouse button click\n"
"For Edit color use right mouse button click")) :
from_u8((boost::format(_utf8(L("Delete color change for Extruder %1%"))) % tick_code_it->extruder).str()) ):
tick_code_it->gcode == PausePrintCode ?
_(L("Delete pause")) :
tick_code_it->gcode == ToolChangeCode ?
from_u8((boost::format(_utf8(L("Delete extruder change to \"%1%\""))) % tick_code_it->extruder).str()) :
from_u8((boost::format(_utf8(L("For Delete \"%1%\" code use left mouse button click\n"
"For Edit \"%1%\" code use right mouse button click"))) % tick_code_it->gcode ).str());
/* Note: just on OSX!!!
* Right click event causes a little scrolling.
* So, as a workaround we use Ctrl+LeftMouseClick instead of RightMouseClick
* Show this information in tooltip
* */
if (tick_code_it == m_ticks.ticks.end()) // tick doesn't exist
{
// Show mode as a first string of tooltop
tooltip = " " + _(L("Slider(print) mode")) + ": ";
tooltip += (m_mode == t_mode::SingleExtruder ? CustomGCode::SingleExtruderMode :
m_mode == t_mode::MultiAsSingle ? CustomGCode::MultiAsSingleMode :
CustomGCode::MultiExtruderMode );
tooltip += "\n\n";
// Show list of actions with new tick
tooltip += ( m_mode == t_mode::MultiAsSingle ?
_(L("For add change extruder use left mouse button click")) :
_(L("For add color change use left mouse button click")) ) + " " +
_(L("OR pres \"+\" key")) + "\n" + (
is_osx ?
_(L("For add another code use Ctrl + Left mouse button click")) :
_(L("For add another code use right mouse button click")) );
}
else // tick exists
{
// Show custom Gcode as a first string of tooltop
tooltip = " ";
tooltip += tick_code_it->gcode == ColorChangeCode ? (
m_mode == t_mode::SingleExtruder ?
from_u8((boost::format(_utf8(L("Color change (\"%1%\")"))) % tick_code_it->gcode ).str()) :
from_u8((boost::format(_utf8(L("Color change (\"%1%\") for Extruder %2%"))) %
tick_code_it->gcode % tick_code_it->extruder).str()) ) :
tick_code_it->gcode == PausePrintCode ?
from_u8((boost::format(_utf8(L("Pause print (\"%1%\")"))) % tick_code_it->gcode ).str()) :
tick_code_it->gcode == ToolChangeCode ?
from_u8((boost::format(_utf8(L("Extruder(tool) is changed to Extruder \"%1%\""))) % tick_code_it->extruder ).str()) :
from_u8((boost::format(_utf8(L("\"%1%\""))) % tick_code_it->gcode ).str()) ;
// If tick is marked as a conflict (exclamation icon),
// we should to explain why
ConflictType conflict = m_ticks.is_conflict_tick(*tick_code_it, m_mode, m_only_extruder, m_values[tick]);
if (conflict != ctNone)
tooltip += "\n\n" + _(L("Note")) + "! ";
if (conflict == ctModeConflict)
tooltip += _(L("G-code of this tick has a conflict with slider(print) mode.\n"
"Any its editing will cause a changes of DoubleSlider data."));
else if (conflict == ctMeaninglessColorChange)
tooltip += _(L("There is a color change for extruder that wouldn't be used till the end of printing.\n"
"This code wouldn't be processed during GCode generation."));
else if (conflict == ctMeaninglessToolChange)
tooltip += _(L("There is a extruder change to the same extruder.\n"
"This code wouldn't be processed during GCode generation."));
else if (conflict == ctRedundant)
tooltip += _(L("There is a color change for extruder that has not been used before.\n"
"Check your choice to avoid redundant color changes."));
// Show list of actions with existing tick
tooltip += "\n\n" + _(L("For Delete tick use left mouse button click OR pres \"-\" key")) + "\n" + (
is_osx ?
_(L("For Edit tick use Ctrl + Left mouse button click")) :
_(L("For Edit tick use right mouse button click")) );
}
}
return tooltip;
@ -988,7 +1029,7 @@ void Control::append_change_extruder_menu_item(wxMenu* menu, bool switch_current
_(L("Change extruder (N/A)"));
wxMenuItem* change_extruder_menu_item = menu->AppendSubMenu(change_extruder_menu, change_extruder_menu_name, _(L("Use another extruder")));
change_extruder_menu_item->SetBitmap(create_scaled_bitmap(this, active_extruders[1] > 0 ? "edit_uni" : "change_extruder"));
change_extruder_menu_item->SetBitmap(create_scaled_bitmap(active_extruders[1] > 0 ? "edit_uni" : "change_extruder"));
GUI::wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this, change_extruder_menu_item](wxUpdateUIEvent& evt) {
enable_menu_item(evt, [this]() {return m_mode == t_mode::MultiAsSingle; }, change_extruder_menu_item, this); },
@ -1001,7 +1042,8 @@ void Control::append_add_color_change_menu_item(wxMenu* menu, bool switch_curren
const int extruders_cnt = GUI::wxGetApp().extruders_edited_cnt();
if (extruders_cnt > 1)
{
std::set<int> used_extruders_for_tick = get_used_extruders_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value);
int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
std::set<int> used_extruders_for_tick = m_ticks.get_used_extruders_for_tick(tick, m_only_extruder, m_values[tick]);
wxMenu* add_color_change_menu = new wxMenu();
@ -1014,14 +1056,14 @@ void Control::append_add_color_change_menu_item(wxMenu* menu, bool switch_curren
append_menu_item(add_color_change_menu, wxID_ANY, item_name, "",
[this, i](wxCommandEvent&) { add_code_as_tick(ColorChangeCode, i); }, "", menu,
[is_used_extruder]() { return is_used_extruder; }, GUI::wxGetApp().plater());
[]() { return true; }, GUI::wxGetApp().plater());
}
const wxString menu_name = switch_current_code ?
from_u8((boost::format(_utf8(L("Switch code to Color change (%1%) for:"))) % ColorChangeCode).str()) :
from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % ColorChangeCode).str());
wxMenuItem* add_color_change_menu_item = menu->AppendSubMenu(add_color_change_menu, menu_name, "");
add_color_change_menu_item->SetBitmap(create_scaled_bitmap(this, "colorchange_add_m"));
add_color_change_menu_item->SetBitmap(create_scaled_bitmap("colorchange_add_m"));
}
}
@ -1220,7 +1262,7 @@ std::array<int, 2> Control::get_active_extruders_for_tick(int tick) const
auto it = m_ticks.ticks.lower_bound(TickCode{tick});
if (it->tick == tick) // current tick exists
if (it != m_ticks.ticks.end() && it->tick == tick) // current tick exists
extruders[1] = it->extruder;
while (it != m_ticks.ticks.begin()) {
@ -1235,10 +1277,10 @@ std::array<int, 2> Control::get_active_extruders_for_tick(int tick) const
}
// Get used extruders for tick.
// Means all extruders(toools) will be used during printing from current tick to the end
std::set<int> Control::get_used_extruders_for_tick(int tick) const
// Means all extruders(tools) which will be used during printing from current tick to the end
std::set<int> TickCodeInfo::get_used_extruders_for_tick(int tick, int only_extruder, double print_z) const
{
if (m_mode == t_mode::MultiExtruder)
if (mode == t_mode::MultiExtruder)
{
// #ys_FIXME: get tool ordering from _correct_ place
const ToolOrdering& tool_ordering = GUI::wxGetApp().plater()->fff_print().get_tool_ordering();
@ -1248,7 +1290,7 @@ std::set<int> Control::get_used_extruders_for_tick(int tick) const
std::set<int> used_extruders;
auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), LayerTools(m_values[tick]));
auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), LayerTools(print_z));
for (; it_layer_tools != tool_ordering.end(); ++it_layer_tools)
{
const std::vector<unsigned>& extruders = it_layer_tools->extruders;
@ -1259,12 +1301,11 @@ std::set<int> Control::get_used_extruders_for_tick(int tick) const
return used_extruders;
}
const int default_initial_extruder = m_mode == t_mode::MultiAsSingle ? std::max(m_only_extruder, 1) : 1;
if (m_ticks.empty())
const int default_initial_extruder = mode == t_mode::MultiAsSingle ? std::max(only_extruder, 1) : 1;
if (ticks.empty())
return {default_initial_extruder};
std::set<int> used_extruders;
const std::set<TickCode>& ticks = m_ticks.ticks;
auto it_start = ticks.lower_bound(TickCode{tick});
auto it = it_start;
@ -1341,7 +1382,7 @@ void Control::OnRightUp(wxMouseEvent& event)
append_menu_item(&menu, wxID_ANY, it->gcode == ColorChangeCode ? _(L("Edit color")) :
it->gcode == PausePrintCode ? _(L("Edit pause print message")) :
_(L("Edit custom G-code")), "",
[this](wxCommandEvent&) { edit_tick(); }, "edit_uni", &menu);
[this](wxCommandEvent&) { edit_tick(); }, "edit_uni", &menu, []() {return true; }, this);
if (it->gcode == ColorChangeCode && m_mode == t_mode::MultiAsSingle)
append_change_extruder_menu_item(&menu, true);
@ -1350,7 +1391,7 @@ void Control::OnRightUp(wxMouseEvent& event)
it->gcode == ToolChangeCode ? _(L("Delete tool change")) :
it->gcode == PausePrintCode ? _(L("Delete pause print")) :
_(L("Delete custom G-code")), "",
[this](wxCommandEvent&) { delete_current_tick();}, "colorchange_del_f", &menu);
[this](wxCommandEvent&) { delete_current_tick();}, "colorchange_del_f", &menu, []() {return true; }, this);
GUI::wxGetApp().plater()->PopupMenu(&menu);
@ -1379,6 +1420,28 @@ static std::string get_new_color(const std::string& color)
return "";
}
// To avoid get an empty string from wxTextEntryDialog
// Let disable OK button, if TextCtrl is empty
static void upgrade_text_entry_dialog(wxTextEntryDialog* dlg)
{
// detect TextCtrl and OK button
wxTextCtrl* textctrl {nullptr};
wxWindowList& dlg_items = dlg->GetChildren();
for (auto item : dlg_items) {
textctrl = dynamic_cast<wxTextCtrl*>(item);
if (textctrl)
break;
}
if (!textctrl)
return;
wxButton* btn_OK = static_cast<wxButton*>(dlg->FindWindowById(wxID_OK));
btn_OK->Bind(wxEVT_UPDATE_UI, [textctrl](wxUpdateUIEvent& evt) {
evt.Enable(!textctrl->IsEmpty());
}, btn_OK->GetId());
}
static std::string get_custom_code(const std::string& code_in, double height)
{
wxString msg_text = from_u8(_utf8(L("Enter custom G-code used on current layer"))) + ":";
@ -1387,7 +1450,9 @@ static std::string get_custom_code(const std::string& code_in, double height)
// get custom gcode
wxTextEntryDialog dlg(nullptr, msg_text, msg_header, code_in,
wxTextEntryDialogStyle | wxTE_MULTILINE);
if (dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty())
upgrade_text_entry_dialog(&dlg);
if (dlg.ShowModal() != wxID_OK)
return "";
return dlg.GetValue().ToStdString();
@ -1401,6 +1466,8 @@ static std::string get_pause_print_msg(const std::string& msg_in, double height)
// get custom gcode
wxTextEntryDialog dlg(nullptr, msg_text, msg_header, from_u8(msg_in),
wxTextEntryDialogStyle);
upgrade_text_entry_dialog(&dlg);
if (dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty())
return "";
@ -1759,6 +1826,61 @@ bool TickCodeInfo::has_tick_with_code(const std::string& gcode)
return false;
}
ConflictType TickCodeInfo::is_conflict_tick(const TickCode& tick, t_mode out_mode, int only_extruder, double print_z)
{
if ((tick.gcode == ColorChangeCode && (
(mode == t_mode::SingleExtruder && out_mode == t_mode::MultiExtruder ) ||
(mode == t_mode::MultiExtruder && out_mode == t_mode::SingleExtruder) )) ||
(tick.gcode == ToolChangeCode &&
(mode == t_mode::MultiAsSingle && out_mode != t_mode::MultiAsSingle)) )
return ctModeConflict;
// check ColorChange tick
if (tick.gcode == ColorChangeCode)
{
// We should mark a tick as a "MeaninglessColorChange",
// if it has a ColorChange for unused extruder from current print to end of the print
std::set<int> used_extruders_for_tick = get_used_extruders_for_tick(tick.tick, only_extruder, print_z);
if (used_extruders_for_tick.find(tick.extruder) == used_extruders_for_tick.end())
return ctMeaninglessColorChange;
// We should mark a tick as a "Redundant",
// if it has a ColorChange for extruder that has not been used before
if (mode == t_mode::MultiAsSingle && tick.extruder != std::max<int>(only_extruder, 1) )
{
auto it = ticks.lower_bound( tick );
if (it == ticks.begin() && it->gcode == ToolChangeCode && tick.extruder == it->extruder)
return ctNone;
while (it != ticks.begin()) {
--it;
if (it->gcode == ToolChangeCode && tick.extruder == it->extruder)
return ctNone;
}
return ctRedundant;
}
}
// check ToolChange tick
if (mode == t_mode::MultiAsSingle && tick.gcode == ToolChangeCode)
{
// We should mark a tick as a "MeaninglessToolChange",
// if it has a ToolChange to the same extruder
auto it = ticks.find(tick);
if (it == ticks.begin())
return tick.extruder == std::max<int>(only_extruder, 1) ? ctMeaninglessToolChange : ctNone;
--it;
if (it->gcode == ToolChangeCode && tick.extruder == it->extruder)
return ctMeaninglessToolChange;
}
return ctNone;
}
} // DoubleSlider
} // Slic3r

View file

@ -39,6 +39,15 @@ enum IconFocus {
ifCog
};
enum ConflictType
{
ctNone,
ctModeConflict,
ctMeaninglessColorChange,
ctMeaninglessToolChange,
ctRedundant
};
using t_mode = CustomGCode::Mode;
struct TickCode
@ -73,7 +82,13 @@ public:
void switch_code(const std::string& code_from, const std::string& code_to);
bool switch_code_for_tick(std::set<TickCode>::iterator it, const std::string& code_to, const int extruder);
void erase_all_ticks_with_code(const std::string& gcode);
bool has_tick_with_code(const std::string& gcode);
bool has_tick_with_code(const std::string& gcode);
ConflictType is_conflict_tick(const TickCode& tick, t_mode out_mode, int only_extruder, double print_z);
// Get used extruders for tick.
// Means all extruders(tools) which will be used during printing from current tick to the end
std::set<int> get_used_extruders_for_tick(int tick, int only_extruder, double print_z) const;
void suppress_plus (bool suppress) { m_suppress_plus = suppress; }
void suppress_minus(bool suppress) { m_suppress_minus = suppress; }
@ -230,7 +245,7 @@ protected:
private:
bool is_point_in_rect(const wxPoint& pt, const wxRect& rect);
int is_point_near_tick(const wxPoint& pt);
int get_tick_near_point(const wxPoint& pt);
double get_scroll_step();
wxString get_label(const SelectedSlider& selection) const;
@ -251,10 +266,6 @@ private:
// Use those values to disable selection of active extruders
std::array<int, 2> get_active_extruders_for_tick(int tick) const;
// Get used extruders for tick.
// Means all extruders(toools) will be used during printing from current tick to the end
std::set<int> get_used_extruders_for_tick(int tick) const;
void post_ticks_changed_event(const std::string& gcode = "");
bool check_ticks_changed_event(const std::string& gcode);

View file

@ -1256,6 +1256,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event<float>);
wxDEFINE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent);
#if ENABLE_THUMBNAIL_GENERATOR
const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25;
@ -1710,6 +1711,13 @@ void GLCanvas3D::render()
}
const Size& cnv_size = get_canvas_size();
#if ENABLE_6DOF_CAMERA
// Probably due to different order of events on Linux/GTK2, when one switched from 3D scene
// to preview, this was called before canvas had its final size. It reported zero width
// and the viewport was set incorrectly, leading to tripping glAsserts further down
// the road (in apply_projection). That's why the minimum size is forced to 10.
m_camera.apply_viewport(0, 0, std::max(10u, (unsigned int)cnv_size.get_width()), std::max(10u, (unsigned int)cnv_size.get_height()));
#endif // ENABLE_6DOF_CAMERA
if (m_camera.requires_zoom_to_bed)
{
@ -2647,6 +2655,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE));
break;
case WXK_ESCAPE: { deselect_all(); break; }
case WXK_F5: { post_event(SimpleEvent(EVT_GLCANVAS_RELOAD_FROM_DISK)); break; }
case '0': { select_view("iso"); break; }
case '1': { select_view("top"); break; }
case '2': { select_view("bottom"); break; }
@ -3839,8 +3848,13 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool
#if ENABLE_6DOF_CAMERA
camera.set_scene_box(scene_bounding_box());
#endif // ENABLE_6DOF_CAMERA
#if ENABLE_6DOF_CAMERA
camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height);
camera.zoom_to_volumes(visible_volumes);
#else
camera.zoom_to_volumes(visible_volumes, thumbnail_data.width, thumbnail_data.height);
camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height);
#endif // ENABLE_6DOF_CAMERA
camera.apply_view_matrix();
double near_z = -1.0;
@ -4431,8 +4445,10 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h)
// ensures that this canvas is current
_set_current();
#if !ENABLE_6DOF_CAMERA
// updates camera
m_camera.apply_viewport(0, 0, w, h);
#endif // !ENABLE_6DOF_CAMERA
}
BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_bed_model) const
@ -4456,8 +4472,12 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_be
#if ENABLE_THUMBNAIL_GENERATOR
void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box, double margin_factor)
{
#if ENABLE_6DOF_CAMERA
m_camera.zoom_to_box(box, margin_factor);
#else
const Size& cnv_size = get_canvas_size();
m_camera.zoom_to_box(box, cnv_size.get_width(), cnv_size.get_height(), margin_factor);
#endif // ENABLE_6DOF_CAMERA
m_dirty = true;
}
#else

View file

@ -108,6 +108,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event<float>);
wxDECLARE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent);
class GLCanvas3D
{

View file

@ -10,6 +10,7 @@
#include <wx/glcanvas.h>
#include <wx/timer.h>
#include <wx/msgdlg.h>
#include <vector>
#include <string>

View file

@ -960,8 +960,11 @@ void GUI_App::load_current_presets()
this->plater()->set_printer_technology(printer_technology);
for (Tab *tab : tabs_list)
if (tab->supports_printer_technology(printer_technology)) {
if (tab->type() == Preset::TYPE_PRINTER)
if (tab->type() == Preset::TYPE_PRINTER) {
static_cast<TabPrinter*>(tab)->update_pages();
// Mark the plater to update print bed by tab->load_current_preset() from Plater::on_config_change().
this->plater()->force_print_bed_update();
}
tab->load_current_preset();
}
}

View file

@ -90,20 +90,20 @@ ObjectList::ObjectList(wxWindow* parent) :
// see note in PresetBundle::load_compatible_bitmaps()
// ptFFF
CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap(nullptr, "layers");
CATEGORY_ICON[L("Infill")] = create_scaled_bitmap(nullptr, "infill");
CATEGORY_ICON[L("Support material")] = create_scaled_bitmap(nullptr, "support");
CATEGORY_ICON[L("Speed")] = create_scaled_bitmap(nullptr, "time");
CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap(nullptr, "funnel");
CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap(nullptr, "funnel");
CATEGORY_ICON[L("Wipe options")] = create_scaled_bitmap(nullptr, "funnel");
// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap(nullptr, "skirt+brim");
// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap(nullptr, "time");
CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap(nullptr, "wrench");
CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap("layers");
CATEGORY_ICON[L("Infill")] = create_scaled_bitmap("infill");
CATEGORY_ICON[L("Support material")] = create_scaled_bitmap("support");
CATEGORY_ICON[L("Speed")] = create_scaled_bitmap("time");
CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap("funnel");
CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap("funnel");
CATEGORY_ICON[L("Wipe options")] = create_scaled_bitmap("funnel");
// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap("skirt+brim");
// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap("time");
CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap("wrench");
// ptSLA
CATEGORY_ICON[L("Supports")] = create_scaled_bitmap(nullptr, "support"/*"sla_supports"*/);
CATEGORY_ICON[L("Pad")] = create_scaled_bitmap(nullptr, "pad");
CATEGORY_ICON[L("Hollowing")] = create_scaled_bitmap(nullptr, "hollowing");
CATEGORY_ICON[L("Supports")] = create_scaled_bitmap("support"/*"sla_supports"*/);
CATEGORY_ICON[L("Pad")] = create_scaled_bitmap("pad");
CATEGORY_ICON[L("Hollowing")] = create_scaled_bitmap("hollowing");
}
// create control
@ -230,9 +230,9 @@ ObjectList::ObjectList(wxWindow* parent) :
// So the postponed EnsureVisible() call is planned for an item, which may not exist at the Idle processing time, if this wxEVT_SIZE
// event is succeeded by a delete of the currently active item. We are trying our luck by postponing the wxEVT_SIZE triggered EnsureVisible(),
// which seems to be working as of now.
this->CallAfter([this](){ this->EnsureVisible(this->GetCurrentItem()); });
this->CallAfter([this](){ ensure_current_item_visible(); });
#else
this->EnsureVisible(this->GetCurrentItem());
ensure_current_item_visible();
#endif
e.Skip();
}));
@ -265,7 +265,7 @@ void ObjectList::create_objects_ctrl()
// column ItemName(Icon+Text) of the view control:
// And Icon can be consisting of several bitmaps
AppendColumn(new wxDataViewColumn(_(L("Name")), new BitmapTextRenderer(),
AppendColumn(new wxDataViewColumn(_(L("Name")), new BitmapTextRenderer(this),
colName, 20*em, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE));
// column PrintableProperty (Icon) of the view control:
@ -559,10 +559,10 @@ void ObjectList::update_name_in_model(const wxDataViewItem& item) const
void ObjectList::init_icons()
{
m_bmp_solidmesh = ScalableBitmap(nullptr, ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::MODEL_PART) ].second);
m_bmp_modifiermesh = ScalableBitmap(nullptr, ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::PARAMETER_MODIFIER)].second);
m_bmp_support_enforcer = ScalableBitmap(nullptr, ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::SUPPORT_ENFORCER) ].second);
m_bmp_support_blocker = ScalableBitmap(nullptr, ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::SUPPORT_BLOCKER) ].second);
m_bmp_solidmesh = ScalableBitmap(this, ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::MODEL_PART) ].second);
m_bmp_modifiermesh = ScalableBitmap(this, ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::PARAMETER_MODIFIER)].second);
m_bmp_support_enforcer = ScalableBitmap(this, ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::SUPPORT_ENFORCER) ].second);
m_bmp_support_blocker = ScalableBitmap(this, ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::SUPPORT_BLOCKER) ].second);
m_bmp_vector.reserve(4); // bitmaps for different types of parts
m_bmp_vector.push_back(&m_bmp_solidmesh.bmp());
@ -575,12 +575,12 @@ void ObjectList::init_icons()
m_objects_model->SetVolumeBitmaps(m_bmp_vector);
// init icon for manifold warning
m_bmp_manifold_warning = ScalableBitmap(nullptr, "exclamation");
m_bmp_manifold_warning = ScalableBitmap(this, "exclamation");
// Set warning bitmap for the model
m_objects_model->SetWarningBitmap(&m_bmp_manifold_warning.bmp());
// init bitmap for "Add Settings" context menu
m_bmp_cog = ScalableBitmap(nullptr, "cog");
m_bmp_cog = ScalableBitmap(this, "cog");
}
void ObjectList::msw_rescale_icons()
@ -607,23 +607,20 @@ void ObjectList::msw_rescale_icons()
// Update CATEGORY_ICON according to new scale
{
// Note: `this` isn't passed to create_scaled_bitmap() here because of bugs in the widget,
// see note in PresetBundle::load_compatible_bitmaps()
// ptFFF
CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap(nullptr, "layers");
CATEGORY_ICON[L("Infill")] = create_scaled_bitmap(nullptr, "infill");
CATEGORY_ICON[L("Support material")] = create_scaled_bitmap(nullptr, "support");
CATEGORY_ICON[L("Speed")] = create_scaled_bitmap(nullptr, "time");
CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap(nullptr, "funnel");
CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap(nullptr, "funnel");
CATEGORY_ICON[L("Wipe options")] = create_scaled_bitmap(nullptr, "funnel");
// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap(nullptr, "skirt+brim");
// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap(nullptr, "time");
CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap(nullptr, "wrench");
CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap("layers");
CATEGORY_ICON[L("Infill")] = create_scaled_bitmap("infill");
CATEGORY_ICON[L("Support material")] = create_scaled_bitmap("support");
CATEGORY_ICON[L("Speed")] = create_scaled_bitmap("time");
CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap("funnel");
CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap("funnel");
CATEGORY_ICON[L("Wipe options")] = create_scaled_bitmap("funnel");
// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap("skirt+brim");
// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap("time");
CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap("wrench");
// ptSLA
CATEGORY_ICON[L("Supports")] = create_scaled_bitmap(nullptr, "support"/*"sla_supports"*/);
CATEGORY_ICON[L("Pad")] = create_scaled_bitmap(nullptr, "pad");
CATEGORY_ICON[L("Supports")] = create_scaled_bitmap("support"/*"sla_supports"*/);
CATEGORY_ICON[L("Pad")] = create_scaled_bitmap("pad");
}
}
@ -1003,14 +1000,13 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
const bool mult_sel = multiple_selection();
if ((mult_sel && !selected_instances_of_same_object()) ||
(!mult_sel && (GetSelection() != item)) ||
m_objects_model->GetParent(item) == wxDataViewItem(nullptr) ) {
(!mult_sel && (GetSelection() != item)) ) {
event.Veto();
return;
}
const ItemType& type = m_objects_model->GetItemType(item);
if (!(type & (itVolume | itInstance))) {
if (!(type & (itVolume | itObject | itInstance))) {
event.Veto();
return;
}
@ -1024,11 +1020,13 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
for (auto sel : sels )
sub_obj_idxs.insert(m_objects_model->GetInstanceIdByItem(sel));
}
else
else if (type & itObject)
m_dragged_data.init(m_objects_model->GetIdByItem(item), type);
else
m_dragged_data.init(m_objects_model->GetObjectIdByItem(item),
type&itVolume ? m_objects_model->GetVolumeIdByItem(item) :
type&itVolume ? m_objects_model->GetVolumeIdByItem(item) :
m_objects_model->GetInstanceIdByItem(item),
type);
type);
/* Under MSW or OSX, DnD moves an item to the place of another selected item
* But under GTK, DnD moves an item between another two items.
@ -1049,10 +1047,20 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
bool ObjectList::can_drop(const wxDataViewItem& item) const
{
return (m_dragged_data.type() == itInstance && !item.IsOk()) ||
(m_dragged_data.type() == itVolume && item.IsOk() &&
m_objects_model->GetItemType(item) == itVolume &&
m_dragged_data.obj_idx() == m_objects_model->GetObjectIdByItem(item));
// move instance(s) or object on "empty place" of ObjectList
if ( (m_dragged_data.type() & (itInstance | itObject)) && !item.IsOk() )
return true;
// type of moved item should be the same as a "destination" item
if (!item.IsOk() || !(m_dragged_data.type() & (itVolume|itObject)) ||
m_objects_model->GetItemType(item) != m_dragged_data.type() )
return false;
// move volumes inside one object only
if (m_dragged_data.type() & itVolume)
return m_dragged_data.obj_idx() == m_objects_model->GetObjectIdByItem(item);
return true;
}
void ObjectList::OnDropPossible(wxDataViewEvent &event)
@ -1082,9 +1090,6 @@ void ObjectList::OnDrop(wxDataViewEvent &event)
return;
}
const int from_volume_id = m_dragged_data.sub_obj_idx();
int to_volume_id = m_objects_model->GetVolumeIdByItem(item);
// It looks like a fixed in current version of the wxWidgets
// #ifdef __WXGTK__
// /* Under GTK, DnD moves an item between another two items.
@ -1096,14 +1101,33 @@ void ObjectList::OnDrop(wxDataViewEvent &event)
take_snapshot(_((m_dragged_data.type() == itVolume) ? L("Volumes in Object reordered") : L("Object reordered")));
auto& volumes = (*m_objects)[m_dragged_data.obj_idx()]->volumes;
auto delta = to_volume_id < from_volume_id ? -1 : 1;
int cnt = 0;
for (int id = from_volume_id; cnt < abs(from_volume_id - to_volume_id); id += delta, cnt++)
std::swap(volumes[id], volumes[id + delta]);
if (m_dragged_data.type() & itVolume)
{
int from_volume_id = m_dragged_data.sub_obj_idx();
int to_volume_id = m_objects_model->GetVolumeIdByItem(item);
int delta = to_volume_id < from_volume_id ? -1 : 1;
select_item(m_objects_model->ReorganizeChildren(from_volume_id, to_volume_id,
m_objects_model->GetParent(item)));
auto& volumes = (*m_objects)[m_dragged_data.obj_idx()]->volumes;
int cnt = 0;
for (int id = from_volume_id; cnt < abs(from_volume_id - to_volume_id); id += delta, cnt++)
std::swap(volumes[id], volumes[id + delta]);
select_item(m_objects_model->ReorganizeChildren(from_volume_id, to_volume_id, m_objects_model->GetParent(item)));
}
else if (m_dragged_data.type() & itObject)
{
int from_obj_id = m_dragged_data.obj_idx();
int to_obj_id = item.IsOk() ? m_objects_model->GetIdByItem(item) : ((int)m_objects->size()-1);
int delta = to_obj_id < from_obj_id ? -1 : 1;
int cnt = 0;
for (int id = from_obj_id; cnt < abs(from_obj_id - to_obj_id); id += delta, cnt++)
std::swap((*m_objects)[id], (*m_objects)[id + delta]);
select_item(m_objects_model->ReorganizeObjects(from_obj_id, to_obj_id));
}
changed_object(m_dragged_data.obj_idx());
@ -1741,7 +1765,8 @@ void ObjectList::create_instance_popupmenu(wxMenu*menu)
void ObjectList::create_default_popupmenu(wxMenu*menu)
{
wxMenu* sub_menu = append_submenu_add_generic(menu, ModelVolumeType::INVALID);
append_submenu(menu, sub_menu, wxID_ANY, _(L("Add Shape")), "", "add_part");
append_submenu(menu, sub_menu, wxID_ANY, _(L("Add Shape")), "", "add_part",
[](){return true;}, this);
}
wxMenu* ObjectList::create_settings_popupmenu(wxMenu *parent_menu)
@ -3162,7 +3187,7 @@ void ObjectList::update_selections()
select_items(sels);
// Scroll selected Item in the middle of an object list
this->EnsureVisible(this->GetCurrentItem());
ensure_current_item_visible();
}
void ObjectList::update_selections_on_canvas()

View file

@ -3,6 +3,7 @@
#include <map>
#include <vector>
#include <set>
#include <wx/bitmap.h>
#include <wx/dataview.h>
@ -10,6 +11,7 @@
#include "Event.hpp"
#include "wxExtensions.hpp"
#include "ObjectDataViewModel.hpp"
class wxBoxSizer;
class wxBitmapComboBox;
@ -171,6 +173,12 @@ private:
SettingsBundle m_freq_settings_sla;
#endif
inline void ensure_current_item_visible()
{
if (const auto &item = this->GetCurrentItem())
this->EnsureVisible(item);
}
public:
ObjectList(wxWindow* parent);
~ObjectList();

View file

@ -9,6 +9,8 @@
#include <wx/stattext.h>
#include <wx/sizer.h>
#include <algorithm>
#include "slic3r/GUI/GUI_App.hpp"
@ -189,7 +191,7 @@ void GLGizmoCut::update_max_z(const Selection& selection) const
void GLGizmoCut::set_cut_z(double cut_z) const
{
// Clamp the plane to the object's bounding box
m_cut_z = std::max(0.0, std::min(m_max_z, cut_z));
m_cut_z = std::clamp(cut_z, 0.0, m_max_z);
}
void GLGizmoCut::perform_cut(const Selection& selection)

View file

@ -25,6 +25,9 @@ class GLGizmoCut : public GLGizmoBase
public:
GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
double get_cut_z() const { return m_cut_z; }
void set_cut_z(double cut_z) const;
protected:
virtual bool on_init();
virtual void on_load(cereal::BinaryInputArchive& ar) { ar(m_cut_z, m_keep_upper, m_keep_lower, m_rotate_lower); }
@ -40,7 +43,6 @@ protected:
private:
void update_max_z(const Selection& selection) const;
void set_cut_z(double cut_z) const;
void perform_cut(const Selection& selection);
double calc_projection(const Linef3& mouse_ray) const;
};

View file

@ -500,7 +500,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
processed = true;
}
else if (evt.Dragging() && (m_parent.get_move_volume_id() != -1) && (m_current == SlaSupports || m_current == Hollow))
// don't allow dragging objects with the Sla gizmo on
// don't allow dragging objects with the Sla gizmo on
processed = true;
else if (evt.Dragging() && (m_current == SlaSupports || m_current == Hollow) && gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown()))
{
@ -557,12 +557,9 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
else if (evt.LeftUp() && is_dragging())
{
switch (m_current) {
case Move : m_parent.do_move(L("Gizmo-Move"));
break;
case Scale : m_parent.do_scale(L("Gizmo-Scale"));
break;
case Rotate : m_parent.do_rotate(L("Gizmo-Rotate"));
break;
case Move : m_parent.do_move(L("Gizmo-Move")); break;
case Scale : m_parent.do_scale(L("Gizmo-Scale")); break;
case Rotate : m_parent.do_rotate(L("Gizmo-Rotate")); break;
default : break;
}
@ -779,6 +776,64 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt)
processed = true;
}
}
else if (m_current == Move)
{
auto do_move = [this, &processed](const Vec3d& displacement) {
Selection& selection = m_parent.get_selection();
selection.start_dragging();
selection.translate(displacement);
wxGetApp().obj_manipul()->set_dirty();
m_parent.do_move(L("Gizmo-Move"));
m_parent.set_as_dirty();
processed = true;
};
switch (keyCode)
{
case WXK_NUMPAD_LEFT: case WXK_LEFT: { do_move(-Vec3d::UnitX()); break; }
case WXK_NUMPAD_RIGHT: case WXK_RIGHT: { do_move(Vec3d::UnitX()); break; }
case WXK_NUMPAD_UP: case WXK_UP: { do_move(Vec3d::UnitY()); break; }
case WXK_NUMPAD_DOWN: case WXK_DOWN: { do_move(-Vec3d::UnitY()); break; }
default: { break; }
}
}
else if (m_current == Rotate)
{
auto do_rotate = [this, &processed](const Vec3d& rotation) {
Selection& selection = m_parent.get_selection();
selection.start_dragging();
selection.rotate(rotation, TransformationType(TransformationType::World_Relative_Joint));
wxGetApp().obj_manipul()->set_dirty();
m_parent.do_rotate(L("Gizmo-Rotate"));
m_parent.set_as_dirty();
processed = true;
};
switch (keyCode)
{
case WXK_NUMPAD_LEFT: case WXK_LEFT: { do_rotate(Vec3d(0.0, 0.0, 0.5 * M_PI)); break; }
case WXK_NUMPAD_RIGHT: case WXK_RIGHT: { do_rotate(-Vec3d(0.0, 0.0, 0.5 * M_PI)); break; }
case WXK_NUMPAD_UP: case WXK_UP: { do_rotate(Vec3d(0.0, 0.0, 0.25 * M_PI)); break; }
case WXK_NUMPAD_DOWN: case WXK_DOWN: { do_rotate(-Vec3d(0.0, 0.0, 0.25 * M_PI)); break; }
default: { break; }
}
}
else if (m_current == Cut)
{
auto do_move = [this, &processed](double delta_z) {
GLGizmoCut* cut = dynamic_cast<GLGizmoCut*>(get_current());
cut->set_cut_z(delta_z + cut->get_cut_z());
m_parent.set_as_dirty();
processed = true;
};
switch (keyCode)
{
case WXK_NUMPAD_UP: case WXK_UP: { do_move(1.0); break; }
case WXK_NUMPAD_DOWN: case WXK_DOWN: { do_move(-1.0); break; }
default: { break; }
}
}
// if (processed)
// m_parent.set_cursor(GLCanvas3D::Standard);

View file

@ -68,7 +68,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
/* Load default preset bitmaps before a tabpanel initialization,
* but after filling of an em_unit value
*/
wxGetApp().preset_bundle->load_default_preset_bitmaps(this);
wxGetApp().preset_bundle->load_default_preset_bitmaps();
// initialize tabpanel and menubar
init_tabpanel();
@ -345,7 +345,7 @@ void MainFrame::on_dpi_changed(const wxRect &suggested_rect)
/* Load default preset bitmaps before a tabpanel initialization,
* but after filling of an em_unit value
*/
wxGetApp().preset_bundle->load_default_preset_bitmaps(this);
wxGetApp().preset_bundle->load_default_preset_bitmaps();
// update Plater
wxGetApp().plater()->msw_rescale();
@ -578,6 +578,11 @@ void MainFrame::init_menubar()
append_menu_item(editMenu, wxID_ANY, _(L("&Paste")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "V",
_(L("Paste clipboard")), [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); },
"paste_menu", nullptr, [this](){return m_plater->can_paste_from_clipboard(); }, this);
editMenu->AppendSeparator();
append_menu_item(editMenu, wxID_ANY, _(L("Re&load from disk")) + sep + "F5",
_(L("Reload the plater from disk")), [this](wxCommandEvent&) { m_plater->reload_all_from_disk(); },
"", nullptr, [this]() {return !m_plater->model().objects.empty(); }, this);
}
// Window menu
@ -728,7 +733,7 @@ void MainFrame::update_menubar()
m_changeable_menu_items[miSend] ->SetItemLabel((is_fff ? _(L("S&end G-code")) : _(L("S&end to print"))) + dots + "\tCtrl+Shift+G");
m_changeable_menu_items[miMaterialTab] ->SetItemLabel((is_fff ? _(L("&Filament Settings Tab")) : _(L("Mate&rial Settings Tab"))) + "\tCtrl+3");
m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(this, is_fff ? "spool": "resin"));
m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(is_fff ? "spool": "resin"));
}
// To perform the "Quck Slice", "Quick Slice and Save As", "Repeat last Quick Slice" and "Slice to SVG".

View file

@ -53,7 +53,7 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he
rightsizer->Add(btn_sizer, 0, wxALIGN_RIGHT);
if (! bitmap.IsOk()) {
bitmap = create_scaled_bitmap(this, "PrusaSlicer_192px.png", 192);
bitmap = create_scaled_bitmap("PrusaSlicer_192px.png", this, 192);
}
logo = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap);
@ -99,7 +99,7 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
btn_ok->SetFocus();
btn_sizer->Add(btn_ok, 0, wxRIGHT, HORIZ_SPACING);
logo->SetBitmap(create_scaled_bitmap(this, "PrusaSlicer_192px_grayscale.png", 192));
logo->SetBitmap(create_scaled_bitmap("PrusaSlicer_192px_grayscale.png", this, 192));
SetMaxSize(wxSize(-1, CONTENT_MAX_HEIGHT*wxGetApp().em_unit()));
Fit();

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,516 @@
#ifndef slic3r_GUI_ObjectDataViewModel_hpp_
#define slic3r_GUI_ObjectDataViewModel_hpp_
#include <wx/dataview.h>
#include <vector>
namespace Slic3r {
enum class ModelVolumeType : int;
namespace GUI {
typedef double coordf_t;
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
// ----------------------------------------------------------------------------
// DataViewBitmapText: helper class used by BitmapTextRenderer
// ----------------------------------------------------------------------------
class DataViewBitmapText : public wxObject
{
public:
DataViewBitmapText( const wxString &text = wxEmptyString,
const wxBitmap& bmp = wxNullBitmap) :
m_text(text),
m_bmp(bmp)
{ }
DataViewBitmapText(const DataViewBitmapText &other)
: wxObject(),
m_text(other.m_text),
m_bmp(other.m_bmp)
{ }
void SetText(const wxString &text) { m_text = text; }
wxString GetText() const { return m_text; }
void SetBitmap(const wxBitmap &bmp) { m_bmp = bmp; }
const wxBitmap &GetBitmap() const { return m_bmp; }
bool IsSameAs(const DataViewBitmapText& other) const {
return m_text == other.m_text && m_bmp.IsSameAs(other.m_bmp);
}
bool operator==(const DataViewBitmapText& other) const {
return IsSameAs(other);
}
bool operator!=(const DataViewBitmapText& other) const {
return !IsSameAs(other);
}
private:
wxString m_text;
wxBitmap m_bmp;
wxDECLARE_DYNAMIC_CLASS(DataViewBitmapText);
};
DECLARE_VARIANT_OBJECT(DataViewBitmapText)
// ----------------------------------------------------------------------------
// BitmapTextRenderer
// ----------------------------------------------------------------------------
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
class BitmapTextRenderer : public wxDataViewRenderer
#else
class BitmapTextRenderer : public wxDataViewCustomRenderer
#endif //ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
{
public:
BitmapTextRenderer(wxWindow* parent,
wxDataViewCellMode mode =
#ifdef __WXOSX__
wxDATAVIEW_CELL_INERT
#else
wxDATAVIEW_CELL_EDITABLE
#endif
, int align = wxDVR_DEFAULT_ALIGNMENT
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
);
#else
) :
wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align),
m_parent(parent)
{}
#endif //ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
bool SetValue(const wxVariant& value);
bool GetValue(wxVariant& value) const;
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING && wxUSE_ACCESSIBILITY
virtual wxString GetAccessibleDescription() const override;
#endif // wxUSE_ACCESSIBILITY && ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
virtual bool Render(wxRect cell, wxDC* dc, int state) override;
virtual wxSize GetSize() const override;
bool HasEditorCtrl() const override
{
#ifdef __WXOSX__
return false;
#else
return true;
#endif
}
wxWindow* CreateEditorCtrl(wxWindow* parent,
wxRect labelRect,
const wxVariant& value) override;
bool GetValueFromEditorCtrl(wxWindow* ctrl,
wxVariant& value) override;
bool WasCanceled() const { return m_was_unusable_symbol; }
private:
DataViewBitmapText m_value;
bool m_was_unusable_symbol{ false };
wxWindow* m_parent{ nullptr };
};
// ----------------------------------------------------------------------------
// BitmapChoiceRenderer
// ----------------------------------------------------------------------------
class BitmapChoiceRenderer : public wxDataViewCustomRenderer
{
public:
BitmapChoiceRenderer(wxDataViewCellMode mode =
#ifdef __WXOSX__
wxDATAVIEW_CELL_INERT
#else
wxDATAVIEW_CELL_EDITABLE
#endif
, int align = wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL
) : wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align) {}
bool SetValue(const wxVariant& value);
bool GetValue(wxVariant& value) const;
virtual bool Render(wxRect cell, wxDC* dc, int state) override;
virtual wxSize GetSize() const override;
bool HasEditorCtrl() const override { return true; }
wxWindow* CreateEditorCtrl(wxWindow* parent,
wxRect labelRect,
const wxVariant& value) override;
bool GetValueFromEditorCtrl(wxWindow* ctrl,
wxVariant& value) override;
private:
DataViewBitmapText m_value;
};
// ----------------------------------------------------------------------------
// ObjectDataViewModelNode: a node inside ObjectDataViewModel
// ----------------------------------------------------------------------------
enum ItemType {
itUndef = 0,
itObject = 1,
itVolume = 2,
itInstanceRoot = 4,
itInstance = 8,
itSettings = 16,
itLayerRoot = 32,
itLayer = 64,
};
enum ColumnNumber
{
colName = 0, // item name
colPrint , // printable property
colExtruder , // extruder selection
colEditing , // item editing
};
enum PrintIndicator
{
piUndef = 0, // no print indicator
piPrintable , // printable
piUnprintable , // unprintable
};
class ObjectDataViewModelNode;
WX_DEFINE_ARRAY_PTR(ObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray);
class ObjectDataViewModelNode
{
ObjectDataViewModelNode* m_parent;
MyObjectTreeModelNodePtrArray m_children;
wxBitmap m_empty_bmp;
size_t m_volumes_cnt = 0;
std::vector< std::string > m_opt_categories;
t_layer_height_range m_layer_range = { 0.0f, 0.0f };
wxString m_name;
wxBitmap& m_bmp = m_empty_bmp;
ItemType m_type;
int m_idx = -1;
bool m_container = false;
wxString m_extruder = "default";
wxBitmap m_extruder_bmp;
wxBitmap m_action_icon;
PrintIndicator m_printable {piUndef};
wxBitmap m_printable_icon;
std::string m_action_icon_name = "";
ModelVolumeType m_volume_type;
public:
ObjectDataViewModelNode(const wxString& name,
const wxString& extruder):
m_parent(NULL),
m_name(name),
m_type(itObject),
m_extruder(extruder)
{
set_action_and_extruder_icons();
init_container();
}
ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
const wxString& sub_obj_name,
const wxBitmap& bmp,
const wxString& extruder,
const int idx = -1 ) :
m_parent (parent),
m_name (sub_obj_name),
m_type (itVolume),
m_idx (idx),
m_extruder (extruder)
{
m_bmp = bmp;
set_action_and_extruder_icons();
init_container();
}
ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
const t_layer_height_range& layer_range,
const int idx = -1,
const wxString& extruder = wxEmptyString );
ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type);
~ObjectDataViewModelNode()
{
// free all our children nodes
size_t count = m_children.GetCount();
for (size_t i = 0; i < count; i++)
{
ObjectDataViewModelNode *child = m_children[i];
delete child;
}
#ifndef NDEBUG
// Indicate that the object was deleted.
m_idx = -2;
#endif /* NDEBUG */
}
void init_container();
bool IsContainer() const
{
return m_container;
}
ObjectDataViewModelNode* GetParent()
{
assert(m_parent == nullptr || m_parent->valid());
return m_parent;
}
MyObjectTreeModelNodePtrArray& GetChildren()
{
return m_children;
}
ObjectDataViewModelNode* GetNthChild(unsigned int n)
{
return m_children.Item(n);
}
void Insert(ObjectDataViewModelNode* child, unsigned int n)
{
if (!m_container)
m_container = true;
m_children.Insert(child, n);
}
void Append(ObjectDataViewModelNode* child)
{
if (!m_container)
m_container = true;
m_children.Add(child);
}
void RemoveAllChildren()
{
if (GetChildCount() == 0)
return;
for (int id = int(GetChildCount()) - 1; id >= 0; --id)
{
if (m_children.Item(id)->GetChildCount() > 0)
m_children[id]->RemoveAllChildren();
auto node = m_children[id];
m_children.RemoveAt(id);
delete node;
}
}
size_t GetChildCount() const
{
return m_children.GetCount();
}
bool SetValue(const wxVariant &variant, unsigned int col);
void SetBitmap(const wxBitmap &icon) { m_bmp = icon; }
const wxBitmap& GetBitmap() const { return m_bmp; }
const wxString& GetName() const { return m_name; }
ItemType GetType() const { return m_type; }
void SetIdx(const int& idx);
int GetIdx() const { return m_idx; }
t_layer_height_range GetLayerRange() const { return m_layer_range; }
PrintIndicator IsPrintable() const { return m_printable; }
// use this function only for childrens
void AssignAllVal(ObjectDataViewModelNode& from_node)
{
// ! Don't overwrite other values because of equality of this values for all children --
m_name = from_node.m_name;
m_bmp = from_node.m_bmp;
m_idx = from_node.m_idx;
m_extruder = from_node.m_extruder;
m_type = from_node.m_type;
}
bool SwapChildrens(int frst_id, int scnd_id) {
if (GetChildCount() < 2 ||
frst_id < 0 || (size_t)frst_id >= GetChildCount() ||
scnd_id < 0 || (size_t)scnd_id >= GetChildCount())
return false;
ObjectDataViewModelNode new_scnd = *GetNthChild(frst_id);
ObjectDataViewModelNode new_frst = *GetNthChild(scnd_id);
new_scnd.m_idx = m_children.Item(scnd_id)->m_idx;
new_frst.m_idx = m_children.Item(frst_id)->m_idx;
m_children.Item(frst_id)->AssignAllVal(new_frst);
m_children.Item(scnd_id)->AssignAllVal(new_scnd);
return true;
}
// Set action icons for node
void set_action_and_extruder_icons();
// Set printable icon for node
void set_printable_icon(PrintIndicator printable);
void update_settings_digest_bitmaps();
bool update_settings_digest(const std::vector<std::string>& categories);
int volume_type() const { return int(m_volume_type); }
void msw_rescale();
#ifndef NDEBUG
bool valid();
#endif /* NDEBUG */
bool invalid() const { return m_idx < -1; }
private:
friend class ObjectDataViewModel;
};
// ----------------------------------------------------------------------------
// ObjectDataViewModel
// ----------------------------------------------------------------------------
// custom message the model sends to associated control to notify a last volume deleted from the object:
wxDECLARE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent);
class ObjectDataViewModel :public wxDataViewModel
{
std::vector<ObjectDataViewModelNode*> m_objects;
std::vector<wxBitmap*> m_volume_bmps;
wxBitmap* m_warning_bmp { nullptr };
wxDataViewCtrl* m_ctrl { nullptr };
public:
ObjectDataViewModel();
~ObjectDataViewModel();
wxDataViewItem Add( const wxString &name,
const int extruder,
const bool has_errors = false);
wxDataViewItem AddVolumeChild( const wxDataViewItem &parent_item,
const wxString &name,
const Slic3r::ModelVolumeType volume_type,
const bool has_errors = false,
const int extruder = 0,
const bool create_frst_child = true);
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, const std::vector<bool>& print_indicator);
wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item,
const t_layer_height_range& layer_range,
const int extruder = 0,
const int index = -1);
wxDataViewItem Delete(const wxDataViewItem &item);
wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
void DeleteAll();
void DeleteChildren(wxDataViewItem& parent);
void DeleteVolumeChildren(wxDataViewItem& parent);
void DeleteSettings(const wxDataViewItem& parent);
wxDataViewItem GetItemById(int obj_idx);
wxDataViewItem GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type);
wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx);
wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx);
wxDataViewItem GetItemByLayerId(int obj_idx, int layer_idx);
wxDataViewItem GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
int GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
int GetIdByItem(const wxDataViewItem& item) const;
int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
int GetObjectIdByItem(const wxDataViewItem& item) const;
int GetVolumeIdByItem(const wxDataViewItem& item) const;
int GetInstanceIdByItem(const wxDataViewItem& item) const;
int GetLayerIdByItem(const wxDataViewItem& item) const;
void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx);
int GetRowByItem(const wxDataViewItem& item) const;
bool IsEmpty() { return m_objects.empty(); }
bool InvalidItem(const wxDataViewItem& item);
// helper method for wxLog
wxString GetName(const wxDataViewItem &item) const;
wxBitmap& GetBitmap(const wxDataViewItem &item) const;
wxString GetExtruder(const wxDataViewItem &item) const;
int GetExtruderNumber(const wxDataViewItem &item) const;
// helper methods to change the model
virtual unsigned int GetColumnCount() const override { return 3;}
virtual wxString GetColumnType(unsigned int col) const override{ return wxT("string"); }
virtual void GetValue( wxVariant &variant,
const wxDataViewItem &item,
unsigned int col) const override;
virtual bool SetValue( const wxVariant &variant,
const wxDataViewItem &item,
unsigned int col) override;
bool SetValue( const wxVariant &variant,
const int item_idx,
unsigned int col);
void SetExtruder(const wxString& extruder, wxDataViewItem item);
// For parent move child from cur_volume_id place to new_volume_id
// Remaining items will moved up/down accordingly
wxDataViewItem ReorganizeChildren( const int cur_volume_id,
const int new_volume_id,
const wxDataViewItem &parent);
wxDataViewItem ReorganizeObjects( int current_id, int new_id);
virtual bool IsEnabled(const wxDataViewItem &item, unsigned int col) const override;
virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override;
// get object item
wxDataViewItem GetTopParent(const wxDataViewItem &item) const;
virtual bool IsContainer(const wxDataViewItem &item) const override;
virtual unsigned int GetChildren(const wxDataViewItem &parent,
wxDataViewItemArray &array) const override;
void GetAllChildren(const wxDataViewItem &parent,wxDataViewItemArray &array) const;
// Is the container just a header or an item with all columns
// In our case it is an item with all columns
virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; }
ItemType GetItemType(const wxDataViewItem &item) const ;
wxDataViewItem GetItemByType( const wxDataViewItem &parent_item,
ItemType type) const;
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const;
bool IsSettingsItem(const wxDataViewItem &item) const;
void UpdateSettingsDigest( const wxDataViewItem &item,
const std::vector<std::string>& categories);
bool IsPrintable(const wxDataViewItem &item) const;
void UpdateObjectPrintable(wxDataViewItem parent_item);
void UpdateInstancesPrintable(wxDataViewItem parent_item);
void SetVolumeBitmaps(const std::vector<wxBitmap*>& volume_bmps) { m_volume_bmps = volume_bmps; }
void SetWarningBitmap(wxBitmap* bitmap) { m_warning_bmp = bitmap; }
void SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type);
wxDataViewItem SetPrintableState( PrintIndicator printable, int obj_idx,
int subobj_idx = -1,
ItemType subobj_type = itInstance);
wxDataViewItem SetObjectPrintableState(PrintIndicator printable, wxDataViewItem obj_item);
void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; }
// Rescale bitmaps for existing Items
void Rescale();
wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type,
const bool is_marked = false);
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const;
bool UpdateColumValues(unsigned col);
void UpdateExtruderBitmap(wxDataViewItem item);
private:
wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type);
wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item);
};
}
}
#endif // slic3r_GUI_ObjectDataViewModel_hpp_

View file

@ -169,7 +169,7 @@ ObjectInfo::ObjectInfo(wxWindow *parent) :
info_manifold_text->SetFont(wxGetApp().small_font());
info_manifold = new wxStaticText(parent, wxID_ANY, "");
info_manifold->SetFont(wxGetApp().small_font());
manifold_warning_icon = new wxStaticBitmap(parent, wxID_ANY, create_scaled_bitmap(parent, "exclamation"));
manifold_warning_icon = new wxStaticBitmap(parent, wxID_ANY, create_scaled_bitmap("exclamation"));
auto *sizer_manifold = new wxBoxSizer(wxHORIZONTAL);
sizer_manifold->Add(info_manifold_text, 0);
sizer_manifold->Add(manifold_warning_icon, 0, wxLEFT, 2);
@ -188,7 +188,7 @@ void ObjectInfo::show_sizer(bool show)
void ObjectInfo::msw_rescale()
{
manifold_warning_icon->SetBitmap(create_scaled_bitmap(nullptr, "exclamation"));
manifold_warning_icon->SetBitmap(create_scaled_bitmap("exclamation"));
}
enum SlicedInfoIdx
@ -258,7 +258,7 @@ void SlicedInfo::SetTextAndShow(SlicedInfoIdx idx, const wxString& text, const w
}
PresetComboBox::PresetComboBox(wxWindow *parent, Preset::Type preset_type) :
wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * wxGetApp().em_unit(), -1), 0, nullptr, wxCB_READONLY),
PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)),
preset_type(preset_type),
last_selected(wxNOT_FOUND),
m_em_unit(wxGetApp().em_unit())
@ -1875,6 +1875,7 @@ struct Plater::priv
}
void export_gcode(fs::path output_path, PrintHostJob upload_job);
void reload_from_disk();
void reload_all_from_disk();
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
void set_current_panel(wxPanel* panel);
@ -2075,6 +2076,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
view3D_canvas->Bind(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, [this](SimpleEvent&) { this->view3D->get_canvas3d()->reset_layer_height_profile(); });
view3D_canvas->Bind(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, [this](Event<float>& evt) { this->view3D->get_canvas3d()->adaptive_layer_height_profile(evt.data); });
view3D_canvas->Bind(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, [this](HeightProfileSmoothEvent& evt) { this->view3D->get_canvas3d()->smooth_layer_height_profile(evt.data); });
view3D_canvas->Bind(EVT_GLCANVAS_RELOAD_FROM_DISK, [this](SimpleEvent&) { if (!this->model.objects.empty()) this->reload_all_from_disk(); });
// 3DScene/Toolbar:
view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this);
@ -3447,6 +3449,24 @@ void Plater::priv::reload_from_disk()
}
}
void Plater::priv::reload_all_from_disk()
{
Plater::TakeSnapshot snapshot(q, _(L("Reload all from disk")));
Plater::SuppressSnapshots suppress(q);
Selection& selection = get_selection();
Selection::IndicesList curr_idxs = selection.get_volume_idxs();
// reload from disk uses selection
select_all();
reload_from_disk();
// restore previous selection
selection.clear();
for (unsigned int idx : curr_idxs)
{
selection.add(idx, false);
}
}
void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/)
{
if (obj_idx < 0)
@ -5034,6 +5054,11 @@ void Plater::reload_from_disk()
p->reload_from_disk();
}
void Plater::reload_all_from_disk()
{
p->reload_all_from_disk();
}
bool Plater::has_toolpaths_to_export() const
{
return p->preview->get_canvas3d()->has_toolpaths_to_export();
@ -5376,6 +5401,13 @@ void Plater::force_filament_colors_update()
this->p->schedule_background_process();
}
void Plater::force_print_bed_update()
{
// Fill in the printer model key with something which cannot possibly be valid, so that Plater::on_config_change() will update the print bed
// once a new Printer profile config is loaded.
p->config->opt_string("printer_model", true) = "\x01\x00\x01";
}
void Plater::on_activate()
{
#ifdef __linux__
@ -5392,11 +5424,6 @@ void Plater::on_activate()
this->p->show_delayed_error_message();
}
const DynamicPrintConfig* Plater::get_plater_config() const
{
return p->config;
}
// Get vector of extruder colors considering filament color, if extruder color is undefined.
std::vector<std::string> Plater::get_extruder_colors_from_plater_config() const
{

View file

@ -12,6 +12,7 @@
#include "3DScene.hpp"
#include "GLTexture.hpp"
#include "wxExtensions.hpp"
class wxButton;
class ScalableButton;
@ -49,7 +50,7 @@ using t_optgroups = std::vector <std::shared_ptr<ConfigOptionsGroup>>;
class Plater;
enum class ActionButtonType : int;
class PresetComboBox : public wxBitmapComboBox
class PresetComboBox : public PresetBitmapComboBox
{
public:
PresetComboBox(wxWindow *parent, Preset::Type preset_type);
@ -193,6 +194,7 @@ public:
void export_amf();
void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path());
void reload_from_disk();
void reload_all_from_disk();
bool has_toolpaths_to_export() const;
void export_toolpaths_to_obj() const;
void hollow();
@ -227,9 +229,9 @@ public:
void on_extruders_change(size_t extruders_count);
void on_config_change(const DynamicPrintConfig &config);
void force_filament_colors_update();
void force_print_bed_update();
// On activating the parent window.
void on_activate();
const DynamicPrintConfig* get_plater_config() const;
std::vector<std::string> get_extruder_colors_from_plater_config() const;
std::vector<std::string> get_colors_for_color_print() const;

View file

@ -550,7 +550,6 @@ const std::vector<std::string>& Preset::sla_printer_options()
s_opts = {
"printer_technology",
"bed_shape", "bed_custom_texture", "bed_custom_model", "max_print_height",
"bed_shape", "max_print_height",
"display_width", "display_height", "display_pixels_x", "display_pixels_y",
"display_mirror_x", "display_mirror_y",
"display_orientation",
@ -874,18 +873,14 @@ bool PresetCollection::delete_preset(const std::string& name)
return true;
}
void PresetCollection::load_bitmap_default(wxWindow *window, const std::string &file_name)
void PresetCollection::load_bitmap_default(const std::string &file_name)
{
// XXX: See note in PresetBundle::load_compatible_bitmaps()
(void)window;
*m_bitmap_main_frame = create_scaled_bitmap(nullptr, file_name);
*m_bitmap_main_frame = create_scaled_bitmap(file_name);
}
void PresetCollection::load_bitmap_add(wxWindow *window, const std::string &file_name)
void PresetCollection::load_bitmap_add(const std::string &file_name)
{
// XXX: See note in PresetBundle::load_compatible_bitmaps()
(void)window;
*m_bitmap_add = create_scaled_bitmap(nullptr, file_name);
*m_bitmap_add = create_scaled_bitmap(file_name);
}
const Preset* PresetCollection::get_selected_preset_parent() const

View file

@ -313,10 +313,10 @@ public:
bool delete_preset(const std::string& name);
// Load default bitmap to be placed at the wxBitmapComboBox of a MainFrame.
void load_bitmap_default(wxWindow *window, const std::string &file_name);
void load_bitmap_default(const std::string &file_name);
// Load "add new printer" bitmap to be placed at the wxBitmapComboBox of a MainFrame.
void load_bitmap_add(wxWindow *window, const std::string &file_name);
void load_bitmap_add(const std::string &file_name);
// Compatible & incompatible marks, to be placed at the wxBitmapComboBox items.
void set_bitmap_compatible (const wxBitmap *bmp) { m_bitmap_compatible = bmp; }

View file

@ -480,19 +480,12 @@ void PresetBundle::export_selections(AppConfig &config)
config.set("presets", "printer", printers.get_selected_preset_name());
}
void PresetBundle::load_compatible_bitmaps(wxWindow *window)
void PresetBundle::load_compatible_bitmaps()
{
// We don't actually pass the window pointer here and instead generate
// a low DPI bitmap, because the wxBitmapComboBox and wxDataViewCtrl don't support
// high DPI bitmaps very well, they compute their dimensions wrong.
// TODO: Update this when fixed in wxWidgets
// See also PresetCollection::load_bitmap_default() and PresetCollection::load_bitmap_add()
(void)window;
*m_bitmapCompatible = create_scaled_bitmap(nullptr, "flag_green");
*m_bitmapIncompatible = create_scaled_bitmap(nullptr, "flag_red");
*m_bitmapLock = create_scaled_bitmap(nullptr, "lock_closed");
*m_bitmapLockOpen = create_scaled_bitmap(nullptr, "lock_open");
*m_bitmapCompatible = create_scaled_bitmap("flag_green");
*m_bitmapIncompatible = create_scaled_bitmap("flag_red");
*m_bitmapLock = create_scaled_bitmap("lock_closed");
*m_bitmapLockOpen = create_scaled_bitmap("lock_open");
prints .set_bitmap_compatible(m_bitmapCompatible);
filaments .set_bitmap_compatible(m_bitmapCompatible);
@ -1536,31 +1529,7 @@ void PresetBundle::set_filament_preset(size_t idx, const std::string &name)
filament_presets[idx] = Preset::remove_suffix_modified(name);
}
static inline int hex_digit_to_int(const char c)
{
return
(c >= '0' && c <= '9') ? int(c - '0') :
(c >= 'A' && c <= 'F') ? int(c - 'A') + 10 :
(c >= 'a' && c <= 'f') ? int(c - 'a') + 10 : -1;
}
bool PresetBundle::parse_color(const std::string &scolor, unsigned char *rgb_out)
{
rgb_out[0] = rgb_out[1] = rgb_out[2] = 0;
if (scolor.size() != 7 || scolor.front() != '#')
return false;
const char *c = scolor.data() + 1;
for (size_t i = 0; i < 3; ++ i) {
int digit1 = hex_digit_to_int(*c ++);
int digit2 = hex_digit_to_int(*c ++);
if (digit1 == -1 || digit2 == -1)
return false;
rgb_out[i] = (unsigned char)(digit1 * 16 + digit2);
}
return true;
}
void PresetBundle::load_default_preset_bitmaps(wxWindow *window)
void PresetBundle::load_default_preset_bitmaps()
{
// Clear bitmap cache, before load new scaled default preset bitmaps
m_bitmapCache->clear();
@ -1570,13 +1539,13 @@ void PresetBundle::load_default_preset_bitmaps(wxWindow *window)
this->sla_materials.clear_bitmap_cache();
this->printers.clear_bitmap_cache();
this->prints.load_bitmap_default(window, "cog");
this->sla_prints.load_bitmap_default(window, "cog");
this->filaments.load_bitmap_default(window, "spool.png");
this->sla_materials.load_bitmap_default(window, "resin");
this->printers.load_bitmap_default(window, "printer");
this->printers.load_bitmap_add(window, "add.png");
this->load_compatible_bitmaps(window);
this->prints.load_bitmap_default("cog");
this->sla_prints.load_bitmap_default("cog");
this->filaments.load_bitmap_default("spool.png");
this->sla_materials.load_bitmap_default("resin");
this->printers.load_bitmap_default("printer");
this->printers.load_bitmap_add("add.png");
this->load_compatible_bitmaps();
}
void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui)
@ -1587,7 +1556,7 @@ void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::Pre
unsigned char rgb[3];
std::string extruder_color = this->printers.get_edited_preset().config.opt_string("extruder_colour", idx_extruder);
if (! parse_color(extruder_color, rgb))
if (!m_bitmapCache->parse_color(extruder_color, rgb))
// Extruder color is not defined.
extruder_color.clear();
@ -1623,7 +1592,12 @@ void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::Pre
// To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size, so
// set a bitmap height to m_bitmapLock->GetHeight()
const int icon_height = m_bitmapLock->GetHeight();//2 * icon_unit; //16 * scale_f + 0.5f;
// Note, under OSX we should use a ScaledHeight because of Retina scale
#ifdef __APPLE__
const int icon_height = m_bitmapLock->GetScaledHeight();
#else
const int icon_height = m_bitmapLock->GetHeight();
#endif
wxString tooltip = "";
@ -1652,10 +1626,10 @@ void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::Pre
// Paint a red flag for incompatible presets.
bmps.emplace_back(preset.is_compatible ? m_bitmapCache->mkclear(normal_icon_width, icon_height) : *m_bitmapIncompatible);
// Paint the color bars.
parse_color(filament_rgb, rgb);
m_bitmapCache->parse_color(filament_rgb, rgb);
bmps.emplace_back(m_bitmapCache->mksolid(single_bar ? wide_icon_width : normal_icon_width, icon_height, rgb));
if (! single_bar) {
parse_color(extruder_rgb, rgb);
m_bitmapCache->parse_color(extruder_rgb, rgb);
bmps.emplace_back(m_bitmapCache->mksolid(thin_icon_width, icon_height, rgb));
}
// Paint a lock at the system presets.

View file

@ -54,8 +54,7 @@ public:
// There will be an entry for each system profile loaded,
// and the system profiles will point to the VendorProfile instances owned by PresetBundle::vendors.
// std::set<VendorProfile> vendors;
VendorMap vendors;
VendorMap vendors;
struct ObsoletePresets {
std::vector<std::string> prints;
@ -130,9 +129,7 @@ public:
// preset if the current print or filament preset is not compatible.
void update_compatible(bool select_other_if_incompatible);
static bool parse_color(const std::string &scolor, unsigned char *rgb_out);
void load_default_preset_bitmaps(wxWindow *window);
void load_default_preset_bitmaps();
// Set the is_visible flag for printer vendors, printer models and printer variants
// based on the user configuration.
@ -161,7 +158,7 @@ private:
// If it is not an external config, then the config will be stored into the user profile directory.
void load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config);
void load_config_file_config_bundle(const std::string &path, const boost::property_tree::ptree &tree);
void load_compatible_bitmaps(wxWindow *window);
void load_compatible_bitmaps();
DynamicPrintConfig full_fff_config() const;
DynamicPrintConfig full_sla_config() const;

View file

@ -114,7 +114,7 @@ void Tab::create_preset_tab()
#endif //__WXOSX__
// preset chooser
m_presets_choice = new wxBitmapComboBox(panel, wxID_ANY, "", wxDefaultPosition, wxSize(35 * m_em_unit, -1), 0, 0, wxCB_READONLY);
m_presets_choice = new PresetBitmapComboBox(panel, wxSize(35 * m_em_unit, -1));
auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
@ -1690,7 +1690,7 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup)
auto printhost_cafile_browse = [this, optgroup] (wxWindow* parent) {
auto btn = new wxButton(parent, wxID_ANY, " " + _(L("Browse"))+" " +dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
btn->SetFont(Slic3r::GUI::wxGetApp().normal_font());
btn->SetBitmap(create_scaled_bitmap(this, "browse"));
btn->SetBitmap(create_scaled_bitmap("browse"));
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn);

View file

@ -120,7 +120,7 @@ protected:
Preset::Type m_type;
std::string m_name;
const wxString m_title;
wxBitmapComboBox* m_presets_choice;
PresetBitmapComboBox* m_presets_choice;
ScalableButton* m_btn_save_preset;
ScalableButton* m_btn_delete_preset;
ScalableButton* m_btn_hide_incompatible_presets;

View file

@ -149,7 +149,7 @@ MsgDataIncompatible::MsgDataIncompatible(const std::unordered_map<std::string, w
MsgDialog(nullptr, wxString::Format(_(L("%s incompatibility")), SLIC3R_APP_NAME),
wxString::Format(_(L("%s configuration is incompatible")), SLIC3R_APP_NAME), wxID_NONE)
{
logo->SetBitmap(create_scaled_bitmap(this, "PrusaSlicer_192px_grayscale.png", 192));
logo->SetBitmap(create_scaled_bitmap("PrusaSlicer_192px_grayscale.png", this, 192));
auto *text = new wxStaticText(this, wxID_ANY, wxString::Format(_(L(
"This version of %s is not compatible with currently installed configuration bundles.\n"

View file

@ -1,7 +1,7 @@
#include <algorithm>
#include <sstream>
#include "WipeTowerDialog.hpp"
#include "PresetBundle.hpp"
#include "BitmapCache.hpp"
#include "GUI.hpp"
#include "I18N.hpp"
#include "GUI_App.hpp"
@ -191,7 +191,7 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, con
for (const std::string& color : extruder_colours) {
unsigned char rgb[3];
Slic3r::PresetBundle::parse_color(color, rgb);
Slic3r::GUI::BitmapCache::parse_color(color, rgb);
m_colours.push_back(wxColor(rgb[0], rgb[1], rgb[2]));
}

File diff suppressed because it is too large Load diff

View file

@ -4,23 +4,14 @@
#include <wx/checklst.h>
#include <wx/combo.h>
#include <wx/dataview.h>
#include <wx/dc.h>
#include <wx/wupdlock.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/menu.h>
#include <wx/wx.h>
#include <wx/bmpcbox.h>
#include <vector>
#include <set>
#include <functional>
namespace Slic3r {
enum class ModelVolumeType : int;
};
typedef double coordf_t;
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
#ifdef __WXMSW__
void msw_rescale_menu(wxMenu* menu);
@ -48,15 +39,13 @@ wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string,
void enable_menu_item(wxUpdateUIEvent& evt, std::function<bool()> const cb_condition, wxMenuItem* item, wxWindow* win);
class wxDialog;
class wxBitmapComboBox;
void edit_tooltip(wxString& tooltip);
void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector<int>& btn_ids);
int em_unit(wxWindow* win);
float get_svg_scale_factor(wxWindow* win);
wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name,
const int px_cnt = 16, const bool is_horizontal = false, const bool grayscale = false);
wxBitmap create_scaled_bitmap(const std::string& bmp_name, wxWindow *win = nullptr,
const int px_cnt = 16, const bool grayscale = false);
std::vector<wxBitmap*> get_extruder_color_icons(bool thin_icon = false);
void apply_extruder_selector(wxBitmapComboBox** ctrl,
@ -102,6 +91,37 @@ public:
void OnListBoxSelection(wxCommandEvent& evt);
};
namespace Slic3r {
namespace GUI {
// *** PresetBitmapComboBox ***
// BitmapComboBox used to presets list on Sidebar and Tabs
class PresetBitmapComboBox: public wxBitmapComboBox
{
public:
PresetBitmapComboBox(wxWindow* parent, const wxSize& size = wxDefaultSize);
~PresetBitmapComboBox() {}
#ifdef __APPLE__
protected:
/* For PresetBitmapComboBox we use bitmaps that are created from images that are already scaled appropriately for Retina
* (Contrary to the intuition, the `scale` argument for Bitmap's constructor doesn't mean
* "please scale this to such and such" but rather
* "the wxImage is already sized for backing scale such and such". )
* Unfortunately, the constructor changes the size of wxBitmap too.
* Thus We need to use unscaled size value for bitmaps that we use
* to avoid scaled size of control items.
* For this purpose control drawing methods and
* control size calculation methods (virtual) are overridden.
**/
virtual bool OnAddBitmap(const wxBitmap& bitmap) override;
virtual void OnDrawItem(wxDC& dc, const wxRect& rect, int item, int flags) const override;
#endif
};
}
}
// *** wxDataViewTreeCtrlComboBox ***
@ -127,587 +147,6 @@ public:
};
// ----------------------------------------------------------------------------
// DataViewBitmapText: helper class used by PrusaBitmapTextRenderer
// ----------------------------------------------------------------------------
class DataViewBitmapText : public wxObject
{
public:
DataViewBitmapText( const wxString &text = wxEmptyString,
const wxBitmap& bmp = wxNullBitmap) :
m_text(text),
m_bmp(bmp)
{ }
DataViewBitmapText(const DataViewBitmapText &other)
: wxObject(),
m_text(other.m_text),
m_bmp(other.m_bmp)
{ }
void SetText(const wxString &text) { m_text = text; }
wxString GetText() const { return m_text; }
void SetBitmap(const wxBitmap &bmp) { m_bmp = bmp; }
const wxBitmap &GetBitmap() const { return m_bmp; }
bool IsSameAs(const DataViewBitmapText& other) const {
return m_text == other.m_text && m_bmp.IsSameAs(other.m_bmp);
}
bool operator==(const DataViewBitmapText& other) const {
return IsSameAs(other);
}
bool operator!=(const DataViewBitmapText& other) const {
return !IsSameAs(other);
}
private:
wxString m_text;
wxBitmap m_bmp;
wxDECLARE_DYNAMIC_CLASS(DataViewBitmapText);
};
DECLARE_VARIANT_OBJECT(DataViewBitmapText)
// ----------------------------------------------------------------------------
// ObjectDataViewModelNode: a node inside ObjectDataViewModel
// ----------------------------------------------------------------------------
enum ItemType {
itUndef = 0,
itObject = 1,
itVolume = 2,
itInstanceRoot = 4,
itInstance = 8,
itSettings = 16,
itLayerRoot = 32,
itLayer = 64,
};
enum ColumnNumber
{
colName = 0, // item name
colPrint , // printable property
colExtruder , // extruder selection
colEditing , // item editing
};
enum PrintIndicator
{
piUndef = 0, // no print indicator
piPrintable , // printable
piUnprintable , // unprintable
};
class ObjectDataViewModelNode;
WX_DEFINE_ARRAY_PTR(ObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray);
class ObjectDataViewModelNode
{
ObjectDataViewModelNode* m_parent;
MyObjectTreeModelNodePtrArray m_children;
wxBitmap m_empty_bmp;
size_t m_volumes_cnt = 0;
std::vector< std::string > m_opt_categories;
t_layer_height_range m_layer_range = { 0.0f, 0.0f };
wxString m_name;
wxBitmap& m_bmp = m_empty_bmp;
ItemType m_type;
int m_idx = -1;
bool m_container = false;
wxString m_extruder = "default";
wxBitmap m_extruder_bmp;
wxBitmap m_action_icon;
PrintIndicator m_printable {piUndef};
wxBitmap m_printable_icon;
std::string m_action_icon_name = "";
Slic3r::ModelVolumeType m_volume_type;
public:
ObjectDataViewModelNode(const wxString &name,
const wxString& extruder):
m_parent(NULL),
m_name(name),
m_type(itObject),
m_extruder(extruder)
{
set_action_and_extruder_icons();
init_container();
}
ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
const wxString& sub_obj_name,
const wxBitmap& bmp,
const wxString& extruder,
const int idx = -1 ) :
m_parent (parent),
m_name (sub_obj_name),
m_type (itVolume),
m_idx (idx),
m_extruder (extruder)
{
m_bmp = bmp;
set_action_and_extruder_icons();
init_container();
}
ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
const t_layer_height_range& layer_range,
const int idx = -1,
const wxString& extruder = wxEmptyString );
ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type);
~ObjectDataViewModelNode()
{
// free all our children nodes
size_t count = m_children.GetCount();
for (size_t i = 0; i < count; i++)
{
ObjectDataViewModelNode *child = m_children[i];
delete child;
}
#ifndef NDEBUG
// Indicate that the object was deleted.
m_idx = -2;
#endif /* NDEBUG */
}
void init_container();
bool IsContainer() const
{
return m_container;
}
ObjectDataViewModelNode* GetParent()
{
assert(m_parent == nullptr || m_parent->valid());
return m_parent;
}
MyObjectTreeModelNodePtrArray& GetChildren()
{
return m_children;
}
ObjectDataViewModelNode* GetNthChild(unsigned int n)
{
return m_children.Item(n);
}
void Insert(ObjectDataViewModelNode* child, unsigned int n)
{
if (!m_container)
m_container = true;
m_children.Insert(child, n);
}
void Append(ObjectDataViewModelNode* child)
{
if (!m_container)
m_container = true;
m_children.Add(child);
}
void RemoveAllChildren()
{
if (GetChildCount() == 0)
return;
for (int id = int(GetChildCount()) - 1; id >= 0; --id)
{
if (m_children.Item(id)->GetChildCount() > 0)
m_children[id]->RemoveAllChildren();
auto node = m_children[id];
m_children.RemoveAt(id);
delete node;
}
}
size_t GetChildCount() const
{
return m_children.GetCount();
}
bool SetValue(const wxVariant &variant, unsigned int col);
void SetBitmap(const wxBitmap &icon) { m_bmp = icon; }
const wxBitmap& GetBitmap() const { return m_bmp; }
const wxString& GetName() const { return m_name; }
ItemType GetType() const { return m_type; }
void SetIdx(const int& idx);
int GetIdx() const { return m_idx; }
t_layer_height_range GetLayerRange() const { return m_layer_range; }
PrintIndicator IsPrintable() const { return m_printable; }
// use this function only for childrens
void AssignAllVal(ObjectDataViewModelNode& from_node)
{
// ! Don't overwrite other values because of equality of this values for all children --
m_name = from_node.m_name;
m_bmp = from_node.m_bmp;
m_idx = from_node.m_idx;
m_extruder = from_node.m_extruder;
m_type = from_node.m_type;
}
bool SwapChildrens(int frst_id, int scnd_id) {
if (GetChildCount() < 2 ||
frst_id < 0 || (size_t)frst_id >= GetChildCount() ||
scnd_id < 0 || (size_t)scnd_id >= GetChildCount())
return false;
ObjectDataViewModelNode new_scnd = *GetNthChild(frst_id);
ObjectDataViewModelNode new_frst = *GetNthChild(scnd_id);
new_scnd.m_idx = m_children.Item(scnd_id)->m_idx;
new_frst.m_idx = m_children.Item(frst_id)->m_idx;
m_children.Item(frst_id)->AssignAllVal(new_frst);
m_children.Item(scnd_id)->AssignAllVal(new_scnd);
return true;
}
// Set action icons for node
void set_action_and_extruder_icons();
// Set printable icon for node
void set_printable_icon(PrintIndicator printable);
void update_settings_digest_bitmaps();
bool update_settings_digest(const std::vector<std::string>& categories);
int volume_type() const { return int(m_volume_type); }
void msw_rescale();
#ifndef NDEBUG
bool valid();
#endif /* NDEBUG */
bool invalid() const { return m_idx < -1; }
private:
friend class ObjectDataViewModel;
};
// ----------------------------------------------------------------------------
// ObjectDataViewModel
// ----------------------------------------------------------------------------
// custom message the model sends to associated control to notify a last volume deleted from the object:
wxDECLARE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent);
class ObjectDataViewModel :public wxDataViewModel
{
std::vector<ObjectDataViewModelNode*> m_objects;
std::vector<wxBitmap*> m_volume_bmps;
wxBitmap* m_warning_bmp { nullptr };
wxDataViewCtrl* m_ctrl { nullptr };
public:
ObjectDataViewModel();
~ObjectDataViewModel();
wxDataViewItem Add( const wxString &name,
const int extruder,
const bool has_errors = false);
wxDataViewItem AddVolumeChild( const wxDataViewItem &parent_item,
const wxString &name,
const Slic3r::ModelVolumeType volume_type,
const bool has_errors = false,
const int extruder = 0,
const bool create_frst_child = true);
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, const std::vector<bool>& print_indicator);
wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item,
const t_layer_height_range& layer_range,
const int extruder = 0,
const int index = -1);
wxDataViewItem Delete(const wxDataViewItem &item);
wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
void DeleteAll();
void DeleteChildren(wxDataViewItem& parent);
void DeleteVolumeChildren(wxDataViewItem& parent);
void DeleteSettings(const wxDataViewItem& parent);
wxDataViewItem GetItemById(int obj_idx);
wxDataViewItem GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type);
wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx);
wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx);
wxDataViewItem GetItemByLayerId(int obj_idx, int layer_idx);
wxDataViewItem GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
int GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
int GetIdByItem(const wxDataViewItem& item) const;
int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
int GetObjectIdByItem(const wxDataViewItem& item) const;
int GetVolumeIdByItem(const wxDataViewItem& item) const;
int GetInstanceIdByItem(const wxDataViewItem& item) const;
int GetLayerIdByItem(const wxDataViewItem& item) const;
void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx);
int GetRowByItem(const wxDataViewItem& item) const;
bool IsEmpty() { return m_objects.empty(); }
bool InvalidItem(const wxDataViewItem& item);
// helper method for wxLog
wxString GetName(const wxDataViewItem &item) const;
wxBitmap& GetBitmap(const wxDataViewItem &item) const;
wxString GetExtruder(const wxDataViewItem &item) const;
int GetExtruderNumber(const wxDataViewItem &item) const;
// helper methods to change the model
virtual unsigned int GetColumnCount() const override { return 3;}
virtual wxString GetColumnType(unsigned int col) const override{ return wxT("string"); }
virtual void GetValue( wxVariant &variant,
const wxDataViewItem &item,
unsigned int col) const override;
virtual bool SetValue( const wxVariant &variant,
const wxDataViewItem &item,
unsigned int col) override;
bool SetValue( const wxVariant &variant,
const int item_idx,
unsigned int col);
void SetExtruder(const wxString& extruder, wxDataViewItem item);
// For parent move child from cur_volume_id place to new_volume_id
// Remaining items will moved up/down accordingly
wxDataViewItem ReorganizeChildren( const int cur_volume_id,
const int new_volume_id,
const wxDataViewItem &parent);
virtual bool IsEnabled(const wxDataViewItem &item, unsigned int col) const override;
virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override;
// get object item
wxDataViewItem GetTopParent(const wxDataViewItem &item) const;
virtual bool IsContainer(const wxDataViewItem &item) const override;
virtual unsigned int GetChildren(const wxDataViewItem &parent,
wxDataViewItemArray &array) const override;
void GetAllChildren(const wxDataViewItem &parent,wxDataViewItemArray &array) const;
// Is the container just a header or an item with all columns
// In our case it is an item with all columns
virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; }
ItemType GetItemType(const wxDataViewItem &item) const ;
wxDataViewItem GetItemByType( const wxDataViewItem &parent_item,
ItemType type) const;
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const;
bool IsSettingsItem(const wxDataViewItem &item) const;
void UpdateSettingsDigest( const wxDataViewItem &item,
const std::vector<std::string>& categories);
bool IsPrintable(const wxDataViewItem &item) const;
void UpdateObjectPrintable(wxDataViewItem parent_item);
void UpdateInstancesPrintable(wxDataViewItem parent_item);
void SetVolumeBitmaps(const std::vector<wxBitmap*>& volume_bmps) { m_volume_bmps = volume_bmps; }
void SetWarningBitmap(wxBitmap* bitmap) { m_warning_bmp = bitmap; }
void SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type);
wxDataViewItem SetPrintableState( PrintIndicator printable, int obj_idx,
int subobj_idx = -1,
ItemType subobj_type = itInstance);
wxDataViewItem SetObjectPrintableState(PrintIndicator printable, wxDataViewItem obj_item);
void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; }
// Rescale bitmaps for existing Items
void Rescale();
wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type,
const bool is_marked = false);
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const;
bool UpdateColumValues(unsigned col);
void UpdateExtruderBitmap(wxDataViewItem item);
private:
wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type);
wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item);
};
// ----------------------------------------------------------------------------
// BitmapTextRenderer
// ----------------------------------------------------------------------------
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
class BitmapTextRenderer : public wxDataViewRenderer
#else
class BitmapTextRenderer : public wxDataViewCustomRenderer
#endif //ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
{
public:
BitmapTextRenderer(wxDataViewCellMode mode =
#ifdef __WXOSX__
wxDATAVIEW_CELL_INERT
#else
wxDATAVIEW_CELL_EDITABLE
#endif
,int align = wxDVR_DEFAULT_ALIGNMENT
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
);
#else
) : wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align) {}
#endif //ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
bool SetValue(const wxVariant &value);
bool GetValue(wxVariant &value) const;
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING && wxUSE_ACCESSIBILITY
virtual wxString GetAccessibleDescription() const override;
#endif // wxUSE_ACCESSIBILITY && ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
virtual bool Render(wxRect cell, wxDC *dc, int state);
virtual wxSize GetSize() const;
bool HasEditorCtrl() const override
{
#ifdef __WXOSX__
return false;
#else
return true;
#endif
}
wxWindow* CreateEditorCtrl(wxWindow* parent,
wxRect labelRect,
const wxVariant& value) override;
bool GetValueFromEditorCtrl( wxWindow* ctrl,
wxVariant& value) override;
bool WasCanceled() const { return m_was_unusable_symbol; }
private:
DataViewBitmapText m_value;
bool m_was_unusable_symbol {false};
};
// ----------------------------------------------------------------------------
// BitmapChoiceRenderer
// ----------------------------------------------------------------------------
class BitmapChoiceRenderer : public wxDataViewCustomRenderer
{
public:
BitmapChoiceRenderer(wxDataViewCellMode mode =
#ifdef __WXOSX__
wxDATAVIEW_CELL_INERT
#else
wxDATAVIEW_CELL_EDITABLE
#endif
,int align = wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL
) : wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align) {}
bool SetValue(const wxVariant& value);
bool GetValue(wxVariant& value) const;
virtual bool Render(wxRect cell, wxDC* dc, int state);
virtual wxSize GetSize() const;
bool HasEditorCtrl() const override { return true; }
wxWindow* CreateEditorCtrl(wxWindow* parent,
wxRect labelRect,
const wxVariant& value) override;
bool GetValueFromEditorCtrl( wxWindow* ctrl,
wxVariant& value) override;
private:
DataViewBitmapText m_value;
};
// ----------------------------------------------------------------------------
// MyCustomRenderer
// ----------------------------------------------------------------------------
class MyCustomRenderer : public wxDataViewCustomRenderer
{
public:
// This renderer can be either activatable or editable, for demonstration
// purposes. In real programs, you should select whether the user should be
// able to activate or edit the cell and it doesn't make sense to switch
// between the two -- but this is just an example, so it doesn't stop us.
explicit MyCustomRenderer(wxDataViewCellMode mode)
: wxDataViewCustomRenderer("string", mode, wxALIGN_CENTER)
{ }
virtual bool Render(wxRect rect, wxDC *dc, int state) override/*wxOVERRIDE*/
{
dc->SetBrush(*wxLIGHT_GREY_BRUSH);
dc->SetPen(*wxTRANSPARENT_PEN);
rect.Deflate(2);
dc->DrawRoundedRectangle(rect, 5);
RenderText(m_value,
0, // no offset
wxRect(dc->GetTextExtent(m_value)).CentreIn(rect),
dc,
state);
return true;
}
virtual bool ActivateCell(const wxRect& WXUNUSED(cell),
wxDataViewModel *WXUNUSED(model),
const wxDataViewItem &WXUNUSED(item),
unsigned int WXUNUSED(col),
const wxMouseEvent *mouseEvent) override/*wxOVERRIDE*/
{
wxString position;
if (mouseEvent)
position = wxString::Format("via mouse at %d, %d", mouseEvent->m_x, mouseEvent->m_y);
else
position = "from keyboard";
// wxLogMessage("MyCustomRenderer ActivateCell() %s", position);
return false;
}
virtual wxSize GetSize() const override/*wxOVERRIDE*/
{
return wxSize(60, 20);
}
virtual bool SetValue(const wxVariant &value) override/*wxOVERRIDE*/
{
m_value = value.GetString();
return true;
}
virtual bool GetValue(wxVariant &WXUNUSED(value)) const override/*wxOVERRIDE*/{ return true; }
virtual bool HasEditorCtrl() const override/*wxOVERRIDE*/{ return true; }
virtual wxWindow*
CreateEditorCtrl(wxWindow* parent,
wxRect labelRect,
const wxVariant& value) override/*wxOVERRIDE*/
{
wxTextCtrl* text = new wxTextCtrl(parent, wxID_ANY, value,
labelRect.GetPosition(),
labelRect.GetSize(),
wxTE_PROCESS_ENTER);
text->SetInsertionPointEnd();
return text;
}
virtual bool
GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) override/*wxOVERRIDE*/
{
wxTextCtrl* text = wxDynamicCast(ctrl, wxTextCtrl);
if (!text)
return false;
value = text->GetValue();
return true;
}
private:
wxString m_value;
};
// ----------------------------------------------------------------------------
// ScalableBitmap
// ----------------------------------------------------------------------------
@ -718,11 +157,14 @@ public:
ScalableBitmap() {};
ScalableBitmap( wxWindow *parent,
const std::string& icon_name = "",
const int px_cnt = 16,
const bool is_horizontal = false);
const int px_cnt = 16);
~ScalableBitmap() {}
wxSize GetBmpSize() const;
int GetBmpWidth() const;
int GetBmpHeight() const;
void msw_rescale();
const wxBitmap& bmp() const { return m_bmp; }
@ -730,14 +172,12 @@ public:
const std::string& name() const{ return m_icon_name; }
int px_cnt()const {return m_px_cnt;}
bool is_horizontal()const {return m_is_horizontal;}
private:
wxWindow* m_parent{ nullptr };
wxBitmap m_bmp = wxBitmap();
std::string m_icon_name = "";
int m_px_cnt {16};
bool m_is_horizontal {false};
};
@ -821,7 +261,6 @@ private:
// bitmap dimensions
int m_px_cnt{ 16 };
bool m_is_horizontal{ false };
};