diff --git a/Lib/typerig/proxy/fl/gui/widgets.py b/Lib/typerig/proxy/fl/gui/widgets.py
index 7634956..0e146ce 100644
--- a/Lib/typerig/proxy/fl/gui/widgets.py
+++ b/Lib/typerig/proxy/fl/gui/widgets.py
@@ -28,7 +28,7 @@
from typerig.proxy.fl.gui.styles import css_tr_button
# - Init ----------------------------------
-__version__ = '0.4.5'
+__version__ = '0.4.6'
# - Keep compatibility for basestring checks
try:
@@ -332,6 +332,23 @@ def expand(self):
self.opt_sliders.show()
self.__toggle_slider()
+ def blockSignals(self, state):
+ self.spin_box.blockSignals(state)
+ self.ctrl_btn_dec_10.blockSignals(state)
+ self.ctrl_btn_dec_1.blockSignals(state)
+ self.ctrl_btn_inc_1.blockSignals(state)
+ self.ctrl_btn_inc_10.blockSignals(state)
+ self.ctrl_slider.blockSignals(state)
+
+ def setEnabled(self, state):
+ self.spin_box.setEnabled(state)
+ self.ctrl_btn_dec_10.setEnabled(state)
+ self.ctrl_btn_dec_1.setEnabled(state)
+ self.ctrl_btn_inc_1.setEnabled(state)
+ self.ctrl_btn_inc_10.setEnabled(state)
+ self.opt_sliders.setEnabled(state)
+ self.ctrl_slider.setEnabled(state)
+
def setValue(self, value):
self.spin_box.setValue(value)
self.__set_slider_no_signal(value)
diff --git a/Scripts/TypeRig GUI/Panel/Delta.py b/Scripts/TypeRig GUI/Panel/Delta.py
index 6a80856..ebb88b8 100644
--- a/Scripts/TypeRig GUI/Panel/Delta.py
+++ b/Scripts/TypeRig GUI/Panel/Delta.py
@@ -36,7 +36,7 @@
global pMode
pLayers = None
pMode = 0
-app_name, app_version = 'TypeRig | Delta', '5.2'
+app_name, app_version = 'TypeRig | Delta', '5.3'
TRToolFont = getTRIconFontPath()
font_loaded = QtGui.QFontDatabase.addApplicationFont(TRToolFont)
@@ -73,7 +73,7 @@ def __init__(self):
self.tree_layer = TRDeltaLayerTree()
# --- Layer selector: Actions (Context Menu)
- act_resetAxis = QtGui.QAction('Reset Axis', self)
+ act_resetAxis = QtGui.QAction('Clear all', self)
act_getVstem = QtGui.QAction('Get Vertical Stems', self)
act_getHstem = QtGui.QAction('Get Horizontal Stems', self)
@@ -83,7 +83,7 @@ def __init__(self):
self.tree_layer.menu.addSeparator()
self.tree_layer.menu.addAction(act_resetAxis)
- act_resetAxis.triggered.connect(lambda: self.__reset_axis())
+ act_resetAxis.triggered.connect(lambda: self.__reset_all())
act_getVstem.triggered.connect(lambda: self.get_stem(False))
act_getHstem.triggered.connect(lambda: self.get_stem(True))
@@ -97,6 +97,11 @@ def __init__(self):
lay_actions = TRFlowLayout(spacing=10)
+ tooltip_button = 'Execute delta scale'
+ self.btn_execute_scale = CustomPushButton('action_play', tooltip=tooltip_button, enabled=False, obj_name='btn_panel')
+ lay_actions.addWidget(self.btn_execute_scale)
+ self.btn_execute_scale.clicked.connect(lambda: self.execute_target())
+
tooltip_button = 'Get vertical stems'
self.btn_get_stem_x = CustomPushButton('stem_vertical_alt', tooltip=tooltip_button, obj_name='btn_panel')
lay_actions.addWidget(self.btn_get_stem_x)
@@ -107,10 +112,25 @@ def __init__(self):
lay_actions.addWidget(self.btn_get_stem_y)
self.btn_get_stem_y.clicked.connect(lambda: self.get_stem(True))
- tooltip_button = 'Reset axis data'
- self.btn_axis_reset = CustomPushButton('refresh', tooltip=tooltip_button, obj_name='btn_panel')
+ tooltip_button = 'Make undo snapshot'
+ self.btn_undo_snapshot = CustomPushButton('undo_snapshot', tooltip=tooltip_button, obj_name='btn_panel')
+ lay_actions.addWidget(self.btn_undo_snapshot)
+ self.btn_undo_snapshot.clicked.connect(lambda: self.__undo_snapshot())
+
+ tooltip_button = 'Set axis'
+ self.btn_axis_set = CustomPushButton('axis_set', tooltip=tooltip_button, obj_name='btn_panel')
+ lay_actions.addWidget(self.btn_axis_set)
+ self.btn_axis_set.clicked.connect(lambda: self.__set_axis(True))
+
+ tooltip_button = 'Reset axis'
+ self.btn_axis_reset = CustomPushButton('axis_remove', tooltip=tooltip_button, obj_name='btn_panel')
lay_actions.addWidget(self.btn_axis_reset)
- self.btn_axis_reset.clicked.connect(lambda: self.__reset_axis())
+ self.btn_axis_reset.clicked.connect(lambda: self.__reset_axis(True))
+
+ tooltip_button = 'Reset all data'
+ self.btn_axis_reset_all = CustomPushButton('refresh', tooltip=tooltip_button, obj_name='btn_panel')
+ lay_actions.addWidget(self.btn_axis_reset_all)
+ self.btn_axis_reset_all.clicked.connect(lambda: self.__reset_all(True))
tooltip_button = 'Save axis data to external file'
self.btn_file_save = CustomPushButton('file_save', tooltip=tooltip_button, obj_name='btn_panel')
@@ -125,12 +145,12 @@ def __init__(self):
tooltip_button = 'Save axis data to font file'
self.btn_font_save = CustomPushButton('font_save', tooltip=tooltip_button, enabled=False, obj_name='btn_panel')
lay_actions.addWidget(self.btn_font_save)
- #self.btn_font_save.clicked.connect(lambda: self.__reset_axis())
+ #self.btn_font_save.clicked.connect(lambda: self.__reset_all())
tooltip_button = 'Load axis data from font file'
self.btn_font_open = CustomPushButton('font_open', tooltip=tooltip_button, enabled=False, obj_name='btn_panel')
lay_actions.addWidget(self.btn_font_open)
- #self.btn_file_open.clicked.connect(lambda: self.__reset_axis())
+ #self.btn_file_open.clicked.connect(lambda: self.__reset_all())
box_delta_actions.setLayout(lay_actions)
lay_main.addWidget(box_delta_actions)
@@ -154,13 +174,14 @@ def __init__(self):
lay_options.addWidget(self.chk_extrapolate)
tooltip_button = 'Use target'
- self.chk_target = CustomPushButton("node_target", checkable=True, cheked=False, enabled=False, tooltip=tooltip_button, obj_name='btn_panel_opt')
+ self.chk_target = CustomPushButton("node_target", checkable=True, cheked=False, tooltip=tooltip_button, obj_name='btn_panel_opt')
lay_options.addWidget(self.chk_target)
- #self.chk_target.clicked.connect(lambda: self.__toggle_controls())
+ self.chk_target.clicked.connect(lambda: self.__prepare_target())
- tooltip_button = 'Proportional mode'
- self.chk_proportional = CustomPushButton("diagonal_bottom_up", checkable=True, cheked=False, enabled=False,tooltip=tooltip_button, obj_name='btn_panel_opt')
+ tooltip_button = 'Proportional scale mode'
+ self.chk_proportional = CustomPushButton("diagonal_bottom_up", checkable=True, cheked=False, tooltip=tooltip_button, obj_name='btn_panel_opt')
lay_options.addWidget(self.chk_proportional)
+ self.chk_proportional.clicked.connect(lambda: self.__toggle_proportional_scale())
tooltip_button = 'Scale from center'
self.chk_center = CustomPushButton("node_target_expand", checkable=True, cheked=False, tooltip=tooltip_button, obj_name='btn_panel_opt')
@@ -233,6 +254,12 @@ def __toggle_controls(self):
self.cpn_value_stem_y.contract()
self.cpn_value_lerp_t.contract()
+ def __toggle_proportional_scale(self):
+ if self.chk_proportional.isChecked():
+ self.cpn_value_height.setEnabled(False)
+ else:
+ self.cpn_value_height.setEnabled(True)
+
def __change_value(self, cpn_object, value):
cpn_object.setValue(cpn_object.getValue() + value)
@@ -288,6 +315,26 @@ def __prepare_delta(self):
# - Default
return True
+ def __prepare_target(self):
+ if self.chk_target.isChecked():
+ self.cpn_value_width.setEnabled(False)
+ self.cpn_value_height.setEnabled(False)
+ self.cpn_value_stem_x.setEnabled(False)
+ self.cpn_value_stem_y.setEnabled(False)
+ self.cpn_value_lerp_t.setEnabled(False)
+ self.cpn_value_ital.setEnabled(False)
+
+ self.btn_execute_scale.setEnabled(True)
+ else:
+ self.cpn_value_width.setEnabled(True)
+ self.cpn_value_height.setEnabled(True)
+ self.cpn_value_stem_x.setEnabled(True)
+ self.cpn_value_stem_y.setEnabled(True)
+ self.cpn_value_lerp_t.setEnabled(True)
+ self.cpn_value_ital.setEnabled(True)
+
+ self.btn_execute_scale.setEnabled(False)
+
def __refresh_ui(self):
self.cpn_value_width.setValue(100)
self.cpn_value_height.setValue(100)
@@ -310,20 +357,7 @@ def __refresh_arrays(self):
temp_service = [glyph._getServiceArray(layer_data[0]) for layer_data in self.axis_data]
self.glyph_arrays[glyph.name] = [glyph, DeltaScale(temp_outline, self.axis_stems), DeltaScale(temp_service, self.axis_stems)]
- def __reset_axis(self):
- self.tree_layer.setTree(self.__init_tree(), tree_column_names)
- self.axis_data = []
- self.axis_stems = []
- self.glyph_arrays = {}
-
- self.cpn_value_width.setValue(100)
- self.cpn_value_height.setValue(100)
- self.cpn_value_stem_x.setValue(100)
- self.cpn_value_stem_y.setValue(100)
- self.cpn_value_lerp_t.setValue(0)
- self.cpn_value_ital.setValue(self.active_font.italic_angle)
-
- def __set_axis(self):
+ def __set_axis(self, verbose=False):
self.masters_data = self.tree_layer.getTree()
self.axis_data = self.masters_data[tree_axis_group_name]
self.axis_stems = []
@@ -337,12 +371,54 @@ def __set_axis(self):
warnings.warn('Missing or invalid stem data!', TRDeltaStemWarning)
return
- def __apply_scale(self):
- if pMode == 0:
- glyph, _delta_outline, _delta_service = self.glyph_arrays[fl6.CurrentGlyph().name]
- glyph.updateObject(glyph.fl, '{} {} | \tGlyph: {}; Layer: {}'.format(app_name, app_version, glyph.name, self.active_layer))
+ if verbose: output(0, '%s %s' %(app_name, app_version), 'Font: %s; Axis set.' %(self.active_font.name))
+
+ def __reset_axis(self, verbose=False):
+ self.axis_data = []
+ self.axis_stems = []
+ self.glyph_arrays = {}
+
+ if verbose: output(0, '%s %s' %(app_name, app_version), 'Font: %s; Axis data cleared.' %(self.active_font.name))
+
+ def __reset_all(self, verbose=False):
+ self.tree_layer.setTree(self.__init_tree(), tree_column_names)
+ self.__reset_axis()
+
+ self.cpn_value_width.blockSignals(True)
+ self.cpn_value_height.blockSignals(True)
+ self.cpn_value_stem_x.blockSignals(True)
+ self.cpn_value_stem_y.blockSignals(True)
+ self.cpn_value_lerp_t.blockSignals(True)
+ self.cpn_value_ital.blockSignals(True)
+
+ self.cpn_value_width.setValue(100)
+ self.cpn_value_height.setValue(100)
+ self.cpn_value_stem_x.setValue(100)
+ self.cpn_value_stem_y.setValue(100)
+ self.cpn_value_lerp_t.setValue(0)
+ self.cpn_value_ital.setValue(self.active_font.italic_angle)
+
+ self.cpn_value_width.blockSignals(False)
+ self.cpn_value_height.blockSignals(False)
+ self.cpn_value_stem_x.blockSignals(False)
+ self.cpn_value_stem_y.blockSignals(False)
+ self.cpn_value_lerp_t.blockSignals(False)
+ self.cpn_value_ital.blockSignals(False)
+
+ if verbose: output(0, '%s %s' %(app_name, app_version), 'Reset.')
+
+ def __undo_snapshot(self, verbose=True):
+ # - Init
+ process_glyphs = getProcessGlyphs(pMode)
+ process_glyphs_names = [glyph.name for glyph in process_glyphs]
+ undo_message = '{} {} | Undo Snapshot for glyphs: {};'.format(app_name, app_version, '; '.join(process_glyphs_names))
+
+ # - Set undo
+ if len(process_glyphs) > 2:
+ self.active_font.updateObject(self.active_font.fl, undo_message, verbose)
else:
- self.active_font.updateObject(glyph.fl, '{} {} | \tGlyphs: {}; Layer: {}'.format(app_name, app_version, '; '.join(list(self.glyph_arrays.keys())), self.active_layer))
+ glyph = process_glyphs[0]
+ glyph.updateObject(glyph.fl, undo_message, verbose)
# -- File operations
def file_save_axis_data(self):
@@ -404,11 +480,18 @@ def execute_scale(self, use_time=False):
# - Scaling
sx = float(self.cpn_value_width.getValue())/100.
- sy = float(self.cpn_value_height.getValue())/100.
+
+ if self.chk_proportional.isChecked():
+ sy = sx
+ self.cpn_value_height.blockSignals(True)
+ self.cpn_value_height.setValue(self.cpn_value_width.getValue())
+ self.cpn_value_height.blockSignals(False)
+ else:
+ sy = float(self.cpn_value_height.getValue())/100.
# - Italic
- #it = radians(-float(self.cpn_value_ital.getValue())) self.active_font.italic_angle
- it = math.radians(-float(self.active_font.italic_angle)) # Use italic only in the context of Delta calculation not for actuall slanting
+ # Note: Use italic only in the context of Delta calculation not for actuall slanting
+ it = math.radians(-float(self.active_font.italic_angle))
# - Options
opt_extrapolate = self.chk_extrapolate.isChecked()
@@ -461,10 +544,66 @@ def execute_scale(self, use_time=False):
glyph.update()
+ # - Update viewport
+ try:
+ self.active_canvas.refreshAll()
+ except:
+ pass
+
+ def execute_target(self):
+ # - Init
+ glyphs_done = []
+
+ system_ready = self.__prepare_delta()
+ if not system_ready: return
+
+ process_target = self.masters_data[tree_axis_target_name]
+ if not len(process_target): return
+
+ if pMode == 0:
+ system_process = [self.glyph_arrays[fl6.CurrentGlyph().name]]
+ else:
+ system_process = self.glyph_arrays.values()
+
+ # - Process
+ for glyph, delta_outline, delta_service in system_process:
+ for process_layer_data in process_target:
+ # - Unpack axis data
+ layer_name, curr_sw_dx, curr_sw_dy, sx, sy, _ = process_layer_data
+
+ curr_sw_dx = float(curr_sw_dx)
+ curr_sw_dy = float(curr_sw_dy)
+ sx = float(sx)/100.
+ sy = float(sy)/100.
+ it = math.radians(-float(self.active_font.italic_angle))
+
+ # - Options
+ opt_extrapolate = self.chk_extrapolate.isChecked()
+ opt_center = self.chk_center.isChecked()
+ opt_metrics = self.chk_metrics.isChecked()
+ opt_anchors = self.chk_anchors.isChecked()
+
+ # - Process
+ outline_scale = delta_outline.scale_by_stem((curr_sw_dx, curr_sw_dy), (sx, sy), (0., 0.), (0., 0.), it, extrapolate=opt_extrapolate)
+ service_scale = delta_service.scale_by_stem((curr_sw_dx, curr_sw_dy), (sx, sy), (0., 0.), (0., 0.), it, extrapolate=opt_extrapolate)
+
+ # - Apply transformations
+ glyph._setPointArray(outline_scale, layer=layer_name, keep_center=opt_center)
+ glyph._setServiceArray(service_scale, layer=layer_name, set_metrics=opt_metrics, set_anchors=opt_anchors)
+
+ glyphs_done.append(glyph.name)
+ glyph.update()
+
+ # - Update viewport
try:
self.active_canvas.refreshAll()
except:
pass
+
+ # - Finish it
+ self.__undo_snapshot(False)
+ output(0, '%s %s' %(app_name, app_version), 'Font: %s;' %(self.active_font.name))
+ output(0, '%s %s' %(app_name, app_version), 'Glyph(s): %s.' %('; '.join(glyphs_done)))
# - Tabs -------------------------------
class tool_tab(QtGui.QWidget):
diff --git a/Scripts/TypeRig GUI/Panel/DeltaOld.py b/Scripts/TypeRig GUI/Panel/DeltaOld.py
deleted file mode 100644
index 44090a3..0000000
--- a/Scripts/TypeRig GUI/Panel/DeltaOld.py
+++ /dev/null
@@ -1,484 +0,0 @@
-#FLM: TR: Delta Old
-# -----------------------------------------------------------
-# (C) Vassil Kateliev, 2020-2021 (http://www.kateliev.com)
-# (C) Karandash Type Foundry (http://www.karandash.eu)
-#------------------------------------------------------------
-
-# No warranties. By using this you agree
-# that you use it at your own risk!
-
-# - Dependencies -----------------
-from __future__ import absolute_import, print_function
-import warnings, os, json, random
-from math import radians
-from collections import OrderedDict
-
-import fontlab as fl6
-import fontgate as fgt
-
-from typerig.proxy.fl.objects.font import pFont
-from typerig.proxy.fl.objects.glyph import eGlyph
-
-from typerig.core.base.message import *
-from typerig.core.func.math import linInterp, ratfrac
-from typerig.core.func import transform
-from typerig.core.objects.array import PointArray
-from typerig.core.objects.delta import DeltaArray, DeltaScale
-
-from PythonQt import QtCore
-from typerig.proxy.fl.gui import QtGui
-from typerig.proxy.fl.gui.widgets import *
-from typerig.proxy.fl.gui.dialogs import TR2ComboDLG
-
-# - Init -------------------------------
-global pLayers
-global pMode
-pLayers = None
-pMode = 0
-app_name, app_version = 'TypeRig | Delta', '4.48'
-
-# -- Strings
-tree_column_names = ('Layer','X', 'Y', 'Width', 'Height', 'Color')
-tree_masters_group_name = 'Master Layers'
-tree_axis_group_name = 'Virtual Axis'
-tree_axis_target_name = 'Target Layers'
-fileFormats = 'TypeRig Delta Panel Target (*.json);;'
-
-default_sx = '100.'
-default_sy = '100.'
-
-# - Tabs -------------------------------
-class tool_tab(QtGui.QWidget):
- def __init__(self):
- super(tool_tab, self).__init__()
-
- # - Init
-
- # - Widgets
- # - Glyph list
- self.lst_glyphName = QtGui.QListWidget()
- self.lst_glyphName.setMinimumHeight(50)
- self.lst_glyphName.setAlternatingRowColors(True)
-
- # -- Buttons
- self.btn_refresh = QtGui.QPushButton('&Refresh')
- self.btn_setAxis = QtGui.QPushButton('Set &Axis')
- self.btn_setAxis_c = QtGui.QPushButton('Set &Axis')
- self.btn_resetAxis = QtGui.QPushButton('Reset Axis')
- self.btn_getVstem = QtGui.QPushButton('Get &Vertical Stems')
- self.btn_getHstem = QtGui.QPushButton('Get &Horizontal Stems')
- self.btn_setLayer = QtGui.QPushButton('Layer changed')
- self.btn_execute = QtGui.QPushButton('Execute')
- self.btn_file_load_patchboard = QtGui.QPushButton('Load')
- self.btn_file_save_patchboard = QtGui.QPushButton('Save')
-
- # -- Options
- self.btn_opt_extrapolate = QtGui.QPushButton('Extrapolate')
- self.btn_opt_italic = QtGui.QPushButton('Italic')
- self.btn_opt_update_preview = QtGui.QPushButton('Live preview')
- self.btn_opt_keep_center = QtGui.QPushButton('Keep Center')
- self.btn_opt_metrics = QtGui.QPushButton('Metrics')
- self.btn_opt_anchors = QtGui.QPushButton('Anchors')
- self.btn_opt_target = QtGui.QPushButton('Use Target')
-
- self.btn_opt_extrapolate.setCheckable(True)
- self.btn_opt_italic.setCheckable(True)
- self.btn_opt_update_preview.setCheckable(True)
- self.btn_opt_keep_center.setCheckable(True)
- self.btn_opt_metrics.setCheckable(True)
- self.btn_opt_anchors.setCheckable(True)
- self.btn_opt_target.setCheckable(True)
-
- #self.btn_opt_extrapolate.setChecked(True)
- #self.btn_opt_keep_center.setChecked(True)
- #self.btn_opt_target.setChecked(True)
-
- self.btn_refresh.clicked.connect(self.refresh)
- self.btn_setAxis.clicked.connect(self.set_axis)
- self.btn_setAxis_c.clicked.connect(self.set_axis)
- self.btn_resetAxis.clicked.connect(self.reset_axis)
- self.btn_getVstem.clicked.connect(lambda: self.get_stem(False))
- self.btn_getHstem.clicked.connect(lambda: self.get_stem(True))
- self.btn_setLayer.clicked.connect(self.set_current_layer)
- self.btn_execute.clicked.connect(lambda: self.execute_scale(True))
-
- self.btn_file_save_patchboard.clicked.connect(self.file_save_patchboard)
- self.btn_file_load_patchboard.clicked.connect(self.file_load_patchboard)
-
- # -- Layer selector
- self.tree_layer = TRDeltaLayerTree()
-
- # -- Additional Actions (Context Menu)
- act_setItem_mask = QtGui.QAction('Set mask', self)
- act_setItem_unmask = QtGui.QAction('Remove mask', self)
- act_setItem_value = QtGui.QAction('Set value', self)
-
- act_setAxis = QtGui.QAction('Set Axis', self)
- act_resetAxis = QtGui.QAction('Reset Axis', self)
- act_getVstem = QtGui.QAction('Get Vertical Stems', self)
- act_getHstem = QtGui.QAction('Get Horizontal Stems', self)
-
- self.tree_layer.menu.addSeparator()
- self.tree_layer.menu.addAction(act_setItem_mask )
- self.tree_layer.menu.addAction(act_setItem_unmask )
- self.tree_layer.menu.addAction(act_setItem_value )
- self.tree_layer.menu.addSeparator()
- self.tree_layer.menu.addAction(act_getVstem)
- self.tree_layer.menu.addAction(act_getHstem)
- self.tree_layer.menu.addSeparator()
- self.tree_layer.menu.addAction(act_setAxis)
- self.tree_layer.menu.addAction(act_resetAxis)
-
- act_setItem_mask.triggered.connect(lambda: self.tree_layer._setItemData('mask.', 0, 0, False))
- act_setItem_unmask.triggered.connect(lambda: self.tree_layer._setItemData('mask.', 0, 1, True))
- act_setItem_value.triggered.connect(lambda: self.tree_layer._setItemData(*TR2ComboDLG('Delta Setup', 'Please enter new value for selected columns', 'Value:', 'Column:', tree_column_names).values))
-
- act_setAxis.triggered.connect(lambda: self.set_axis())
- act_resetAxis.triggered.connect(lambda: self.reset_axis())
-
- act_getVstem.triggered.connect(lambda: self.get_stem(False))
- act_getHstem.triggered.connect(lambda: self.get_stem(True))
-
- # - Build Layout
- layoutV = QtGui.QVBoxLayout()
-
- # -- Layer selector
- layoutV.addWidget(self.tree_layer)
-
- # -- Set Glyph list
- self.fld_glyphs = TRCollapsibleBox('Process Glyphs')
- lay_glyphs = QtGui.QVBoxLayout()
- lay_glyphs_b = QtGui.QHBoxLayout()
- lay_glyphs.addWidget(self.lst_glyphName)
- lay_glyphs_b.addWidget(self.btn_refresh)
- lay_glyphs_b.addWidget(self.btn_setAxis_c)
- lay_glyphs.addLayout(lay_glyphs_b)
- self.fld_glyphs.setContentLayout(lay_glyphs)
- layoutV.addWidget(self.fld_glyphs)
-
- # -- Delta Setup controls
- self.fld_setup = TRCollapsibleBox('Delta Setup')
- layoutG = QtGui.QGridLayout()
- layoutG.addWidget(QtGui.QLabel('Axis Setup:'), 0, 0, 1, 10)
- layoutG.addWidget(self.btn_getVstem, 1, 0, 1, 5)
- layoutG.addWidget(self.btn_getHstem, 1, 5, 1, 5)
- layoutG.addWidget(self.btn_resetAxis, 2, 0, 1, 5)
- layoutG.addWidget(self.btn_setAxis, 2, 5, 1, 5)
- layoutG.addWidget(self.btn_file_save_patchboard, 3, 0, 1, 5)
- layoutG.addWidget(self.btn_file_load_patchboard, 3, 5, 1, 5)
-
- layoutG.addWidget(QtGui.QLabel('Options:'), 4, 0, 1, 10)
- layoutG.addWidget(self.btn_opt_extrapolate, 5, 0, 1, 5)
- layoutG.addWidget(self.btn_opt_italic, 5, 5, 1, 5)
- layoutG.addWidget(self.btn_opt_anchors, 6, 0, 1, 5)
- layoutG.addWidget(self.btn_opt_metrics, 6, 5, 1, 5)
- layoutG.addWidget(self.btn_opt_target, 8, 0, 1, 5)
- layoutG.addWidget(self.btn_opt_keep_center, 8, 5, 1, 5)
- layoutG.addWidget(self.btn_opt_update_preview, 9, 0, 1, 10)
-
- self.fld_setup.setContentLayout(layoutG)
- layoutV.addWidget(self.fld_setup)
-
- # -- Set Sliders
- self.fld_weight = TRCollapsibleBox('Stem Weight Control')
- self.fld_scale = TRCollapsibleBox('Compensative scaler')
-
- lay_weight = QtGui.QVBoxLayout()
- lay_scale = QtGui.QVBoxLayout()
-
- # --- Mixer
- lay_weight.addWidget(QtGui.QLabel('Vertical Stem Weight (X):'))
- self.mixer_dx = TRSliderCtrl('1', '1000', '0', 1)
- self.mixer_dx.sld_axis.valueChanged.connect(self.execute_scale)
- lay_weight.addLayout(self.mixer_dx)
- lay_weight.addSpacing(10)
-
- lay_weight.addWidget(QtGui.QLabel('Horizontal Stem Weight (Y):'))
- self.mixer_dy = TRSliderCtrl('1', '1000', '0', 1)
- self.mixer_dy.sld_axis.valueChanged.connect(self.execute_scale)
- lay_weight.addLayout(self.mixer_dy)
-
- self.fld_weight.setContentLayout(lay_weight)
- layoutV.addWidget(self.fld_weight)
-
- # --- Scaler
- lay_scale.addWidget(QtGui.QLabel('Width'))
- self.scalerX = TRSliderCtrl('1', '200', '100', 1)
- self.scalerX.sld_axis.valueChanged.connect(self.execute_scale)
- lay_scale.addLayout(self.scalerX)
- lay_scale.addSpacing(10)
-
- lay_scale.addWidget(QtGui.QLabel('Height'))
- self.scalerY = TRSliderCtrl('1', '200', '100', 1)
- self.scalerY.sld_axis.valueChanged.connect(self.execute_scale)
- lay_scale.addLayout(self.scalerY)
-
- self.fld_scale.setContentLayout(lay_scale)
- layoutV.addWidget(self.fld_scale)
-
- # -- Tail
- layoutE = QtGui.QHBoxLayout()
- layoutE.addWidget(self.btn_setLayer)
- layoutE.addWidget(self.btn_execute)
- layoutV.addLayout(layoutE)
-
- self.__lbl_warn = QtGui.QLabel('')
- layoutV.addWidget(self.__lbl_warn)
- self.__lbl_warn.hide()
-
- # -- Finish
- self.refresh()
- self.tree_layer.setTree(self.__init_tree(), tree_column_names)
- self.setLayout(layoutV)
- self.setMinimumSize(300, self.sizeHint.height())
-
- # - Functions -----------------------------------------
- # - File operations
- def file_save_patchboard(self):
- fontPath = os.path.split(self.active_font.fg.path)[0]
- fname = QtGui.QFileDialog.getSaveFileName(self, 'Save Axis Patch-board to file', fontPath, fileFormats)
-
- if fname != None:
- with open(fname, 'w') as exportFile:
- json.dump(self.tree_layer.getTree(), exportFile)
- output(7, app_name, 'Font: %s; Patch-board saved to: %s.' %(self.active_font.name, fname))
-
- def file_load_patchboard(self):
- fontPath = os.path.split(self.active_font.fg.path)[0]
- fname = QtGui.QFileDialog.getOpenFileName(self, 'Load Axis Patch-board from file', fontPath, fileFormats)
-
- if fname != None:
- with open(fname, 'r') as importFile:
- imported_data = json.load(importFile)
-
- self.masters_data = imported_data
- self.tree_layer.setTree(self.masters_data, tree_column_names)
- output(6, app_name, 'Font: %s; Patch-board loaded from: %s.' %(self.active_font.name, fname))
-
- # -- Special
- def __where(self, data, search, ret=1):
- for item in data:
- if search == item[0]: return item[ret]
-
- warnings.warn('Axis/target missing layer: %s!' %search, TRDeltaAxisWarning)
- return 0
-
- def __init_tree(self):
- return_data = []
- return_data.append((tree_masters_group_name, [(layer, '', '', default_sx, default_sy, eGlyph().layer(layer).wireframeColor) for layer in self.active_font.masters()]))
- return_data.append((tree_axis_group_name,[]))
- return_data.append((tree_axis_target_name,[]))
- return OrderedDict(return_data)
-
- def __doCheck(self):
- if pMode > 0: return 1
- if self.active_glyph.fg.id != fl6.CurrentGlyph().id and self.active_glyph.fl.name != fl6.CurrentGlyph().name:
- warnings.warn('Glyph mismatch! No action taken! Forcing refresh!', GlyphWarning)
- self.refresh()
- return 0
- return 1
-
- # -- Operation
- def refresh(self):
- # - Init
- self.axis_points = []
- self.axis_stems = []
- self.data_glyphs = getProcessGlyphs(pMode)
- self.data_glyphs = [glyph for glyph in self.data_glyphs if not glyph.isEmpty()]
- self.glyph_arrays = {}
- self.glyph_arrays_service = {}
-
- self.active_glyph = eGlyph()
- self.active_font = pFont()
- self.active_workspace = pWorkspace()
- self.active_canvas = self.active_workspace.getCanvas(True)
-
- self.working_names = [glyph.name for glyph in self.data_glyphs] if len(self.data_glyphs) > 1 else [self.active_glyph.name]
- self.lst_glyphName.clear()
- self.lst_glyphName.addItems(self.working_names)
-
- if len(self.active_font.masters()) > 1:
- # - Activate
- self.__lbl_warn.setText('')
- self.__lbl_warn.setStyleSheet('')
- self.btn_setAxis.setEnabled(True)
- self.btn_getVstem.setEnabled(True)
- self.btn_getHstem.setEnabled(True)
-
- self.mixer_dx.reset()
- self.mixer_dy.reset()
- self.scalerX.reset()
- self.scalerY.reset()
- else:
- # - Deactivate
- self.__lbl_warn.show()
- self.__lbl_warn.setText('Insufficient number of Master layers!
Delta Panel is currently disabled!')
- self.__lbl_warn.setStyleSheet('padding: 10; font-size: 10pt; background: lightpink;')
- self.btn_setAxis.setEnabled(False)
- self.btn_getVstem.setEnabled(False)
- self.btn_getHstem.setEnabled(False)
-
- def get_stem(self, get_y=False):
- if self.__doCheck():
- self.masters_data = self.tree_layer.getTree()
- self.active_glyph = eGlyph()
-
- for group, data in self.masters_data.items():
- for layer_data in data:
- try:
- selection = self.active_glyph.selectedNodes(layer_data[0], True)
-
- if get_y:
- layer_data[2] = abs(selection[0].y - selection[-1].y)
- else:
- layer_data[1] = abs(selection[0].x - selection[-1].x)
- except IndexError:
- warnings.warn('Missing or incompatible layer: %s!' %layer_data[0], LayerWarning)
- continue
-
- self.tree_layer.setTree(OrderedDict(self.masters_data), tree_column_names)
-
- def set_current_layer(self):
- try:
- if not self.btn_opt_target.isChecked():
- max_dx = max(self.axis_data, key=lambda i: float(i[1]))[1]
- max_dy = max(self.axis_data, key=lambda i: float(i[2]))[2]
- min_dx = min(self.axis_data, key=lambda i: float(i[1]))[1]
- min_dy = min(self.axis_data, key=lambda i: float(i[2]))[2]
- self.mixer_dx.edt_pos.setText(round(float(self.__where(self.axis_data, self.active_glyph.layer().name, 1))))
- self.mixer_dy.edt_pos.setText(round(float(self.__where(self.axis_data, self.active_glyph.layer().name, 2))))
- else:
- max_dx = max(self.masters_data[tree_axis_target_name], key=lambda i: float(i[1]))[1]
- max_dy = max(self.masters_data[tree_axis_target_name], key=lambda i: float(i[2]))[2]
- min_dx = min(self.masters_data[tree_axis_target_name], key=lambda i: float(i[1]))[1]
- min_dy = min(self.masters_data[tree_axis_target_name], key=lambda i: float(i[2]))[2]
- self.mixer_dx.edt_pos.setText(round(float(self.__where(self.masters_data[tree_axis_target_name], self.active_glyph.layer().name, 1))))
- self.mixer_dy.edt_pos.setText(round(float(self.__where(self.masters_data[tree_axis_target_name], self.active_glyph.layer().name, 2))))
-
-
- self.mixer_dx.edt_1.setText(min_dx)
- self.mixer_dy.edt_1.setText(min_dy)
- self.mixer_dx.edt_1.setText(max_dx)
- self.mixer_dy.edt_1.setText(max_dy)
-
- self.mixer_dx.refreshSlider()
- self.mixer_dy.refreshSlider()
-
- except (ValueError, IndexError):
- warnings.warn('Invalid Axis/Target or Axis/Target not set!', TRDeltaAxisWarning)
-
- def reset_axis(self):
- self.masters_data = self.tree_layer.getTree()
- #self.masters_data[tree_masters_group_name] += self.masters_data[tree_axis_group_name]
- self.masters_data[tree_axis_group_name] = []
- self.masters_data[tree_axis_target_name] = []
- self.tree_layer.setTree(self.masters_data, tree_column_names)
-
- def set_axis(self):
- self.masters_data = self.tree_layer.getTree()
- self.axis_data = self.masters_data[tree_axis_group_name]
-
- if len(self.axis_data):
- # - Init
- self.axis_stems = []
- for layer_data in self.axis_data:
- try:
- x_stem, y_stem = float(layer_data[1]), float(layer_data[2])
- self.axis_stems.append([(x_stem, y_stem)])
-
- except ValueError:
- warnings.warn('Missing or invalid stem data!', TRDeltaStemWarning)
- return
-
- for wGlyph in self.data_glyphs:
- temp_outline = [wGlyph._getPointArray(layer_data[0]) for layer_data in self.axis_data]
- temp_service = [wGlyph._getServiceArray(layer_data[0]) for layer_data in self.axis_data]
- self.glyph_arrays[wGlyph.name] = DeltaScale(temp_outline, self.axis_stems)
- self.glyph_arrays_service[wGlyph.name] = DeltaScale(temp_service, self.axis_stems)
-
- # - Set Sliders
- # -- X
- self.mixer_dx.edt_0.setText(round(float(self.axis_data[0][1])))
- self.mixer_dx.edt_1.setText(round(float(self.axis_data[-1][1])))
- self.mixer_dx.edt_pos.setText(round(float(self.__where(self.axis_data, self.active_glyph.layer().name, 1))))
- self.mixer_dx.refreshSlider()
- # -- Y
- self.mixer_dy.edt_0.setText(round(float(self.axis_data[0][2])))
- self.mixer_dy.edt_1.setText(round(float(self.axis_data[-1][2])))
- self.mixer_dy.edt_pos.setText(round(float(self.__where(self.axis_data, self.active_glyph.layer().name, 2))))
- self.mixer_dy.refreshSlider()
-
- # - Build
- self.active_font.updateObject(self.active_font.fl, 'Glyph(s): {} Axis :{} @ {}'.format('; '.join(self.working_names), ' :'.join([item[0] for item in self.axis_data]), self.active_glyph.layer().name))
-
- def execute_scale(self, force_preview=False):
- if len(self.glyph_arrays.keys()):
- if self.btn_opt_update_preview.isChecked() or force_preview:
- # - Stems
- curr_sw_dx = float(self.mixer_dx.sld_axis.value)
- curr_sw_dy = float(self.mixer_dy.sld_axis.value)
-
- # - Scaling
- sx = float(self.scalerX.sld_axis.value)/100.
- sy = float(self.scalerY.sld_axis.value)/100.
-
- # - Options
- opt_extrapolate = self.btn_opt_extrapolate.isChecked()
- opt_italic = radians(-float(self.active_font.italic_angle)) if self.btn_opt_italic.isChecked() else 0.
- opt_metrics = self.btn_opt_metrics.isChecked()
- opt_anchors = self.btn_opt_anchors.isChecked()
-
- # - Process
- for wGlyph in self.data_glyphs:
- if self.btn_opt_target.isChecked():
- process_target = self.masters_data[tree_axis_target_name]
-
- if len(process_target):
- for process_layer_data in process_target:
- layer_name, layer_dx, layer_dy, layer_width, layer_height, _color = process_layer_data
-
- if not self.btn_opt_update_preview.isChecked():
- # - Stems
- curr_sw_dx = float(layer_dx)
- curr_sw_dy = float(layer_dy)
-
- # - Scaling
- sx = float(layer_width)/100.
- sy = float(layer_height)/100.
-
- outline_scale = self.glyph_arrays[wGlyph.name].scale_by_stem((curr_sw_dx, curr_sw_dy), (sx,sy), (0.,0.), (0.,0.), opt_italic, extrapolate=opt_extrapolate)
- wGlyph._setPointArray(outline_scale, layer_name, keep_center=self.btn_opt_keep_center.isChecked())
-
- service_scale = self.glyph_arrays_service[wGlyph.name].scale_by_stem((curr_sw_dx, curr_sw_dy), (sx,sy), (0.,0.), (0.,0.), opt_italic, extrapolate=opt_extrapolate)
- wGlyph._setServiceArray(service_scale, layer_name, opt_metrics, opt_anchors)
-
- if not self.btn_opt_update_preview.isChecked():
- output(0, app_name, 'Processed: %s' %wGlyph.name)
-
- else:
- warnings.warn('Empty/Invalid Target Table provided! No action taken!', GlyphWarning)
- else:
- outline_scale = self.glyph_arrays[wGlyph.name].scale_by_stem((curr_sw_dx, curr_sw_dy), (sx,sy), (0.,0.), (0.,0.), opt_italic, extrapolate=opt_extrapolate)
- wGlyph._setPointArray(outline_scale, keep_center=self.btn_opt_keep_center.isChecked())
-
- service_scale = self.glyph_arrays_service[wGlyph.name].scale_by_stem((curr_sw_dx, curr_sw_dy), (sx,sy), (0.,0.), (0.,0.), opt_italic, extrapolate=opt_extrapolate)
- wGlyph._setServiceArray(service_scale, set_metrics=opt_metrics, set_anchors=opt_anchors)
-
- wGlyph.update()
-
- try:
- self.active_canvas.refreshAll()
- except:
- pass
-
- if opt_metrics: self.active_font.fl.changed()
-
-
-# - Test ----------------------
-if __name__ == '__main__':
- test = tool_tab()
- test.setWindowTitle('%s %s' %(app_name, app_version))
- test.setGeometry(100, 100, 280, 800)
- test.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) # Always on top!!
-
- test.show()
\ No newline at end of file