Separate icon manager. Create well public interface for future work and improve

This commit is contained in:
Filip Sykala - NTB T15p 2023-02-24 13:31:20 +01:00
parent 870561469f
commit 9d88830365
5 changed files with 287 additions and 57 deletions

View File

@ -97,6 +97,8 @@ set(SLIC3R_GUI_SOURCES
GUI/GUI_Geometry.hpp GUI/GUI_Geometry.hpp
GUI/I18N.cpp GUI/I18N.cpp
GUI/I18N.hpp GUI/I18N.hpp
GUI/IconManager.cpp
GUI/IconManager.hpp
GUI/MainFrame.cpp GUI/MainFrame.cpp
GUI/MainFrame.hpp GUI/MainFrame.hpp
GUI/Plater.cpp GUI/Plater.cpp

View File

@ -3795,23 +3795,9 @@ void GLGizmoEmboss::init_icons()
std::string path = resources_dir() + "/icons/"; std::string path = resources_dir() + "/icons/";
for (std::string &filename : filenames) filename = path + filename; for (std::string &filename : filenames) filename = path + filename;
// state order has to match the enum IconState ImVec2 size(m_gui_cfg->icon_width, m_gui_cfg->icon_width);
std::vector<std::pair<int, bool>> states; auto type = IconManager::RasterType::color_wite_gray;
states.push_back(std::make_pair(1, false)); // Activable m_icons = m_icon_manager.init(filenames, size, type);
states.push_back(std::make_pair(0, false)); // Hovered
states.push_back(std::make_pair(2, false)); // Disabled
bool compress = false;
bool is_loaded = m_icons_texture.load_from_svg_files_as_sprites_array(
filenames, states, m_gui_cfg->icon_width, compress);
if (!is_loaded ||
(size_t)m_icons_texture.get_width() < (states.size() * m_gui_cfg->icon_width) ||
(size_t)m_icons_texture.get_height() < (filenames.size() * m_gui_cfg->icon_width)) {
// bad load of icons, but all usage of m_icons_texture check that texture is initialized
assert(false);
m_icons_texture.reset();
}
} }
void GLGizmoEmboss::draw_icon(IconType icon, IconState state, ImVec2 size) void GLGizmoEmboss::draw_icon(IconType icon, IconState state, ImVec2 size)
@ -3820,48 +3806,32 @@ void GLGizmoEmboss::draw_icon(IconType icon, IconState state, ImVec2 size)
assert(icon != IconType::_count); assert(icon != IconType::_count);
if (icon == IconType::_count) return; if (icon == IconType::_count) return;
unsigned int icons_texture_id = m_icons_texture.get_id(); const auto &i = *m_icons[static_cast<int>(icon)][static_cast<int>(state)];
int tex_width = m_icons_texture.get_width(); IconManager::draw(i);
int tex_height = m_icons_texture.get_height();
// is icon loaded
if ((icons_texture_id == 0) || (tex_width <= 1) || (tex_height <= 1)){
ImGui::Text("");
return;
}
int icon_width = m_gui_cfg->icon_width;
ImTextureID tex_id = (void *) (intptr_t) (GLuint) icons_texture_id;
int start_x = static_cast<unsigned>(state) * (icon_width + 1) + 1,
start_y = static_cast<unsigned>(icon) * (icon_width + 1) + 1;
ImVec2 uv0(start_x / (float) tex_width,
start_y / (float) tex_height);
ImVec2 uv1((start_x + icon_width) / (float) tex_width,
(start_y + icon_width) / (float) tex_height);
if (size.x < 1 || size.y < 1)
size = ImVec2(m_gui_cfg->icon_width, m_gui_cfg->icon_width);
ImGui::Image(tex_id, size, uv0, uv1);
} }
void GLGizmoEmboss::draw_transparent_icon() void GLGizmoEmboss::draw_transparent_icon()
{ {
unsigned int icons_texture_id = m_icons_texture.get_id(); // use top left corner of first icon
int tex_width = m_icons_texture.get_width(); IconManager::Icon icon = *m_icons.front().front(); // copy
int tex_height = m_icons_texture.get_height();
// is icon loaded if (!icon.is_valid()) {
if ((icons_texture_id == 0) || (tex_width <= 1) || (tex_height <= 1)) {
ImGui::Text(""); ImGui::Text("");
return; return;
} }
ImTextureID tex_id = (void *) (intptr_t) (GLuint) icons_texture_id; // size UV texture coors [in texture ratio]
int icon_width = m_gui_cfg->icon_width; ImVec2 size_uv(
ImVec2 icon_size(icon_width, icon_width); icon.br.x-icon.tl.x,
ImVec2 pixel_size(1.f / tex_width, 1.f / tex_height); icon.br.y-icon.tl.y);
// zero pixel is transparent in texture ImVec2 one_px(
ImGui::Image(tex_id, icon_size, ImVec2(0, 0), pixel_size); size_uv.x/icon.size.x,
size_uv.y/icon.size.y);
// reduce uv coors to one pixel
icon.br = ImVec2(
icon.tl.x + one_px.x,
icon.tl.y + one_px.y);
IconManager::draw(icon);
} }
bool GLGizmoEmboss::draw_clickable( bool GLGizmoEmboss::draw_clickable(

View File

@ -5,15 +5,12 @@
// which overrides our localization "L" macro. // which overrides our localization "L" macro.
#include "GLGizmoBase.hpp" #include "GLGizmoBase.hpp"
#include "GLGizmoRotate.hpp" #include "GLGizmoRotate.hpp"
#include "slic3r/GUI/GLTexture.hpp" #include "slic3r/GUI/IconManager.hpp"
#include "slic3r/Utils/RaycastManager.hpp" #include "slic3r/Utils/RaycastManager.hpp"
#include "slic3r/Utils/EmbossStyleManager.hpp" #include "slic3r/Utils/EmbossStyleManager.hpp"
#include "admesh/stl.h" // indexed_triangle_set
#include <optional> #include <optional>
#include <memory> #include <memory>
#include <mutex>
#include <thread>
#include <atomic> #include <atomic>
#include "libslic3r/Emboss.hpp" #include "libslic3r/Emboss.hpp"
@ -33,7 +30,6 @@ namespace Slic3r{
} }
namespace Slic3r::GUI { namespace Slic3r::GUI {
class MeshRaycaster;
class GLGizmoEmboss : public GLGizmoBase class GLGizmoEmboss : public GLGizmoBase
{ {
public: public:
@ -346,7 +342,9 @@ private:
void calculate_scale(); void calculate_scale();
// drawing icons // drawing icons
GLTexture m_icons_texture; IconManager m_icon_manager;
std::vector<IconManager::Icons> m_icons;
void init_icons(); void init_icons();
enum class IconType : unsigned { enum class IconType : unsigned {
rename = 0, rename = 0,

View File

@ -0,0 +1,150 @@
#include "IconManager.hpp"
#include <boost/log/trivial.hpp>
using namespace Slic3r::GUI;
namespace priv {
// set shared pointer to point on bad texture
static void clear(IconManager::Icons &icons);
static const std::vector<std::pair<int, bool>>& get_states(IconManager::RasterType type);
}
IconManager::~IconManager() {
priv::clear(m_icons);
// release opengl texture is made in ~GLTexture()
}
std::vector<IconManager::Icons> IconManager::init(const InitTypes &input)
{
BOOST_LOG_TRIVIAL(error) << "Not implemented yet";
return {};
}
std::vector<IconManager::Icons> IconManager::init(const std::vector<std::string> &file_paths, const ImVec2 &size, RasterType type)
{
// TODO: remove in future
if (!m_icons.empty()) {
// not first initialization
priv::clear(m_icons);
m_icons.clear();
m_icons_texture.reset();
}
// only rectangle are supported
assert(size.x == size.y);
// no subpixel supported
unsigned int width = static_cast<unsigned int>(std::fabs(std::round(size.x)));
assert(size.x == static_cast<float>(width));
// state order has to match the enum IconState
const auto& states = priv::get_states(type);
bool compress = false;
bool is_loaded = m_icons_texture.load_from_svg_files_as_sprites_array(file_paths, states, width, compress);
if (!is_loaded || (size_t) m_icons_texture.get_width() < (states.size() * width) ||
(size_t) m_icons_texture.get_height() < (file_paths.size() * width)) {
// bad load of icons, but all usage of m_icons_texture check that texture is initialized
assert(false);
m_icons_texture.reset();
return {};
}
unsigned count_files = file_paths.size();
// count icons per file
unsigned count = states.size();
// create result
std::vector<Icons> result;
result.reserve(count_files);
Icon def_icon;
def_icon.tex_id = m_icons_texture.get_id();
def_icon.size = size;
// float beacouse of dividing
float tex_height = static_cast<float>(m_icons_texture.get_height());
float tex_width = static_cast<float>(m_icons_texture.get_width());
//for (const auto &f: file_paths) {
for (unsigned f = 0; f < count_files; ++f) {
// NOTE: there are space between icons
unsigned start_y = static_cast<unsigned>(f) * (width + 1) + 1;
float y1 = start_y / tex_height;
float y2 = (start_y + width) / tex_height;
Icons file_icons;
file_icons.reserve(count);
//for (const auto &s : states) {
for (unsigned j = 0; j < count; ++j) {
auto icon = std::make_shared<Icon>(def_icon);
// NOTE: there are space between icons
unsigned start_x = static_cast<unsigned>(j) * (width + 1) + 1;
float x1 = start_x / tex_width;
float x2 = (start_x + width) / tex_width;
icon->tl = ImVec2(x1, y1);
icon->br = ImVec2(x2, y2);
file_icons.push_back(icon);
m_icons.push_back(std::move(icon));
}
result.emplace_back(std::move(file_icons));
}
return result;
}
void IconManager::release() {
BOOST_LOG_TRIVIAL(error) << "Not implemented yet";
}
void IconManager::draw(const Icon &icon, const ImVec2 &size, const ImVec4 &tint_col, const ImVec4 &border_col)
{
// is icon loaded
if (!icon.is_valid()) {
ImGui::Text("?");
return;
}
ImTextureID id = (void *) icon.tex_id;
const ImVec2 &s = (size.x < 1 || size.y < 1) ? icon.size : size;
ImGui::Image(id, s, icon.tl, icon.br, tint_col, border_col);
}
void priv::clear(IconManager::Icons &icons) {
std::string message;
for (auto &icon : icons) {
// Exist more than this instance of shared ptr?
long count = icon.use_count();
if (count != 1) {
// in existing icon change texture to non existing one
icon->tex_id = 0;
std::string descr =
((count > 2) ? (std::to_string(count - 1) + "x") : "") + // count
std::to_string(icon->size.x) + "x" + std::to_string(icon->size.y); // resolution
if (message.empty())
message = descr;
else
message += ", " + descr;
}
}
if (!message.empty())
BOOST_LOG_TRIVIAL(warning) << "There is still used icons(" << message << ").";
}
const std::vector<std::pair<int, bool>> &priv::get_states(IconManager::RasterType type) {
static std::vector<std::pair<int, bool>> color = {std::make_pair(0, false)};
static std::vector<std::pair<int, bool>> white = {std::make_pair(1, false)};
static std::vector<std::pair<int, bool>> gray = {std::make_pair(2, false)};
static std::vector<std::pair<int, bool>> color_wite_gray = {
std::make_pair(1, false), // Activable
std::make_pair(0, false), // Hovered
std::make_pair(2, false) // Disabled
};
switch (type) {
case IconManager::RasterType::color: return color;
case IconManager::RasterType::white_only_data: return white;
case IconManager::RasterType::gray_only_data: return gray;
case IconManager::RasterType::color_wite_gray: return color_wite_gray;
default: return color;
}
}

View File

@ -0,0 +1,110 @@
#ifndef slic3r_IconManager_hpp_
#define slic3r_IconManager_hpp_
#include <vector>
#include <memory>
#include "imgui/imgui.h" // ImVec2
#include "slic3r/GUI/GLTexture.hpp" // texture storage
namespace Slic3r::GUI {
/// <summary>
/// Keep texture with icons for UI
/// Manage texture live -> create and destruct texture
/// by live of icon shared pointers.
/// </summary>
class IconManager
{
public:
/// <summary>
/// Release texture
/// Set shared pointers to invalid texture
/// </summary>
~IconManager();
/// <summary>
/// Define way to convert svg data to raster
/// </summary>
enum class RasterType: int{
color = 1 << 1,
white_only_data = 1 << 2,
gray_only_data = 1 << 3,
color_wite_gray = color | white_only_data | gray_only_data
// TODO: add type with backgrounds
};
struct InitType {
// path to file with image .. svg
std::string filepath;
// resolution of stored rasterized icon
ImVec2 size; // float will be rounded
// could contain more than one type
RasterType type = RasterType::color;
// together color, white and gray = color | white_only_data | gray_only_data
};
using InitTypes = std::vector<InitType>;
/// <summary>
/// Data for render texture with icon
/// </summary>
struct Icon {
// stored texture size
ImVec2 size = ImVec2(-1, -1); // [in px] --> unsigned int values stored as float
// SubTexture UV coordinate in range from 0. to 1.
ImVec2 tl; // top left -> uv0
ImVec2 br; // bottom right -> uv1
// OpenGL texture id
unsigned int tex_id = 0;
bool is_valid() const { return tex_id != 0;}
// && size.x > 0 && size.y > 0 && tl.x != br.x && tl.y != br.y;
};
using Icons = std::vector<std::shared_ptr<Icon> >;
/// <summary>
/// Initialize raster texture on GPU with given images
/// NOTE: Have to be called after OpenGL initialization
/// </summary>
/// <param name="input">Define files and its </param>
/// <returns>Rasterized icons stored on GPU,
/// Same size and order as input, each item of vector is set of texture in order by RasterType</returns>
std::vector<Icons> init(const InitTypes &input);
/// <summary>
/// Initialize multiple icons with same settings for size and type
/// NOTE: Have to be called after OpenGL initialization
/// </summary>
/// <param name="file_paths">Define files with icon</param>
/// <param name="size">Size of stored texture[in px], float will be rounded</param>
/// <param name="type">Define way to rasterize icon,
/// together color, white and gray = RasterType::color | RasterType::white_only_data | RasterType::gray_only_data</param>
/// <returns>Rasterized icons stored on GPU,
/// Same size and order as file_paths, each item of vector is set of texture in order by RasterType</returns>
std::vector<Icons> init(const std::vector<std::string> &file_paths, const ImVec2 &size, RasterType type = RasterType::color);
/// <summary>
/// Release icons which are hold only by this manager
/// May change texture and position of icons.
/// </summary>
void release();
/// <summary>
/// Draw imgui image with icon
/// </summary>
/// <param name="icon">Place in texture</param>
/// <param name="size">[optional]Size of image, wen zero than use same size as stored texture</param>
/// <param name="tint_col">viz ImGui::Image </param>
/// <param name="border_col">viz ImGui::Image </param>
static void draw(const Icon &icon, const ImVec2 &size = ImVec2(0, 0), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0));
private:
// keep data stored on GPU
GLTexture m_icons_texture;
Icons m_icons;
};
} // namespace Slic3r::GUI
#endif // slic3r_IconManager_hpp_