diff options
| -rw-r--r-- | lib/gui/lettering/main_panel.py | 8 | ||||
| -rw-r--r-- | lib/gui/lettering/option_panel.py | 98 | ||||
| -rw-r--r-- | lib/lettering/font.py | 33 |
3 files changed, 93 insertions, 46 deletions
diff --git a/lib/gui/lettering/main_panel.py b/lib/gui/lettering/main_panel.py index f47e6db5..62f5da31 100644 --- a/lib/gui/lettering/main_panel.py +++ b/lib/gui/lettering/main_panel.py @@ -77,6 +77,7 @@ class LetteringPanel(wx.Panel): self.settings = DotDict({ "text": "", + "text_align": 0, "back_and_forth": False, "font": None, "scale": 100, @@ -99,6 +100,7 @@ class LetteringPanel(wx.Panel): def apply_settings(self): """Make the settings in self.settings visible in the UI.""" + self.options_panel.align_text_choice.SetSelection(self.settings.text_align) self.options_panel.color_sort_choice.SetSelection(self.settings.color_sort) self.options_panel.back_and_forth_checkbox.SetValue(bool(self.settings.back_and_forth)) self.options_panel.trim_option_choice.SetSelection(self.settings.trim_option) @@ -201,8 +203,8 @@ class LetteringPanel(wx.Panel): self.settings.color_sort = 0 self.update_preview() - def on_trim_option_change(self, event=None): - self.settings.trim_option = self.options_panel.trim_option_choice.GetCurrentSelection() + def on_choice_change(self, attribute, event=None): + self.settings[attribute] = event.GetEventObject().GetCurrentSelection() self.update_preview() def on_font_changed(self, event=None): @@ -303,7 +305,7 @@ class LetteringPanel(wx.Panel): font.render_text( self.settings.text, destination_group, back_and_forth=self.settings.back_and_forth, trim_option=self.settings.trim_option, use_trim_symbols=self.settings.use_trim_symbols, - color_sort=self.settings.color_sort + color_sort=self.settings.color_sort, text_align=self.settings.text_align ) except FontError as e: if raise_error: diff --git a/lib/gui/lettering/option_panel.py b/lib/gui/lettering/option_panel.py index 542408d6..fe35f9ac 100644 --- a/lib/gui/lettering/option_panel.py +++ b/lib/gui/lettering/option_panel.py @@ -11,6 +11,36 @@ class LetteringOptionsPanel(wx.Panel): outer_sizer = wx.BoxSizer(wx.VERTICAL) + # filter font list + self.font_size_filter = wx.SpinCtrlDouble(self, min=0, max=100, inc=0.1, initial=0, style=wx.SP_WRAP) + self.font_size_filter.SetDigits(2) + self.font_size_filter.Bind(wx.EVT_SPINCTRLDOUBLE, self.panel.on_filter_changed) + self.font_size_filter.SetToolTip(_("Font size filter (mm). 0 for all sizes.")) + + self.font_glyph_filter = wx.CheckBox(self, label=_("Glyphs")) + self.font_glyph_filter.Bind(wx.EVT_CHECKBOX, self.panel.on_filter_changed) + self.font_glyph_filter.SetToolTip(_("Filter fonts by available glyphs.")) + + self.font_category_filter = wx.ComboBox(self, wx.ID_ANY, choices=[], style=wx.CB_DROPDOWN | wx.CB_READONLY) + unfiltered = FontCategory('unfiltered', "---") + self.font_category_filter.Append(unfiltered.name, unfiltered) + for category in FONT_CATEGORIES: + self.font_category_filter.Append(category.name, category) + self.font_category_filter.SetToolTip(_("Filter fonts by category.")) + self.font_category_filter.SetSelection(0) + self.font_category_filter.Bind(wx.EVT_COMBOBOX, self.panel.on_filter_changed) + + self.filter_box = wx.StaticBox(self, wx.ID_ANY, label=_("Font Filter")) + filter_sizer = wx.StaticBoxSizer(self.filter_box, wx.HORIZONTAL) + filter_size_label = wx.StaticText(self, wx.ID_ANY, _("Size")) + filter_sizer.Add(filter_size_label, 0, wx.LEFT | wx.TOP | wx.BOTTOM, 10) + filter_sizer.AddSpacer(5) + filter_sizer.Add(self.font_size_filter, 1, wx.RIGHT | wx.TOP | wx.BOTTOM, 10) + filter_sizer.AddSpacer(5) + filter_sizer.Add(self.font_glyph_filter, 1, wx.RIGHT | wx.TOP | wx.BOTTOM, 10) + filter_sizer.Add(self.font_category_filter, 1, wx.RIGHT | wx.TOP | wx.BOTTOM, 10) + outer_sizer.Add(filter_sizer, 0, wx.EXPAND | wx.LEFT | wx.TOP | wx.RIGHT, 10) + # font selection self.font_chooser = wx.adv.BitmapComboBox(self, wx.ID_ANY, style=wx.CB_READONLY | wx.CB_SORT) self.font_chooser.Bind(wx.EVT_COMBOBOX, self.panel.on_font_changed) @@ -46,36 +76,6 @@ class LetteringOptionsPanel(wx.Panel): font_selector_sizer.Add(font_description_sizer, 1, wx.EXPAND | wx.ALL, 10) outer_sizer.Add(font_selector_sizer, 0, wx.EXPAND | wx.LEFT | wx.TOP | wx.RIGHT, 10) - # filter font list - self.font_size_filter = wx.SpinCtrlDouble(self, min=0, max=100, inc=0.1, initial=0, style=wx.SP_WRAP) - self.font_size_filter.SetDigits(2) - self.font_size_filter.Bind(wx.EVT_SPINCTRLDOUBLE, self.panel.on_filter_changed) - self.font_size_filter.SetToolTip(_("Font size filter (mm). 0 for all sizes.")) - - self.font_glyph_filter = wx.CheckBox(self, label=_("Glyphs")) - self.font_glyph_filter.Bind(wx.EVT_CHECKBOX, self.panel.on_filter_changed) - self.font_glyph_filter.SetToolTip(_("Filter fonts by available glyphs.")) - - self.font_category_filter = wx.ComboBox(self, wx.ID_ANY, choices=[], style=wx.CB_DROPDOWN | wx.CB_READONLY) - unfiltered = FontCategory('unfiltered', "---") - self.font_category_filter.Append(unfiltered.name, unfiltered) - for category in FONT_CATEGORIES: - self.font_category_filter.Append(category.name, category) - self.font_category_filter.SetToolTip(_("Filter fonts by category.")) - self.font_category_filter.SetSelection(0) - self.font_category_filter.Bind(wx.EVT_COMBOBOX, self.panel.on_filter_changed) - - self.filter_box = wx.StaticBox(self, wx.ID_ANY, label=_("Font Filter")) - filter_sizer = wx.StaticBoxSizer(self.filter_box, wx.HORIZONTAL) - filter_size_label = wx.StaticText(self, wx.ID_ANY, _("Size")) - filter_sizer.Add(filter_size_label, 0, wx.LEFT | wx.TOP | wx.BOTTOM, 10) - filter_sizer.AddSpacer(5) - filter_sizer.Add(self.font_size_filter, 1, wx.RIGHT | wx.TOP | wx.BOTTOM, 10) - filter_sizer.AddSpacer(5) - filter_sizer.Add(self.font_glyph_filter, 1, wx.RIGHT | wx.TOP | wx.BOTTOM, 10) - filter_sizer.Add(self.font_category_filter, 1, wx.RIGHT | wx.TOP | wx.BOTTOM, 10) - outer_sizer.Add(filter_sizer, 0, wx.EXPAND | wx.LEFT | wx.TOP | wx.RIGHT, 10) - # options self.scale_spinner = wx.SpinCtrl(self, wx.ID_ANY, min=0, max=1000, initial=100) self.scale_spinner.Bind(wx.EVT_SPINCTRL, lambda event: self.panel.on_change("scale", event)) @@ -83,15 +83,23 @@ class LetteringOptionsPanel(wx.Panel): self.back_and_forth_checkbox = wx.CheckBox(self, label=_("Stitch lines of text back and forth")) self.back_and_forth_checkbox.Bind(wx.EVT_CHECKBOX, lambda event: self.panel.on_change("back_and_forth", event)) + align_text_label = wx.StaticText(self, wx.ID_ANY, _("Align Text")) + self.align_text_choice = wx.Choice( + self, + choices=[_("Left"), _("Center"), _("Right"), _("Block (default)"), _("Block (letterspacing)")] + ) + self.align_text_choice.Bind(wx.EVT_CHOICE, lambda event: self.panel.on_choice_change("text_align", event)) + color_sort_label = wx.StaticText(self, wx.ID_ANY, _("Color sort")) color_sort_label.SetToolTip(_("Sort multicolor fonts. Unifies tartan patterns.")) self.color_sort_choice = wx.Choice(self, choices=[_("Off"), _("Whole text"), _("Line"), _("Word")], name=_("Color sort")) self.color_sort_choice.SetToolTip(_("Sort multicolor fonts. Unifies tartan patterns.")) self.color_sort_choice.Bind(wx.EVT_CHOICE, self.panel.on_color_sort_change) + trim_label = wx.StaticText(self, wx.ID_ANY, _("Add trims")) self.trim_option_choice = wx.Choice(self, choices=[_("Never"), _("after each line"), _("after each word"), _("after each letter")], name=_("Add trim command")) - self.trim_option_choice.Bind(wx.EVT_CHOICE, lambda event: self.panel.on_trim_option_change(event)) + self.trim_option_choice.Bind(wx.EVT_CHOICE, lambda event: self.panel.on_choice_change("trim_option", event)) self.use_trim_symbols = wx.CheckBox(self, label=_("Use command symbols")) self.use_trim_symbols.Bind(wx.EVT_CHECKBOX, lambda event: self.panel.on_change("use_trim_symbols", event)) @@ -103,25 +111,33 @@ class LetteringOptionsPanel(wx.Panel): font_scale_sizer.Add(wx.StaticText(self, wx.ID_ANY, _("Scale")), 0, wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, 0) font_scale_sizer.Add(self.scale_spinner, 0, wx.LEFT, 10) font_scale_sizer.Add(wx.StaticText(self, wx.ID_ANY, "%"), 0, wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, 3) - left_option_sizer.Add(font_scale_sizer, 0, wx.ALIGN_LEFT, 5) + left_option_sizer.Add(font_scale_sizer, 0, wx.ALL, 5) left_option_sizer.Add(self.back_and_forth_checkbox, 1, wx.LEFT | wx.TOP | wx.RIGHT, 5) + align_sizer = wx.BoxSizer(wx.HORIZONTAL) + align_sizer.Add(align_text_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) + align_sizer.Add(self.align_text_choice, 0, wx.ALL, 5) + left_option_sizer.Add(align_sizer, 0, wx.ALL, 5) + + right_option_sizer = wx.BoxSizer(wx.VERTICAL) + color_sort_sizer = wx.BoxSizer(wx.HORIZONTAL) - color_sort_sizer.Add(color_sort_label, 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5) + color_sort_sizer.Add(color_sort_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) color_sort_sizer.Add(self.color_sort_choice, 1, wx.ALL, 5) - left_option_sizer.Add(color_sort_sizer, 0, wx.ALIGN_LEFT, 5) + right_option_sizer.Add(color_sort_sizer, 0, wx.ALIGN_LEFT, 5) - right_option_sizer = wx.BoxSizer(wx.VERTICAL) + trim_sizer = wx.BoxSizer(wx.HORIZONTAL) + trim_sizer.Add(trim_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) + trim_sizer.Add(self.trim_option_choice, 0, wx.ALL, 5) + right_option_sizer.Add(trim_sizer, 0, wx.EXPAND | wx.LEFT | wx.TOP | wx.RIGHT, 5) - right_option_sizer.Add(wx.StaticText(self, wx.ID_ANY, _("Add trims")), 0, wx.LEFT | wx.ALIGN_TOP, 5) - right_option_sizer.Add(self.trim_option_choice, 1, wx.EXPAND | wx.ALL, 5) - right_option_sizer.Add(self.use_trim_symbols, 1, wx.EXPAND | wx.ALL, 5) + right_option_sizer.Add(self.use_trim_symbols, 0, wx.LEFT | wx.BOTTOM | wx.RIGHT, 5) self.options_box = wx.StaticBox(self, wx.ID_ANY, label=_("Options")) options_sizer = wx.StaticBoxSizer(self.options_box, wx.HORIZONTAL) - options_sizer.Add(left_option_sizer, 1, wx.LEFT | wx.RIGHT, 10) - options_sizer.Add(right_option_sizer, 0, wx.RIGHT, 10) + options_sizer.Add(left_option_sizer, 1, wx.ALL, 10) + options_sizer.Add(right_option_sizer, 0, wx.ALL, 10) outer_sizer.Add(options_sizer, 0, wx.EXPAND | wx.LEFT | wx.TOP | wx.RIGHT, 10) # text input @@ -130,7 +146,7 @@ class LetteringOptionsPanel(wx.Panel): self.text_editor.Bind(wx.EVT_TEXT, lambda event: self.panel.on_change("text", event)) text_input_sizer = wx.StaticBoxSizer(self.text_input_box, wx.VERTICAL) - text_input_sizer.Add(self.text_editor, 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10) + text_input_sizer.Add(self.text_editor, 2, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10) outer_sizer.Add(text_input_sizer, 2, wx.EXPAND | wx.LEFT | wx.TOP | wx.RIGHT, 10) # set panel sizer diff --git a/lib/lettering/font.py b/lib/lettering/font.py index fdac9d9b..5c56ca0b 100644 --- a/lib/lettering/font.py +++ b/lib/lettering/font.py @@ -204,7 +204,8 @@ class Font(object): return False return custom_dir in self.path - def render_text(self, text, destination_group, variant=None, back_and_forth=True, trim_option=0, use_trim_symbols=False, color_sort=0): + def render_text(self, text, destination_group, variant=None, back_and_forth=True, # noqa: C901 + trim_option=0, use_trim_symbols=False, color_sort=0, text_align=0): """Render text into an SVG group element.""" self._load_variants() @@ -217,6 +218,7 @@ class Font(object): else: glyph_sets = [self.get_variant(variant)] * 2 + max_line_width = 0 position = Point(0, 0) for i, line in enumerate(text.splitlines()): glyph_set = glyph_sets[i % 2] @@ -225,11 +227,38 @@ class Font(object): letter_group = self._render_line(destination_group, line, position, glyph_set) if (back_and_forth and self.reversible and i % 2 == 1) or variant == '←': letter_group[:] = reversed(letter_group) - destination_group.append(letter_group) position.x = 0 position.y += self.leading + bounding_box = letter_group.bounding_box() + if not bounding_box: + continue + + line_width = bounding_box.width + max_line_width = max(max_line_width, line_width) + if text_align == 1: + # align center + letter_group.transform = f'translate({-line_width/2}, 0)' + if text_align == 2: + letter_group.transform = f'translate({-line_width}, 0)' + + destination_group.append(letter_group) + + if text_align in [3, 4]: + for line_group in destination_group.iterchildren(): + # print(line_group.label, len(line_group), file=sys.stderr) + # print(line_group.bounding_box().width, max_line_width, file=sys.stderr) + if text_align == 4 and len(line_group) == 1: + line_group = line_group[0] + if len(line_group) > 1: + distance = max_line_width - line_group.bounding_box().width + distance_per_space = distance / (len(line_group) - 1) + for i, word in enumerate(line_group.getchildren()[1:]): + transform = word.transform + translate = distance_per_space * (i + 1) + transform.add_translate(translate, 0) + if self.auto_satin and len(destination_group) > 0: self._apply_auto_satin(destination_group) |
