Font name in selecetion of font
This commit is contained in:
parent
664fb8120c
commit
abea5c95f3
@ -184,6 +184,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/Jobs/PlaterWorker.hpp
|
||||
GUI/Jobs/ArrangeJob.hpp
|
||||
GUI/Jobs/ArrangeJob.cpp
|
||||
GUI/Jobs/CreateFontNameImageJob.cpp
|
||||
GUI/Jobs/CreateFontNameImageJob.hpp
|
||||
GUI/Jobs/CreateFontStyleImagesJob.cpp
|
||||
GUI/Jobs/CreateFontStyleImagesJob.hpp
|
||||
GUI/Jobs/EmbossJob.cpp
|
||||
|
@ -723,6 +723,8 @@ void GLGizmoEmboss::initialize()
|
||||
2 * style.FramePadding.x;
|
||||
int max_style_image_height = 2 * input_height;
|
||||
cfg.max_style_image_size = Vec2i(max_style_image_width, max_style_image_height);
|
||||
cfg.face_name_size.y() = line_height_with_spacing;
|
||||
|
||||
m_gui_cfg.emplace(std::move(cfg));
|
||||
|
||||
init_icons();
|
||||
@ -1313,8 +1315,43 @@ void GLGizmoEmboss::init_face_names() {
|
||||
std::sort(m_face_names.names.begin(), m_face_names.names.end());
|
||||
}
|
||||
|
||||
#include "slic3r/GUI/Jobs/CreateFontNameImageJob.hpp"
|
||||
void GLGizmoEmboss::draw_font_list()
|
||||
{
|
||||
{
|
||||
// Create of texture for font name
|
||||
auto init_texture = [&face_names = m_face_names, size = m_gui_cfg->face_name_size]() {
|
||||
// check if already exists
|
||||
GLuint &id = face_names.texture_id;
|
||||
if (id != 0) return;
|
||||
// create texture for font
|
||||
GLenum target = GL_TEXTURE_2D, format = GL_ALPHA,
|
||||
type = GL_UNSIGNED_BYTE;
|
||||
GLint level = 0, border = 0;
|
||||
glsafe(::glGenTextures(1, &id));
|
||||
glsafe(::glBindTexture(target, id));
|
||||
glsafe(::glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
|
||||
glsafe(::glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
|
||||
GLint w = size.x(), h = face_names.names.size() * size.y();
|
||||
std::vector<unsigned char> data(w * h, {0});
|
||||
glsafe(::glTexImage2D(target, level, GL_ALPHA, w, h, border, format, type, data.data()));
|
||||
// bind default texture
|
||||
GLuint no_texture_id = 0;
|
||||
glsafe(::glBindTexture(target, no_texture_id));
|
||||
|
||||
// no one is initialized yet
|
||||
face_names.exist_textures = std::vector<bool>(face_names.names.size(), {false});
|
||||
};
|
||||
auto init_trancated_names = [&face_names = m_face_names,
|
||||
width = m_gui_cfg->face_name_max_width]() {
|
||||
if (!face_names.names_truncated.empty()) return;
|
||||
face_names.names_truncated.reserve(face_names.names.size());
|
||||
for (const wxString &face_name : face_names.names) {
|
||||
std::string name(face_name.ToUTF8().data());
|
||||
face_names.names_truncated.emplace_back(ImGuiWrapper::trunc(name, width));
|
||||
}
|
||||
};
|
||||
|
||||
// Set partial
|
||||
wxString actual_face_name;
|
||||
if (m_font_manager.is_activ_font()) {
|
||||
std::optional<wxFont> &wx_font_opt = m_font_manager.get_wx_font();
|
||||
@ -1326,18 +1363,44 @@ void GLGizmoEmboss::draw_font_list()
|
||||
wxString del_facename;
|
||||
if (ImGui::BeginCombo("##font_selector", selected)) {
|
||||
if (!m_face_names.is_init) init_face_names();
|
||||
init_texture();
|
||||
if (m_face_names.names_truncated.empty()) init_trancated_names();
|
||||
ImTextureID tex_id = (void *) (intptr_t) m_face_names.texture_id;
|
||||
for (const wxString &face_name : m_face_names.names) {
|
||||
size_t index = &face_name - &m_face_names.names.front();
|
||||
ImGui::PushID(index);
|
||||
bool is_selected = (actual_face_name == face_name);
|
||||
if (ImGui::Selectable(face_name.ToUTF8().data(), is_selected)) {
|
||||
if (ImGui::Selectable(m_face_names.names_truncated[index].c_str(), is_selected)) {
|
||||
if (!select_facename(face_name)) {
|
||||
del_facename = face_name;
|
||||
wxMessageBox(GUI::format(
|
||||
_L("Font face \"%1%\" can't be selected."), face_name));
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip(face_name.ToUTF8().data());
|
||||
if (is_selected) ImGui::SetItemDefaultFocus();
|
||||
if (!m_face_names.exist_textures[index] &&
|
||||
ImGui::IsItemVisible()) {
|
||||
m_face_names.exist_textures[index] = true;
|
||||
std::string text = m_text.empty() ? "AaBbCc" : m_text;
|
||||
// render text to texture
|
||||
FontImageData data{text,
|
||||
face_name,
|
||||
m_face_names.encoding,
|
||||
m_face_names.texture_id,
|
||||
index,
|
||||
m_gui_cfg->face_name_size};
|
||||
auto job = std::make_unique<CreateFontImageJob>(std::move(data));
|
||||
auto& worker = wxGetApp().plater()->get_ui_job_worker();
|
||||
queue_job(worker, std::move(job));
|
||||
}
|
||||
ImGui::SameLine(m_gui_cfg->face_name_offset);
|
||||
ImVec2 size(m_gui_cfg->face_name_size.x(),
|
||||
m_gui_cfg->face_name_size.y()),
|
||||
uv0(0.f, index / (float) m_face_names.names.size()),
|
||||
uv1(1.f, (index + 1) / (float) m_face_names.names.size());
|
||||
ImGui::Image(tex_id, size, uv0, uv1);
|
||||
ImGui::PopID();
|
||||
}
|
||||
#ifdef SHOW_FONT_COUNT
|
||||
@ -1345,6 +1408,10 @@ void GLGizmoEmboss::draw_font_list()
|
||||
static_cast<int>(m_face_names.names.size()));
|
||||
#endif // SHOW_FONT_COUNT
|
||||
ImGui::EndCombo();
|
||||
} else {
|
||||
// free texture and set id to zero
|
||||
glsafe(::glDeleteTextures(1, &m_face_names.texture_id));
|
||||
m_face_names.texture_id = 0;
|
||||
}
|
||||
|
||||
// delete unloadable face name when appear
|
||||
@ -1352,6 +1419,7 @@ void GLGizmoEmboss::draw_font_list()
|
||||
// IMPROVE: store list of deleted facename into app.ini
|
||||
std::vector<wxString> &f = m_face_names.names;
|
||||
f.erase(std::remove(f.begin(), f.end(), del_facename), f.end());
|
||||
m_face_names.names_truncated.clear();
|
||||
}
|
||||
|
||||
#ifdef ALLOW_ADD_FONT_BY_FILE
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "libslic3r/TextConfiguration.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include <GL/glew.h>
|
||||
|
||||
class wxFont;
|
||||
namespace Slic3r{
|
||||
@ -184,6 +185,11 @@ private:
|
||||
|
||||
ImVec2 text_size;
|
||||
|
||||
// maximal size of face image
|
||||
Vec2i face_name_size = Vec2i(128, 0);
|
||||
float face_name_max_width = 100.f;
|
||||
float face_name_offset = 100.f;
|
||||
|
||||
// Only translations needed for calc GUI size
|
||||
struct Translations
|
||||
{
|
||||
@ -220,6 +226,11 @@ private:
|
||||
bool is_init = false;
|
||||
std::vector<wxString> names;
|
||||
wxFontEncoding encoding;
|
||||
|
||||
std::vector<std::string> names_truncated;
|
||||
GLuint texture_id = 0;
|
||||
// is texture started create?
|
||||
std::vector<bool> exist_textures = {};
|
||||
} m_face_names;
|
||||
|
||||
// Track stored values in AppConfig
|
||||
|
114
src/slic3r/GUI/Jobs/CreateFontNameImageJob.cpp
Normal file
114
src/slic3r/GUI/Jobs/CreateFontNameImageJob.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
#include "CreateFontNameImageJob.hpp"
|
||||
|
||||
#include "libslic3r/Emboss.hpp"
|
||||
// rasterization of ExPoly
|
||||
#include "libslic3r/SLA/AGGRaster.hpp"
|
||||
|
||||
#include "slic3r/Utils/WxFontUtils.hpp"
|
||||
#include "slic3r/GUI/3DScene.hpp" // ::glsafe
|
||||
|
||||
#include "wx/fontenum.h"
|
||||
|
||||
using namespace Slic3r;
|
||||
using namespace Slic3r::GUI;
|
||||
|
||||
CreateFontImageJob::CreateFontImageJob(FontImageData &&input)
|
||||
: m_input(std::move(input))
|
||||
{
|
||||
assert(!m_input.text.empty());
|
||||
assert(wxFontEnumerator::IsValidFacename(m_input.font_name));
|
||||
assert(m_input.gray_level > 0 && m_input.gray_level < 255);
|
||||
assert(m_input.texture_id != 0);
|
||||
}
|
||||
|
||||
void CreateFontImageJob::process(Ctl &ctl)
|
||||
{
|
||||
if (!wxFontEnumerator::IsValidFacename(m_input.font_name)) return;
|
||||
// Select font
|
||||
wxFont wx_font(
|
||||
wxFontInfo().FaceName(m_input.font_name).Encoding(m_input.encoding));
|
||||
if (!wx_font.IsOk()) return;
|
||||
|
||||
std::unique_ptr<Emboss::FontFile> font_file =
|
||||
WxFontUtils::create_font_file(wx_font);
|
||||
if (font_file == nullptr) return;
|
||||
|
||||
Emboss::FontFileWithCache font_file_with_cache(std::move(font_file));
|
||||
FontProp fp;
|
||||
// use only first line of text
|
||||
std::string text = m_input.text;
|
||||
size_t enter_pos = text.find('\n');
|
||||
if (enter_pos < text.size()) {
|
||||
// text start with enter
|
||||
if (enter_pos == 0) return;
|
||||
// exist enter, soo delete all after enter
|
||||
text = text.substr(0, enter_pos);
|
||||
}
|
||||
|
||||
ExPolygons shapes = Emboss::text2shapes(font_file_with_cache,
|
||||
text.c_str(), fp);
|
||||
// normalize height of font
|
||||
BoundingBox bounding_box;
|
||||
for (ExPolygon &shape : shapes)
|
||||
bounding_box.merge(BoundingBox(shape.contour.points));
|
||||
if (bounding_box.size().x() < 1 || bounding_box.size().y() < 1) return;
|
||||
double scale = m_input.size.y() / (double) bounding_box.size().y();
|
||||
BoundingBoxf bb2(bounding_box.min.cast<double>(),
|
||||
bounding_box.max.cast<double>());
|
||||
bb2.scale(scale);
|
||||
Vec2d size_f = bb2.size();
|
||||
m_tex_size = Point(std::ceil(size_f.x()), std::ceil(size_f.y()));
|
||||
// crop image width
|
||||
if (m_tex_size.x() > m_input.size.x()) m_tex_size.x() = m_input.size.x();
|
||||
|
||||
// Set up result
|
||||
m_result = std::vector<unsigned char>(m_tex_size.x() * m_tex_size.y(), {0});
|
||||
|
||||
sla::Resolution resolution(m_tex_size.x(), m_tex_size.y());
|
||||
double pixel_dim = SCALING_FACTOR / scale;
|
||||
sla::PixelDim dim(pixel_dim, pixel_dim);
|
||||
double gamma = 1.;
|
||||
std::unique_ptr<sla::RasterBase> r =
|
||||
sla::create_raster_grayscale_aa(resolution, dim, gamma);
|
||||
for (ExPolygon &shape : shapes) shape.translate(-bounding_box.min);
|
||||
for (const ExPolygon &shape : shapes) r->draw(shape);
|
||||
|
||||
// copy rastered data to pixels
|
||||
sla::RasterEncoder encoder =
|
||||
[&pix = m_result, w = m_tex_size.x(), h = m_tex_size.y(),
|
||||
gray_level = m_input.gray_level]
|
||||
(const void *ptr, size_t width, size_t height, size_t num_components) {
|
||||
size_t size {static_cast<size_t>(w*h)};
|
||||
const unsigned char *ptr2 = (const unsigned char *) ptr;
|
||||
for (size_t x = 0; x < width; ++x)
|
||||
for (size_t y = 0; y < height; ++y) {
|
||||
size_t index = y*w + x;
|
||||
assert(index < size);
|
||||
if (index >= size) continue;
|
||||
pix[index] = ptr2[y * width + x] / gray_level;
|
||||
}
|
||||
return sla::EncodedRaster();
|
||||
};
|
||||
r->encode(encoder);
|
||||
}
|
||||
|
||||
void CreateFontImageJob::finalize(bool canceled, std::exception_ptr &)
|
||||
{
|
||||
if (canceled) return;
|
||||
|
||||
// upload texture on GPU
|
||||
GLuint tex_id;
|
||||
GLenum target = GL_TEXTURE_2D, format = GL_ALPHA, type = GL_UNSIGNED_BYTE;
|
||||
GLint level = 0, border = 0;
|
||||
glsafe(::glBindTexture(target, m_input.texture_id));
|
||||
|
||||
GLint
|
||||
w = m_tex_size.x(), h = m_tex_size.y(),
|
||||
xoffset = m_input.size.x() - m_tex_size.x(), // arrange right
|
||||
yoffset = m_input.size.y() * m_input.index;
|
||||
glsafe(::glTexSubImage2D(target, level, xoffset, yoffset, w, h, format, type, m_result.data()));
|
||||
|
||||
// bind default texture
|
||||
GLuint no_texture_id = 0;
|
||||
glsafe(::glBindTexture(target, no_texture_id));
|
||||
}
|
62
src/slic3r/GUI/Jobs/CreateFontNameImageJob.hpp
Normal file
62
src/slic3r/GUI/Jobs/CreateFontNameImageJob.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef slic3r_CreateFontNameImageJob_hpp_
|
||||
#define slic3r_CreateFontNameImageJob_hpp_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <GL/glew.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/fontenc.h>
|
||||
#include "Job.hpp"
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
/// <summary>
|
||||
/// Keep data for rasterization of text by font face
|
||||
/// </summary>
|
||||
struct FontImageData
|
||||
{
|
||||
// Text to rasterize
|
||||
std::string text;
|
||||
// Define font face
|
||||
wxString font_name;
|
||||
wxFontEncoding encoding;
|
||||
// texture for copy result to
|
||||
GLuint texture_id;
|
||||
// Index of face name, define place in texture
|
||||
size_t index;
|
||||
// Height of each text
|
||||
// And Limit for width
|
||||
Vec2i size; // in px
|
||||
|
||||
// bigger value create darker image
|
||||
// divide value 255
|
||||
unsigned char gray_level = 5;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create image for face name
|
||||
/// </summary>
|
||||
class CreateFontImageJob : public Job
|
||||
{
|
||||
FontImageData m_input;
|
||||
std::vector<unsigned char> m_result;
|
||||
Point m_tex_size;
|
||||
public:
|
||||
CreateFontImageJob(FontImageData &&input);
|
||||
/// <summary>
|
||||
/// Rasterize text into image (result)
|
||||
/// </summary>
|
||||
/// <param name="ctl">Check for cancelation</param>
|
||||
void process(Ctl &ctl) override;
|
||||
|
||||
/// <summary>
|
||||
/// Copy image data into OpenGL texture
|
||||
/// </summary>
|
||||
/// <param name="canceled"></param>
|
||||
/// <param name=""></param>
|
||||
void finalize(bool canceled, std::exception_ptr &);
|
||||
};
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
|
||||
#endif // slic3r_CreateFontNameImageJob_hpp_
|
@ -9,7 +9,6 @@
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create texture with name of styles written by its style
|
||||
/// NOTE: Access to glyph cache is possible only from job
|
||||
@ -34,4 +33,4 @@ public:
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
|
||||
#endif // slic3r_EmbossJob_hpp_
|
||||
#endif // slic3r_CreateFontStyleImagesJob_hpp_
|
||||
|
Loading…
Reference in New Issue
Block a user