mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-13 03:01:48 +08:00
Add boldness and skew(italic) for embossed text
Change line_gap and char_gap to optional value
This commit is contained in:
parent
7b70083c78
commit
82ee1c5e4a
@ -9,6 +9,9 @@
|
|||||||
|
|
||||||
#include <Triangulation.hpp> // CGAL project
|
#include <Triangulation.hpp> // CGAL project
|
||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
|
|
||||||
|
#include "ClipperUtils.hpp" // for boldness - polygon extend(offset)
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
|
|
||||||
double Emboss::SHAPE_SCALE = 0.001;//SCALING_FACTOR;
|
double Emboss::SHAPE_SCALE = 0.001;//SCALING_FACTOR;
|
||||||
@ -541,8 +544,11 @@ ExPolygons Emboss::text2shapes(Font & font,
|
|||||||
std::wstring ws = boost::nowide::widen(text);
|
std::wstring ws = boost::nowide::widen(text);
|
||||||
for (wchar_t wc: ws){
|
for (wchar_t wc: ws){
|
||||||
if (wc == '\n') {
|
if (wc == '\n') {
|
||||||
|
int line_height = font.ascent - font.descent + font.linegap;
|
||||||
|
if (font_prop.line_gap.has_value())
|
||||||
|
line_height += *font_prop.line_gap;
|
||||||
cursor.x() = 0;
|
cursor.x() = 0;
|
||||||
cursor.y() -= (font.ascent - font.descent + font.linegap + font_prop.line_gap) / SHAPE_SCALE;
|
cursor.y() -= static_cast<int>(line_height / SHAPE_SCALE);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (wc == '\t') {
|
if (wc == '\t') {
|
||||||
@ -550,7 +556,10 @@ ExPolygons Emboss::text2shapes(Font & font,
|
|||||||
const int count_spaces = 4;
|
const int count_spaces = 4;
|
||||||
std::optional<Glyph> space_opt = Private::get_glyph(int(' '), font, font_prop, font.cache, font_info_opt);
|
std::optional<Glyph> space_opt = Private::get_glyph(int(' '), font, font_prop, font.cache, font_info_opt);
|
||||||
if (!space_opt.has_value()) continue;
|
if (!space_opt.has_value()) continue;
|
||||||
cursor.x() += (count_spaces *(space_opt->advance_width + font_prop.char_gap)) / SHAPE_SCALE;
|
int width = space_opt->advance_width;
|
||||||
|
if (font_prop.char_gap.has_value())
|
||||||
|
width += *font_prop.char_gap;
|
||||||
|
cursor.x() += static_cast<int>((count_spaces * width) / SHAPE_SCALE);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,7 +571,30 @@ ExPolygons Emboss::text2shapes(Font & font,
|
|||||||
ExPolygons expolygons = glyph_opt->shape; // copy
|
ExPolygons expolygons = glyph_opt->shape; // copy
|
||||||
for (ExPolygon &expolygon : expolygons)
|
for (ExPolygon &expolygon : expolygons)
|
||||||
expolygon.translate(cursor);
|
expolygon.translate(cursor);
|
||||||
cursor.x() += (glyph_opt->advance_width + font_prop.char_gap) / SHAPE_SCALE;
|
|
||||||
|
if (font_prop.boldness.has_value()) {
|
||||||
|
float delta = *font_prop.boldness / SHAPE_SCALE;
|
||||||
|
expolygons = offset_ex(expolygons, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font_prop.skew.has_value()) {
|
||||||
|
const float& ratio = *font_prop.skew;
|
||||||
|
auto skew = [&ratio](Polygon &polygon) {
|
||||||
|
for (Point &p : polygon.points) {
|
||||||
|
p.x() += p.y() * ratio;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (ExPolygon &expolygon : expolygons) {
|
||||||
|
skew(expolygon.contour);
|
||||||
|
for (Polygon &hole : expolygon.holes)
|
||||||
|
skew(hole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = glyph_opt->advance_width;
|
||||||
|
if (font_prop.char_gap.has_value())
|
||||||
|
width += *font_prop.char_gap;
|
||||||
|
cursor.x() += static_cast<int>(width / SHAPE_SCALE);
|
||||||
expolygons_append(result, expolygons);
|
expolygons_append(result, expolygons);
|
||||||
}
|
}
|
||||||
result = Slic3r::union_ex(result);
|
result = Slic3r::union_ex(result);
|
||||||
|
@ -156,6 +156,8 @@ static constexpr const char *CHAR_GAP_ATTR = "char_gap";
|
|||||||
static constexpr const char *LINE_GAP_ATTR = "line_gap";
|
static constexpr const char *LINE_GAP_ATTR = "line_gap";
|
||||||
static constexpr const char *LINE_HEIGHT_ATTR = "line_height";
|
static constexpr const char *LINE_HEIGHT_ATTR = "line_height";
|
||||||
static constexpr const char *DEPTH_ATTR = "depth";
|
static constexpr const char *DEPTH_ATTR = "depth";
|
||||||
|
static constexpr const char *BOLDNESS_ATTR = "boldness";
|
||||||
|
static constexpr const char *SKEW_ATTR = "skew";
|
||||||
|
|
||||||
static constexpr const char *FONT_FAMILY_ATTR = "family";
|
static constexpr const char *FONT_FAMILY_ATTR = "family";
|
||||||
static constexpr const char *FONT_FACE_NAME_ATTR = "face_name";
|
static constexpr const char *FONT_FACE_NAME_ATTR = "face_name";
|
||||||
@ -3254,10 +3256,18 @@ void TextConfigurationSerialization::to_xml(std::stringstream &stream, const Tex
|
|||||||
|
|
||||||
// font property
|
// font property
|
||||||
const FontProp &fp = tc.font_prop;
|
const FontProp &fp = tc.font_prop;
|
||||||
stream << CHAR_GAP_ATTR << "=\"" << fp.char_gap << "\" ";
|
if (fp.char_gap.has_value())
|
||||||
stream << LINE_GAP_ATTR << "=\"" << fp.line_gap << "\" ";
|
stream << CHAR_GAP_ATTR << "=\"" << *fp.char_gap << "\" ";
|
||||||
|
if (fp.line_gap.has_value())
|
||||||
|
stream << LINE_GAP_ATTR << "=\"" << *fp.line_gap << "\" ";
|
||||||
|
|
||||||
stream << LINE_HEIGHT_ATTR << "=\"" << fp.size_in_mm << "\" ";
|
stream << LINE_HEIGHT_ATTR << "=\"" << fp.size_in_mm << "\" ";
|
||||||
stream << DEPTH_ATTR << "=\"" << fp.emboss << "\" ";
|
stream << DEPTH_ATTR << "=\"" << fp.emboss << "\" ";
|
||||||
|
if (fp.boldness.has_value())
|
||||||
|
stream << BOLDNESS_ATTR << "=\"" << *fp.boldness << "\" ";
|
||||||
|
if (fp.skew.has_value())
|
||||||
|
stream << SKEW_ATTR << "=\"" << *fp.skew << "\" ";
|
||||||
|
|
||||||
// font descriptor
|
// font descriptor
|
||||||
if (fp.family.has_value())
|
if (fp.family.has_value())
|
||||||
stream << FONT_FAMILY_ATTR << "=\"" << *fp.family << "\" ";
|
stream << FONT_FAMILY_ATTR << "=\"" << *fp.family << "\" ";
|
||||||
@ -3280,8 +3290,17 @@ std::optional<TextConfiguration> TextConfigurationSerialization::read(const char
|
|||||||
FontItem fi(font_name, font_descriptor, type);
|
FontItem fi(font_name, font_descriptor, type);
|
||||||
|
|
||||||
FontProp fp;
|
FontProp fp;
|
||||||
fp.char_gap = get_attribute_value_int(attributes, num_attributes, CHAR_GAP_ATTR);
|
int char_gap = get_attribute_value_int(attributes, num_attributes, CHAR_GAP_ATTR);
|
||||||
fp.line_gap = get_attribute_value_int(attributes, num_attributes, LINE_GAP_ATTR);
|
if (char_gap != 0) fp.char_gap = char_gap;
|
||||||
|
int line_gap = get_attribute_value_int(attributes, num_attributes, LINE_GAP_ATTR);
|
||||||
|
if (line_gap != 0) fp.line_gap = line_gap;
|
||||||
|
float boldness = get_attribute_value_float(attributes, num_attributes, BOLDNESS_ATTR);
|
||||||
|
if (std::fabs(boldness) > std::numeric_limits<float>::epsilon())
|
||||||
|
fp.boldness = boldness;
|
||||||
|
float skew = get_attribute_value_float(attributes, num_attributes, SKEW_ATTR);
|
||||||
|
if (std::fabs(skew) > std::numeric_limits<float>::epsilon())
|
||||||
|
fp.skew = skew;
|
||||||
|
|
||||||
fp.size_in_mm = get_attribute_value_float(attributes, num_attributes, LINE_HEIGHT_ATTR);
|
fp.size_in_mm = get_attribute_value_float(attributes, num_attributes, LINE_HEIGHT_ATTR);
|
||||||
fp.emboss = get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR);
|
fp.emboss = get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR);
|
||||||
|
|
||||||
|
@ -38,11 +38,20 @@ using FontList = std::vector<FontItem>;
|
|||||||
struct FontProp
|
struct FontProp
|
||||||
{
|
{
|
||||||
// define extra space between letters, negative mean closer letter
|
// define extra space between letters, negative mean closer letter
|
||||||
int char_gap = 0;
|
std::optional<int> char_gap = 0;
|
||||||
// define extra space between lines, negative mean closer lines
|
// define extra space between lines, negative mean closer lines
|
||||||
int line_gap = 0;
|
std::optional<int> line_gap = 0;
|
||||||
// Z depth of text [in mm]
|
// Z depth of text [in mm]
|
||||||
float emboss = 5;
|
float emboss = 5;
|
||||||
|
|
||||||
|
// positive value mean wider character shape
|
||||||
|
// negative value mean tiner character shape
|
||||||
|
std::optional<float> boldness = 0.f; // [in mm]
|
||||||
|
|
||||||
|
// positive value mean italic of character (CW)
|
||||||
|
// negative value mean CCW skew (unItalic)
|
||||||
|
std::optional<float> skew = 0.f;
|
||||||
|
|
||||||
// TODO: add enum class Align: center/left/right
|
// TODO: add enum class Align: center/left/right
|
||||||
|
|
||||||
//////
|
//////
|
||||||
|
@ -423,7 +423,7 @@ void GLGizmoEmboss::initialize()
|
|||||||
m_gui_cfg->text_size.y +
|
m_gui_cfg->text_size.y +
|
||||||
style.WindowPadding.y * 2.f;
|
style.WindowPadding.y * 2.f;
|
||||||
m_gui_cfg->minimal_window_size = ImVec2(window_width, window_height);
|
m_gui_cfg->minimal_window_size = ImVec2(window_width, window_height);
|
||||||
float advance_height = (input_height + style.ItemSpacing.y) * 4.f;
|
float advance_height = (input_height + style.ItemSpacing.y) * 6.f;
|
||||||
m_gui_cfg->minimal_window_size_with_advance =
|
m_gui_cfg->minimal_window_size_with_advance =
|
||||||
ImVec2(window_width, window_height + advance_height);
|
ImVec2(window_width, window_height + advance_height);
|
||||||
|
|
||||||
@ -765,13 +765,21 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width);
|
ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width);
|
||||||
if (ImGui::InputFloat(_u8L("Emboss[in mm]").c_str(), &m_font_prop.emboss))
|
if (ImGui::InputFloat(_u8L("Emboss[in mm]").c_str(), &m_font_prop.emboss))
|
||||||
process();
|
process();
|
||||||
ImGui::SetNextItemWidth(2*m_gui_cfg->advanced_input_width);
|
|
||||||
if (ImGui::InputInt(_u8L("CharGap[in font points]").c_str(),
|
ImGui::SetNextItemWidth(2 * m_gui_cfg->advanced_input_width);
|
||||||
&m_font_prop.char_gap))
|
if(ImGuiWrapper::input_optional_int(_u8L("CharGap[in font points]").c_str(), m_font_prop.char_gap))
|
||||||
process();
|
process();
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(2*m_gui_cfg->advanced_input_width);
|
ImGui::SetNextItemWidth(2*m_gui_cfg->advanced_input_width);
|
||||||
if (ImGui::InputInt(_u8L("LineGap[in font points]").c_str(),
|
if (ImGuiWrapper::input_optional_int(_u8L("LineGap[in font points]").c_str(), m_font_prop.line_gap))
|
||||||
&m_font_prop.line_gap))
|
process();
|
||||||
|
|
||||||
|
ImGui::SetNextItemWidth(2 * m_gui_cfg->advanced_input_width);
|
||||||
|
if (m_imgui->slider_optional_float(_u8L("Boldness[in font points]").c_str(), m_font_prop.boldness, -200.f, 200.f, "%.0f", 1.f, false, _L("tiny / wide chars")))
|
||||||
|
process();
|
||||||
|
|
||||||
|
ImGui::SetNextItemWidth(2 * m_gui_cfg->advanced_input_width);
|
||||||
|
if (m_imgui->slider_optional_float(_u8L("Skew ratio").c_str(), m_font_prop.skew, -1.f, 1.f, "%.2f", 1.f, false, _L("italic strength")))
|
||||||
process();
|
process();
|
||||||
|
|
||||||
// when more collection add selector
|
// when more collection add selector
|
||||||
@ -793,6 +801,7 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef ALLOW_DEBUG_MODE
|
#ifdef ALLOW_DEBUG_MODE
|
||||||
std::string descriptor = m_font_list[m_font_selected].path;
|
std::string descriptor = m_font_list[m_font_selected].path;
|
||||||
ImGui::Text("family = %s", (m_font_prop.family.has_value() ?
|
ImGui::Text("family = %s", (m_font_prop.family.has_value() ?
|
||||||
|
@ -1041,6 +1041,93 @@ bool ImGuiWrapper::want_any_input() const
|
|||||||
return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput;
|
return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Func>
|
||||||
|
static bool input_optional(std::optional<T> &v, Func& f, std::function<bool(const T&)> is_default)
|
||||||
|
{
|
||||||
|
if (v.has_value()) {
|
||||||
|
if (f(*v)) {
|
||||||
|
if (is_default(*v)) v.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
T val = 0;
|
||||||
|
if (f(val)) {
|
||||||
|
if (!is_default(val)) v = val;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGuiWrapper::input_optional_int(const char * label,
|
||||||
|
std::optional<int>& v,
|
||||||
|
int step,
|
||||||
|
int step_fast,
|
||||||
|
ImGuiInputTextFlags flags)
|
||||||
|
{
|
||||||
|
auto func = [&](int &value) {
|
||||||
|
return ImGui::InputInt(label, &value, step, step_fast, flags);
|
||||||
|
};
|
||||||
|
std::function<bool(const int &)> is_default =
|
||||||
|
[](const int &value) -> bool { return value == 0; };
|
||||||
|
return input_optional(v, func, is_default);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGuiWrapper::input_optional_float(const char * label,
|
||||||
|
std::optional<float> &v,
|
||||||
|
float step,
|
||||||
|
float step_fast,
|
||||||
|
const char * format,
|
||||||
|
ImGuiInputTextFlags flags)
|
||||||
|
{
|
||||||
|
auto func = [&](float &value) {
|
||||||
|
return ImGui::InputFloat(label, &value, step, step_fast, format, flags);
|
||||||
|
};
|
||||||
|
std::function<bool(const float &)> is_default =
|
||||||
|
[](const float &value) -> bool {
|
||||||
|
return std::fabs(value) < std::numeric_limits<float>::epsilon();
|
||||||
|
};
|
||||||
|
return input_optional(v, func, is_default);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGuiWrapper::drag_optional_float(const char * label,
|
||||||
|
std::optional<float> &v,
|
||||||
|
float v_speed,
|
||||||
|
float v_min,
|
||||||
|
float v_max,
|
||||||
|
const char * format,
|
||||||
|
float power)
|
||||||
|
{
|
||||||
|
auto func = [&](float &value) {
|
||||||
|
return ImGui::DragFloat(label, &value, v_speed, v_min, v_max, format, power);
|
||||||
|
};
|
||||||
|
std::function<bool(const float &)> is_default =
|
||||||
|
[](const float &value) -> bool {
|
||||||
|
return std::fabs(value) < std::numeric_limits<float>::epsilon();
|
||||||
|
};
|
||||||
|
return input_optional(v, func, is_default);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGuiWrapper::slider_optional_float(const char * label,
|
||||||
|
std::optional<float> &v,
|
||||||
|
float v_min,
|
||||||
|
float v_max,
|
||||||
|
const char * format,
|
||||||
|
float power,
|
||||||
|
bool clamp,
|
||||||
|
const wxString & tooltip,
|
||||||
|
bool show_edit_btn)
|
||||||
|
{
|
||||||
|
auto func = [&](float &value) {
|
||||||
|
return slider_float(label, &value, v_min, v_max, format, power, clamp, tooltip, show_edit_btn);
|
||||||
|
};
|
||||||
|
std::function<bool(const float &)> is_default =
|
||||||
|
[](const float &value) -> bool {
|
||||||
|
return std::fabs(value) < std::numeric_limits<float>::epsilon();
|
||||||
|
};
|
||||||
|
return input_optional(v, func, is_default);
|
||||||
|
}
|
||||||
|
|
||||||
std::string ImGuiWrapper::trunc(const std::string &text,
|
std::string ImGuiWrapper::trunc(const std::string &text,
|
||||||
float width,
|
float width,
|
||||||
const char * tail)
|
const char * tail)
|
||||||
|
@ -128,6 +128,12 @@ public:
|
|||||||
bool want_text_input() const;
|
bool want_text_input() const;
|
||||||
bool want_any_input() const;
|
bool want_any_input() const;
|
||||||
|
|
||||||
|
// Input [optional] int for nonzero value more info in ImGui::InputInt
|
||||||
|
static bool input_optional_int(const char *label, std::optional<int>& v, int step=1, int step_fast=100, ImGuiInputTextFlags flags=0);
|
||||||
|
// Input [optional] float for nonzero value more info in ImGui::InputFloat
|
||||||
|
static bool input_optional_float(const char* label, std::optional<float> &v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0);
|
||||||
|
static bool drag_optional_float(const char* label, std::optional<float> &v, float v_speed, float v_min, float v_max, const char* format, float power);
|
||||||
|
bool slider_optional_float(const char* label, std::optional<float> &v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = {}, bool show_edit_btn = true);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Truncate text by ImGui draw function to specific width
|
/// Truncate text by ImGui draw function to specific width
|
||||||
/// NOTE 1: ImGui must be initialized
|
/// NOTE 1: ImGui must be initialized
|
||||||
|
Loading…
x
Reference in New Issue
Block a user