mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-13 03:11:47 +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 "libslic3r.h"
|
||||
|
||||
#include "ClipperUtils.hpp" // for boldness - polygon extend(offset)
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
double Emboss::SHAPE_SCALE = 0.001;//SCALING_FACTOR;
|
||||
@ -541,8 +544,11 @@ ExPolygons Emboss::text2shapes(Font & font,
|
||||
std::wstring ws = boost::nowide::widen(text);
|
||||
for (wchar_t wc: ws){
|
||||
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.y() -= (font.ascent - font.descent + font.linegap + font_prop.line_gap) / SHAPE_SCALE;
|
||||
cursor.y() -= static_cast<int>(line_height / SHAPE_SCALE);
|
||||
continue;
|
||||
}
|
||||
if (wc == '\t') {
|
||||
@ -550,7 +556,10 @@ ExPolygons Emboss::text2shapes(Font & font,
|
||||
const int count_spaces = 4;
|
||||
std::optional<Glyph> space_opt = Private::get_glyph(int(' '), font, font_prop, font.cache, font_info_opt);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -562,7 +571,30 @@ ExPolygons Emboss::text2shapes(Font & font,
|
||||
ExPolygons expolygons = glyph_opt->shape; // copy
|
||||
for (ExPolygon &expolygon : expolygons)
|
||||
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);
|
||||
}
|
||||
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_HEIGHT_ATTR = "line_height";
|
||||
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_FACE_NAME_ATTR = "face_name";
|
||||
@ -3254,10 +3256,18 @@ void TextConfigurationSerialization::to_xml(std::stringstream &stream, const Tex
|
||||
|
||||
// font property
|
||||
const FontProp &fp = tc.font_prop;
|
||||
stream << CHAR_GAP_ATTR << "=\"" << fp.char_gap << "\" ";
|
||||
stream << LINE_GAP_ATTR << "=\"" << fp.line_gap << "\" ";
|
||||
if (fp.char_gap.has_value())
|
||||
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 << 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
|
||||
if (fp.family.has_value())
|
||||
stream << FONT_FAMILY_ATTR << "=\"" << *fp.family << "\" ";
|
||||
@ -3280,8 +3290,17 @@ std::optional<TextConfiguration> TextConfigurationSerialization::read(const char
|
||||
FontItem fi(font_name, font_descriptor, type);
|
||||
|
||||
FontProp fp;
|
||||
fp.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);
|
||||
int char_gap = get_attribute_value_int(attributes, num_attributes, CHAR_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.emboss = get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR);
|
||||
|
||||
|
@ -38,11 +38,20 @@ using FontList = std::vector<FontItem>;
|
||||
struct FontProp
|
||||
{
|
||||
// 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
|
||||
int line_gap = 0;
|
||||
std::optional<int> line_gap = 0;
|
||||
// Z depth of text [in mm]
|
||||
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
|
||||
|
||||
//////
|
||||
|
@ -423,7 +423,7 @@ void GLGizmoEmboss::initialize()
|
||||
m_gui_cfg->text_size.y +
|
||||
style.WindowPadding.y * 2.f;
|
||||
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 =
|
||||
ImVec2(window_width, window_height + advance_height);
|
||||
|
||||
@ -765,13 +765,21 @@ void GLGizmoEmboss::draw_advanced()
|
||||
ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width);
|
||||
if (ImGui::InputFloat(_u8L("Emboss[in mm]").c_str(), &m_font_prop.emboss))
|
||||
process();
|
||||
ImGui::SetNextItemWidth(2*m_gui_cfg->advanced_input_width);
|
||||
if (ImGui::InputInt(_u8L("CharGap[in font points]").c_str(),
|
||||
&m_font_prop.char_gap))
|
||||
|
||||
ImGui::SetNextItemWidth(2 * m_gui_cfg->advanced_input_width);
|
||||
if(ImGuiWrapper::input_optional_int(_u8L("CharGap[in font points]").c_str(), m_font_prop.char_gap))
|
||||
process();
|
||||
|
||||
ImGui::SetNextItemWidth(2*m_gui_cfg->advanced_input_width);
|
||||
if (ImGui::InputInt(_u8L("LineGap[in font points]").c_str(),
|
||||
&m_font_prop.line_gap))
|
||||
if (ImGuiWrapper::input_optional_int(_u8L("LineGap[in font points]").c_str(), 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();
|
||||
|
||||
// when more collection add selector
|
||||
@ -793,6 +801,7 @@ void GLGizmoEmboss::draw_advanced()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef ALLOW_DEBUG_MODE
|
||||
std::string descriptor = m_font_list[m_font_selected].path;
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
float width,
|
||||
const char * tail)
|
||||
|
@ -128,6 +128,12 @@ public:
|
||||
bool want_text_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>
|
||||
/// Truncate text by ImGui draw function to specific width
|
||||
/// NOTE 1: ImGui must be initialized
|
||||
|
Loading…
x
Reference in New Issue
Block a user