├── .github
└── workflows
│ └── static.yml
├── .gitignore
├── DSEezui.py
├── DesignspaceEditor2.roboFontExt
├── html
│ ├── chart.bar.doc.horizontal2x.png
│ ├── index.html
│ ├── previewWindow.jpg
│ ├── previewWindow_options2.png
│ ├── questionmark.circle2x.png
│ ├── screenshot_mutatorsans_axestab.jpg
│ ├── screenshot_mutatorsans_axestab.png
│ ├── screenshot_mutatorsans_instancestab.png
│ ├── screenshot_mutatorsans_previewwindow1.jpg
│ ├── screenshot_mutatorsans_problemstab.jpg
│ ├── screenshot_mutatorsans_rulestab.jpg
│ ├── screenshot_mutatorsans_sourcestab.jpg
│ ├── screenshot_mutatorsans_variablefontstab.jpg
│ ├── sparse_master.png
│ ├── square.and.arrow.down2x.png
│ ├── styles.css
│ ├── toolbar_25_25_info.circle.fill.svg
│ ├── toolbar_500_500_icon_axes.png
│ ├── toolbar_500_500_icon_instances.png
│ ├── toolbar_500_500_icon_location_labels.png
│ ├── toolbar_500_500_icon_notes.png
│ ├── toolbar_500_500_icon_notifications.png
│ ├── toolbar_500_500_icon_problems.png
│ ├── toolbar_500_500_icon_rules.png
│ ├── toolbar_500_500_icon_save.png
│ ├── toolbar_500_500_icon_settings.png
│ ├── toolbar_500_500_icon_sources.png
│ └── toolbar_500_500_icon_variable_fonts.png
├── info.plist
├── lib
│ ├── designspaceEditor
│ │ ├── __init__.py
│ │ ├── designspaceLexer.py
│ │ ├── designspaceSubscribers.py
│ │ ├── locationPreview.py
│ │ ├── parsers
│ │ │ ├── __init__.py
│ │ │ ├── glyphNameParser.py
│ │ │ ├── labelsParser.py
│ │ │ ├── mapParser.py
│ │ │ ├── parserTools.py
│ │ │ ├── rulesParser.py
│ │ │ ├── testParser.py
│ │ │ └── variableFontsParser.py
│ │ ├── tools.py
│ │ └── ui.py
│ ├── install.py
│ ├── main.py
│ ├── newDesignspaceEditor.py
│ └── openDesignspaceEditor.py
└── resources
│ ├── toolbar_30_30_arrow.right.filled.filter.arrow.right_arrow.right.filled.filter.arrow.right.pdf
│ ├── toolbar_30_30_atom.pdf
│ ├── toolbar_30_30_chart.bar.doc.horizontal.pdf
│ ├── toolbar_30_30_icon_axes.pdf
│ ├── toolbar_30_30_icon_instances.pdf
│ ├── toolbar_30_30_icon_location_labels.pdf
│ ├── toolbar_30_30_icon_notes.pdf
│ ├── toolbar_30_30_icon_notifications.pdf
│ ├── toolbar_30_30_icon_problems.pdf
│ ├── toolbar_30_30_icon_rules.pdf
│ ├── toolbar_30_30_icon_sources.pdf
│ ├── toolbar_30_30_icon_variable_fonts.pdf
│ ├── toolbar_30_30_icon_variablefonts.pdf
│ ├── toolbar_30_30_mappin.and.ellipse.pdf
│ ├── toolbar_30_30_questionmark.circle.pdf
│ ├── toolbar_30_30_smallcircle.filled.circle.fill.pdf
│ ├── toolbar_30_30_smallcircle.filled.circle.pdf
│ ├── toolbar_30_30_square.and.arrow.down.pdf
│ └── toolbar_30_30_wand.and.stars.pdf
├── LICENSE
├── README.md
├── Scripting examples
├── db_currentDesignspace.py
├── db_currentDesignspace_grid.py
├── db_simpleGlyphPreview.py
├── db_sliders.py
├── db_werkman.py
├── rf_change_previewLocation_of_all_open_designspaces.py
├── rf_close_all_sources_from_designspace.py
├── rf_getBasicValues.py
├── rf_makeOneKerning.py
├── rf_open_all_sources_from_designspace.py
└── rf_previewFont_to_spacecenter.py
├── assets
├── designSpaceFileIcon.png
├── info.circle.fill.svg
├── questionmark.circle.svg
├── toolBar_100_100_icon_ chart.bar.doc.horizontal.png
├── toolbar_100_100_icon_axes.png
├── toolbar_100_100_icon_instances.png
├── toolbar_100_100_icon_location_labels.png
├── toolbar_100_100_icon_notes.png
├── toolbar_100_100_icon_notifications.png
├── toolbar_100_100_icon_problems.png
├── toolbar_100_100_icon_rules.png
├── toolbar_100_100_icon_save.png
├── toolbar_100_100_icon_settings.png
├── toolbar_100_100_icon_sources.png
├── toolbar_100_100_icon_variable_fonts.png
├── toolbar_100_100_icon_variable_notifications.png
├── toolbar_100_100_info.bubble.fill.png
├── toolbar_100_100_info.circle.fill.png
├── toolbar_100_100_info.circle.png
├── toolbar_100_100_questionmark.circle.png
├── toolbar_100_100_square.and.arrow.down.png
├── toolbar_500_500_icon_axes.png
├── toolbar_500_500_icon_instances.png
├── toolbar_500_500_icon_location_labels.png
├── toolbar_500_500_icon_notes.png
├── toolbar_500_500_icon_notifications.png
├── toolbar_500_500_icon_problems.png
├── toolbar_500_500_icon_rules.png
├── toolbar_500_500_icon_sources.png
└── toolbar_500_500_icon_variable_fonts.png
├── icons
├── all_icons_1000_1000_dse2_preview.pdf
├── export_SF_Symbol.py
├── info.bubble.fill_info.bubble.fill.svg
├── info.circle.fill_info.circle.fill.svg
├── info.circle_info.circle.svg
├── makeIcons_dse1.py
├── makeIcons_dse2.py
├── questionmark.circle_questionmark.circle.svg
├── roundedRect.py
├── square.and.arrow.down_square.and.arrow.down.svg
├── toolbar_1000_1000_icon_axes.png
├── toolbar_1000_1000_icon_instances.png
├── toolbar_1000_1000_icon_location_labels.png
├── toolbar_1000_1000_icon_notes.png
├── toolbar_1000_1000_icon_notifications.png
├── toolbar_1000_1000_icon_problems.png
├── toolbar_1000_1000_icon_rules.png
├── toolbar_1000_1000_icon_sources.png
├── toolbar_1000_1000_icon_variable_fonts.png
├── toolbar_1000_1000_icon_variable_notifications.png
├── toolbar_1000_1000_info.bubble.fill.pdf
├── toolbar_1000_1000_info.circle.fill.pdf
├── toolbar_1000_1000_info.circle.pdf
├── toolbar_1000_1000_questionmark.circle.pdf
├── toolbar_1000_1000_square.and.arrow.down.pdf
├── toolbar_30_30_arrow.right.filled.filter.arrow.right_arrow.right.filled.filter.arrow.right.pdf
├── toolbar_30_30_atom.pdf
├── toolbar_30_30_info.bubble.fill.pdf
├── toolbar_30_30_info.circle.fill.pdf
├── toolbar_30_30_info.circle.pdf
├── toolbar_30_30_questionmark.circle.pdf
├── toolbar_30_30_square.and.arrow.down.pdf
├── toolbar_30_30_wand.and.stars.pdf
├── toolbar_500_500_info.bubble.fill.png
├── toolbar_500_500_info.circle.fill.png
├── toolbar_500_500_info.circle.png
├── toolbar_500_500_questionmark.circle.png
├── toolbar_500_500_square.and.arrow.down.png
└── wand.and.stars_wand.and.stars.svg
└── instancestab_mathmodel_dialog.png
/.github/workflows/static.yml:
--------------------------------------------------------------------------------
1 | # Simple workflow for deploying static content to GitHub Pages
2 | name: Deploy static content to Pages
3 |
4 | on:
5 | # Runs on pushes targeting the default branch
6 | push:
7 | branches: ["master"]
8 |
9 | # Allows you to run this workflow manually from the Actions tab
10 | workflow_dispatch:
11 |
12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
13 | permissions:
14 | contents: read
15 | pages: write
16 | id-token: write
17 |
18 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
19 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
20 | concurrency:
21 | group: "pages"
22 | cancel-in-progress: false
23 |
24 | jobs:
25 | # Single deploy job since we're just deploying
26 | deploy:
27 | environment:
28 | name: github-pages
29 | url: ${{ steps.deployment.outputs.page_url }}
30 | runs-on: ubuntu-latest
31 | steps:
32 | - name: Checkout
33 | uses: actions/checkout@v3
34 | - name: Setup Pages
35 | uses: actions/configure-pages@v3
36 | - name: Upload artifact
37 | uses: actions/upload-pages-artifact@v3
38 | with:
39 | # Upload entire repository
40 | path: './DesignspaceEditor2.roboFontExt/html'
41 | - name: Deploy to GitHub Pages
42 | id: deployment
43 | uses: actions/deploy-pages@v4
44 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | test.designspace
2 | build.py
3 | __pycache__
4 | *.pyc
5 | DesignSpaceEditor.roboFontExt/lib/.pytest_cache
6 | issues
7 | .DS_Store
8 | .pytest_cache
9 |
--------------------------------------------------------------------------------
/DSEezui.py:
--------------------------------------------------------------------------------
1 | import AppKit
2 | import ezui
3 |
4 | from lib.cells.doubleClickCell import RFDoubleClickCell
5 |
6 | from mojo.extensions import getExtensionDefault, ExtensionBundle
7 |
8 |
9 | designspaceBundle = ExtensionBundle("DesignspaceEditor2")
10 |
11 | numberFormatter = AppKit.NSNumberFormatter.alloc().init()
12 | numberFormatter.setNumberStyle_(AppKit.NSNumberFormatterDecimalStyle)
13 | numberFormatter.setAllowsFloats_(True)
14 | numberFormatter.setLocalizesFormat_(False)
15 | numberFormatter.setUsesGroupingSeparator_(False)
16 |
17 | infoImage = AppKit.NSImage.imageWithSystemSymbolName_accessibilityDescription_("info.circle.fill", None)
18 |
19 |
20 | def doubleClickCell(callback, image=None):
21 | cell = RFDoubleClickCell.alloc().init()
22 | cell.setDoubleClickCallback_(callback)
23 | cell.setImage_(image)
24 | return cell
25 |
26 |
27 | class Controller(ezui.WindowController):
28 |
29 | def build(self):
30 | content = """
31 | = ToolbarTabs
32 | * ToolbarTab: Axis @axisTab
33 | > |---| @axisTable
34 | > * HorizontalStack @axisStack
35 | >> (+-)
36 | >> (...) @axisActions
37 |
38 | * ToolbarTab: Sources @sourcesTab
39 | >|---| @sourcesTable
40 | > * HorizontalStack @sourcesStack
41 | >> (+-)
42 | >> (...) @sourcesActions
43 |
44 | * ToolbarTab: Intances @instancesTab
45 | > |---| @instancesTable
46 | > * HorizontalStack @instancesStack
47 | >> (+-)
48 | >> ( Preview Instances ) @instancesPreview
49 | >> (...) @instancesActions
50 |
51 | * ToolbarTab: Rules @rulesTab
52 | > * CodeEditor @rulesEditor
53 |
54 | * ToolbarTab: Labels @labelsTab
55 | > * CodeEditor @labelsEditor
56 | > * HorizontalStack @labelsStack
57 | >> ( Preview Labels ) @labelsPreviewButton
58 |
59 |
60 | * ToolbarTab: Problems @problemsTab
61 | > |---| @problemsTable
62 | > * HorizontalStack @problemsStack
63 | >> ( Validate Designspace ) @problemsValidateButton
64 |
65 | * ToolbarTab: Notes @notesTab
66 | > [[__]] @notesEditor
67 | """
68 |
69 | marginDescriptions = dict(margins=(10, 0, 10, 10))
70 | descriptionData = dict(
71 | axisTab=dict(
72 | image=designspaceBundle.getResourceImage("toolbar_30_30_icon_axes")
73 | ),
74 | axisStack=marginDescriptions,
75 | axisTable=dict(
76 | width="fill",
77 | height="fill",
78 | columnDescriptions=[
79 | dict(title="", identifier="genericInfoButton", width=20, editable=False, cell=doubleClickCell(self.axisListDoubleClickCallback, infoImage)),#, cell=axisDoubleClickCell),
80 | dict(title="Ⓡ", identifier="axisRegisterd", width=20, allowsSorting=False, editable=False),
81 | dict(title="Name", identifier="axisName", allowsSorting=False, editable=True),
82 | dict(title="Tag", identifier="axisTag", width=70, allowsSorting=False, editable=True),
83 | dict(title="Minimum", identifier="axisMinimum", width=70, allowsSorting=False, editable=True, formatter=numberFormatter),
84 | dict(title="Default", identifier="axisDefault", width=70, allowsSorting=False, editable=True, formatter=numberFormatter),
85 | dict(title="Maximum", identifier="axisMaximum", width=70, allowsSorting=False, editable=True, formatter=numberFormatter),
86 | dict(title="Discrete Values", identifier="axisDiscreteValues", width=100, allowsSorting=False, editable=True),
87 |
88 | dict(title="Hidden", identifier="axisHidden", width=50, cellType="Checkbox", allowsSorting=False, editable=True),
89 | dict(title="📈", identifier="axisHasMap", width=20, allowsSorting=False, editable=False),
90 | dict(title="🏷️", identifier="axisHasLabels", width=20, allowsSorting=False, editable=False),
91 | ]
92 | ),
93 | axisActions=dict(
94 | itemDescriptions=[
95 | dict(identifier="axisAddWeightAxis", text="Add Weight Axis"),
96 | dict(identifier="axisAddWidthAxis", text="Add Width Axis"),
97 | dict(identifier="axisAddOpticalAxis", text="Add Optical Axis"),
98 | ]
99 | ),
100 |
101 | sourcesTab=dict(
102 | image=designspaceBundle.getResourceImage("toolbar_30_30_icon_sources")
103 | ),
104 | sourcesStack=marginDescriptions,
105 | sourcesTable=dict(
106 | width="fill",
107 | height="fill",
108 | columnDescriptions=[
109 | dict(title="", identifier="genericInfoButton", width=20, editable=False, cell=doubleClickCell(self.sourceListDoubleClickCallback, infoImage)),
110 | dict(title="💾", identifier="sourceHasPath", width=20, editable=False),
111 | dict(title="📍", identifier="sourceIsDefault", width=20, editable=False),
112 | dict(title="UFO", identifier="sourceUFOFileName", width=200, minWidth=100, maxWidth=350, editable=False),
113 | dict(title="Family Name", identifier="sourceFamilyName", editable=True, width=130, minWidth=130, maxWidth=250),
114 | dict(title="Style Name", identifier="sourceStyleName", editable=True, width=130, minWidth=130, maxWidth=250),
115 | dict(title="Layer Name", identifier="sourceLayerName", editable=True, width=130, minWidth=130, maxWidth=250),
116 | dict(title="🌐", identifier="sourceHasLocalisedFamilyNames", width=20, allowsSorting=False, editable=False),
117 | dict(title="🔕", identifier="sourceHasMutedGlyphs", width=20, allowsSorting=False, editable=False),
118 | ]
119 | ),
120 | sourcesActions=dict(
121 | itemDescriptions=[
122 | dict(identifier="basicItem", text="Open source UFO"),
123 | "----",
124 | dict(identifier="basicItem", text="Add Open UFOs"),
125 | dict(identifier="basicItem", text="Replace UFO"),
126 | ]
127 | ),
128 |
129 | instancesTab=dict(
130 | image=designspaceBundle.getResourceImage("toolbar_30_30_icon_instances")
131 | ),
132 | instancesStack=marginDescriptions,
133 | instancesTable=dict(
134 | width="fill",
135 | height="fill",
136 | columnDescriptions=[
137 | dict(title="UFO", identifier="instanceUFOFileName", width=200, minWidth=100, maxWidth=350, editable=False),
138 | dict(title="Family Name", identifier="instanceFamilyName", editable=True, width=130, minWidth=130, maxWidth=250),
139 | dict(title="Style Name", identifier="instanceStyleName", editable=True, width=130, minWidth=130, maxWidth=250),
140 | ]
141 | ),
142 | instancesActions=dict(
143 | itemDescriptions=[
144 | dict(identifier="basicItem", text="Duplicate Instance"),
145 | dict(identifier="basicItem", text="Add Sources as Instances"),
146 | "----",
147 | dict(identifier="basicItem", text="Generate With MutatorMath"),
148 | dict(identifier="basicItem", text="Generate With VarLib"),
149 | ]
150 | ),
151 |
152 | rulesTab=dict(
153 | image=designspaceBundle.getResourceImage("toolbar_30_30_icon_rules")
154 | ),
155 | rulesEditor=dict(
156 | width="fill",
157 | height="fill",
158 | showLineNumbers=False
159 | ),
160 |
161 | labelsTab=dict(
162 | image=designspaceBundle.getResourceImage("toolbar_30_30_icon_labels")
163 | ),
164 | labelsStack=marginDescriptions,
165 | labelsEditor=dict(
166 | width="fill",
167 | height="fill",
168 | showLineNumbers=False
169 | ),
170 | labelsActions=dict(
171 | itemDescriptions=[
172 | dict(identifier="basicItem", text="Preview Labels"),
173 | ]
174 | ),
175 |
176 | problemsTab=dict(
177 | image=designspaceBundle.getResourceImage("toolbar_30_30_icon_problems")
178 | ),
179 | problemsStack=marginDescriptions,
180 | problemsTable=dict(
181 | width="fill",
182 | height="fill",
183 | columnDescriptions = [
184 | dict(title="", identifier="problemIcon", width=20),
185 | dict(title="Where", identifier="problemClass", width=130),
186 | dict(title="What", identifier="problemDescription", minWidth=200, width=200, maxWidth=1000),
187 | dict(title="Specifically", identifier="problemData", minWidth=200, width=200, maxWidth=1000),
188 | ]
189 | ),
190 |
191 | notesTab=dict(
192 | image=designspaceBundle.getResourceImage("toolbar_30_30_icon_notes")
193 | ),
194 | notesEditor=dict(
195 | width="fill",
196 | height="fill",
197 | ),
198 |
199 |
200 | )
201 | self.w = ezui.EZWindow(
202 | title="Title",
203 | content=content,
204 | descriptionData=descriptionData,
205 | size=(800, 500),
206 | minSize=(800, 500),
207 | controller=self,
208 | margins=0
209 | )
210 |
211 | self.w.addToolbarItem(dict(itemIdentifier=AppKit.NSToolbarSpaceItemIdentifier))
212 | self.w.addToolbarItem(dict(
213 | itemIdentifier="save",
214 | label="Save",
215 | imageObject=ezui.makeImage(symbolName="square.and.arrow.down", symbolConfiguration=dict(renderingMode="hierarchical", colors=[(1, 0, 1, 1), ])),
216 | callback=self.toobarSaveCallback
217 | ))
218 | self.w.addToolbarItem(dict(
219 | itemIdentifier="help",
220 | label="Help",
221 | imageObject=ezui.makeImage(symbolName="questionmark.circle", symbolConfiguration=dict(renderingMode="hierarchical", colors=[(1, 0, 1, 1), ])),
222 | callback=self.toolbarHelpCallback
223 | ))
224 |
225 | def started(self):
226 | self.w.open()
227 |
228 | # axis
229 |
230 | def axisListDoubleClickCallback(self, sender):
231 | print("axisListDoubleClickCallback")
232 |
233 | def axisAddWeightAxisCallback(self, sender):
234 | print("axisAddWeightAxisCallback")
235 |
236 | def axisAddWidthAxisCallback(self, sender):
237 | print("axisAddWidthAxisCallback")
238 |
239 | def axisAddOpticalAxisCallback(self, sender):
240 | print("axisAddOpticalAxisCallback")
241 |
242 | # sources
243 |
244 | def sourceListDoubleClickCallback(self, sender):
245 | print("sourceListDoubleClickCallback")
246 |
247 | # instances
248 |
249 |
250 | # toolbar
251 |
252 | def toobarSaveCallback(self, sender):
253 | print("save")
254 |
255 | def toolbarHelpCallback(self, sender):
256 | print("help")
257 |
258 |
259 | Controller()
260 |
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/chart.bar.doc.horizontal2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/chart.bar.doc.horizontal2x.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/previewWindow.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/previewWindow.jpg
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/previewWindow_options2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/previewWindow_options2.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/questionmark.circle2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/questionmark.circle2x.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_axestab.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_axestab.jpg
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_axestab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_axestab.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_instancestab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_instancestab.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_previewwindow1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_previewwindow1.jpg
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_problemstab.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_problemstab.jpg
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_rulestab.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_rulestab.jpg
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_sourcestab.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_sourcestab.jpg
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_variablefontstab.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/screenshot_mutatorsans_variablefontstab.jpg
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/sparse_master.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/sparse_master.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/square.and.arrow.down2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/square.and.arrow.down2x.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/styles.css:
--------------------------------------------------------------------------------
1 | html {
2 | max-width: 800px;
3 | padding: 15px;
4 | margin-left: auto;
5 | margin-right: auto;
6 | }
7 | body {
8 | -ms-text-size-adjust: 100%;
9 | -webkit-text-size-adjust: 100%;
10 | line-height: 1.5;
11 | color: #333;
12 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
13 | font-size: 16px;
14 | line-height: 1.5;
15 | word-wrap: break-word;
16 | }
17 | .smallicon{
18 | width: 80pt;
19 | padding: 20pt;
20 | font-size: 10pt;
21 | margin-left: auto;
22 | margin-right: auto;
23 | }
24 | .bigicon{
25 | margin-top: 80pt;
26 | }
27 | .caption{
28 | font-size:10pt;
29 | }
30 | body .pl-c {
31 | color: #969896;
32 | }
33 | body .pl-c1,
34 | body .pl-s .pl-v {
35 | color: #0086b3;
36 | }
37 | body .pl-e,
38 | body .pl-en {
39 | color: #795da3;
40 | }
41 | body .pl-s .pl-s1,
42 | body .pl-smi {
43 | color: #333;
44 | }
45 | body .pl-ent {
46 | color: #63a35c;
47 | }
48 | body .pl-k {
49 | color: #a71d5d;
50 | }
51 | body .pl-pds,
52 | body .pl-s,
53 | body .pl-s .pl-pse .pl-s1,
54 | body .pl-sr,
55 | body .pl-sr .pl-cce,
56 | body .pl-sr .pl-sra,
57 | body .pl-sr .pl-sre {
58 | color: #183691;
59 | }
60 | body .pl-v {
61 | color: #ed6a43;
62 | }
63 | body .pl-id {
64 | color: #b52a1d;
65 | }
66 | body .pl-ii {
67 | color: #f8f8f8;
68 | background-color: #b52a1d;
69 | }
70 | body .pl-sr .pl-cce {
71 | font-weight: 700;
72 | color: #63a35c;
73 | }
74 | body .pl-ml {
75 | color: #693a17;
76 | }
77 | body .pl-mh,
78 | body .pl-mh .pl-en,
79 | body .pl-ms {
80 | font-weight: 700;
81 | color: #1d3e81;
82 | }
83 | body .pl-mq {
84 | color: teal;
85 | }
86 | body .pl-mi {
87 | font-style: italic;
88 | color: #333;
89 | }
90 | body .pl-mb {
91 | font-weight: 700;
92 | color: #333;
93 | }
94 | body .pl-md {
95 | color: #bd2c00;
96 | background-color: #ffecec;
97 | }
98 | body .pl-mi1 {
99 | color: #55a532;
100 | background-color: #eaffea;
101 | }
102 | body .pl-mdr {
103 | font-weight: 700;
104 | color: #795da3;
105 | }
106 | body .pl-mo {
107 | color: #1d3e81;
108 | }
109 | body .octicon {
110 | display: inline-block;
111 | vertical-align: text-top;
112 | fill: currentColor;
113 | }
114 | body a {
115 | background-color: transparent;
116 | -webkit-text-decoration-skip: objects;
117 | }
118 | body a:active,
119 | body a:hover {
120 | outline-width: 0;
121 | }
122 | body strong {
123 | font-weight: inherit;
124 | }
125 | body strong {
126 | font-weight: bolder;
127 | }
128 | body h1 {
129 | font-size: 2em;
130 | margin: 0.67em 0;
131 | }
132 | body img {
133 | border-style: none;
134 | }
135 | body svg:not(:root) {
136 | overflow: hidden;
137 | }
138 | body code,
139 | body kbd,
140 | body pre {
141 | font-family: monospace, monospace;
142 | font-size: 1em;
143 | }
144 | body hr {
145 | box-sizing: content-box;
146 | height: 0;
147 | overflow: visible;
148 | }
149 | body input {
150 | font: inherit;
151 | margin: 0;
152 | }
153 | body input {
154 | overflow: visible;
155 | }
156 | body [type="checkbox"] {
157 | box-sizing: border-box;
158 | padding: 0;
159 | }
160 | body * {
161 | box-sizing: border-box;
162 | }
163 | body input {
164 | font-family: inherit;
165 | font-size: inherit;
166 | line-height: inherit;
167 | }
168 | body a {
169 | color: #4078c0;
170 | text-decoration: none;
171 | }
172 | body a:active,
173 | body a:hover {
174 | text-decoration: underline;
175 | }
176 | body strong {
177 | font-weight: 600;
178 | }
179 | body hr {
180 | height: 0;
181 | margin: 15px 0;
182 | overflow: hidden;
183 | background: 0 0;
184 | border: 0;
185 | border-bottom: 1px solid #ddd;
186 | }
187 | body hr::before {
188 | display: table;
189 | content: "";
190 | }
191 | body hr::after {
192 | display: table;
193 | clear: both;
194 | content: "";
195 | }
196 | body table {
197 | border-spacing: 0;
198 | border-collapse: collapse;
199 | }
200 | body td,
201 | body th {
202 | padding: 0;
203 | }
204 | body h1,
205 | body h2,
206 | body h3,
207 | body h4,
208 | body h5,
209 | body h6 {
210 | margin-top: 0;
211 | margin-bottom: 0;
212 | }
213 | body h1 {
214 | font-size: 32px;
215 | font-weight: 600;
216 | }
217 | body h2 {
218 | font-size: 24px;
219 | font-weight: 600;
220 | }
221 | body h3 {
222 | font-size: 20px;
223 | font-weight: 600;
224 | }
225 | body h4 {
226 | font-size: 16px;
227 | font-weight: 600;
228 | }
229 | body h5 {
230 | font-size: 14px;
231 | font-weight: 600;
232 | }
233 | body h6 {
234 | font-size: 12px;
235 | font-weight: 600;
236 | }
237 | body p {
238 | margin-top: 0;
239 | margin-bottom: 10px;
240 | }
241 | body blockquote {
242 | margin: 0;
243 | }
244 | body ol,
245 | body ul {
246 | padding-left: 0;
247 | margin-top: 0;
248 | margin-bottom: 0;
249 | }
250 | body ol ol,
251 | body ul ol {
252 | list-style-type: lower-roman;
253 | }
254 | body ol ol ol,
255 | body ol ul ol,
256 | body ul ol ol,
257 | body ul ul ol {
258 | list-style-type: lower-alpha;
259 | }
260 | body dd {
261 | margin-left: 0;
262 | }
263 | body code {
264 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
265 | font-size: 12px;
266 | }
267 | body pre {
268 | margin-top: 0;
269 | margin-bottom: 0;
270 | font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
271 | }
272 | body .octicon {
273 | vertical-align: text-bottom;
274 | }
275 | body input {
276 | -webkit-font-feature-settings: "liga" 0;
277 | font-feature-settings: "liga" 0;
278 | }
279 | body::before {
280 | display: table;
281 | content: "";
282 | }
283 | body::after {
284 | display: table;
285 | clear: both;
286 | content: "";
287 | }
288 | body > :first-child {
289 | margin-top: 0 !important;
290 | }
291 | body > :last-child {
292 | margin-bottom: 0 !important;
293 | }
294 | body a:not([href]) {
295 | color: inherit;
296 | text-decoration: none;
297 | }
298 | body .anchor {
299 | float: left;
300 | padding-right: 4px;
301 | margin-left: -20px;
302 | line-height: 1;
303 | }
304 | body .anchor:focus {
305 | outline: 0;
306 | }
307 | body blockquote,
308 | body dl,
309 | body ol,
310 | body p,
311 | body pre,
312 | body table,
313 | body ul {
314 | margin-top: 0;
315 | margin-bottom: 16px;
316 | }
317 | body hr {
318 | height: 0.25em;
319 | padding: 0;
320 | margin: 24px 0;
321 | background-color: #e7e7e7;
322 | border: 0;
323 | }
324 | body blockquote {
325 | padding: 0 1em;
326 | color: #777;
327 | border-left: 0.25em solid #ddd;
328 | }
329 | body blockquote > :first-child {
330 | margin-top: 0;
331 | }
332 | body blockquote > :last-child {
333 | margin-bottom: 0;
334 | }
335 | body kbd {
336 | display: inline-block;
337 | padding: 3px 5px;
338 | font-size: 11px;
339 | line-height: 10px;
340 | color: #555;
341 | vertical-align: middle;
342 | background-color: #fcfcfc;
343 | border: solid 1px #ccc;
344 | border-bottom-color: #bbb;
345 | border-radius: 3px;
346 | box-shadow: inset 0 -1px 0 #bbb;
347 | }
348 | body h1,
349 | body h2,
350 | body h3,
351 | body h4,
352 | body h5,
353 | body h6 {
354 | margin-top: 30pt;
355 | margin-bottom: 16px;
356 | font-weight: 600;
357 | line-height: 1.25;
358 | }
359 | body h1 .octicon-link,
360 | body h2 .octicon-link,
361 | body h3 .octicon-link,
362 | body h4 .octicon-link,
363 | body h5 .octicon-link,
364 | body h6 .octicon-link {
365 | color: #000;
366 | vertical-align: middle;
367 | visibility: hidden;
368 | }
369 | body h1:hover .anchor,
370 | body h2:hover .anchor,
371 | body h3:hover .anchor,
372 | body h4:hover .anchor,
373 | body h5:hover .anchor,
374 | body h6:hover .anchor {
375 | text-decoration: none;
376 | }
377 | body h1:hover .anchor .octicon-link,
378 | body h2:hover .anchor .octicon-link,
379 | body h3:hover .anchor .octicon-link,
380 | body h4:hover .anchor .octicon-link,
381 | body h5:hover .anchor .octicon-link,
382 | body h6:hover .anchor .octicon-link {
383 | visibility: visible;
384 | }
385 | body h1 {
386 | padding-bottom: 0.3em;
387 | font-size: 2em;
388 | border-bottom: 1px solid #eee;
389 | }
390 | body h2 {
391 | padding-bottom: 0.3em;
392 | font-size: 1.5em;
393 | border-bottom: 1px solid #eee;
394 | }
395 | body h3 {
396 | font-size: 1.25em;
397 | }
398 | body h4 {
399 | font-size: 1em;
400 | }
401 | body h5 {
402 | font-size: 0.875em;
403 | }
404 | body h6 {
405 | font-size: 0.85em;
406 | color: #777;
407 | }
408 | body ol,
409 | body ul {
410 | padding-left: 2em;
411 | }
412 | body ol ol,
413 | body ol ul,
414 | body ul ol,
415 | body ul ul {
416 | margin-top: 0;
417 | margin-bottom: 0;
418 | }
419 | body li > p {
420 | margin-top: 16px;
421 | }
422 | body li + li {
423 | margin-top: 0.25em;
424 | }
425 | body dl {
426 | padding: 0;
427 | }
428 | body dl dt {
429 | padding: 0;
430 | margin-top: 16px;
431 | font-size: 1em;
432 | font-style: italic;
433 | font-weight: 700;
434 | }
435 | body dl dd {
436 | padding: 0 16px;
437 | margin-bottom: 16px;
438 | }
439 | body table {
440 | display: block;
441 | width: 100%;
442 | overflow: auto;
443 | }
444 | body table th {
445 | font-weight: 700;
446 | }
447 | body table td,
448 | body table th {
449 | padding: 6px 13px;
450 | border: 1px solid #ddd;
451 | }
452 | body table tr {
453 | background-color: #fff;
454 | border-top: 1px solid #ccc;
455 | }
456 | body table tr:nth-child(2n) {
457 | background-color: #f8f8f8;
458 | }
459 | body img {
460 | max-width: 100%;
461 | box-sizing: content-box;
462 | background-color: #fff;
463 | }
464 | body code {
465 | padding: 0;
466 | padding-top: 0.2em;
467 | padding-bottom: 0.2em;
468 | margin: 0;
469 | font-size: 85%;
470 | background-color: rgba(0, 0, 0, 0.04);
471 | border-radius: 3px;
472 | }
473 | body pre {
474 | word-wrap: normal;
475 | }
476 | body pre > code {
477 | padding: 0;
478 | margin: 0;
479 | font-size: 100%;
480 | word-break: normal;
481 | white-space: pre;
482 | background: 0 0;
483 | border: 0;
484 | }
485 | body .highlight {
486 | margin-bottom: 16px;
487 | }
488 | body .highlight pre {
489 | margin-bottom: 0;
490 | word-break: normal;
491 | }
492 | body .highlight pre,
493 | body pre {
494 | padding: 16px;
495 | overflow: auto;
496 | font-size: 85%;
497 | line-height: 1.45;
498 | background-color: #f7f7f7;
499 | border-radius: 3px;
500 | }
501 | body pre code {
502 | display: inline;
503 | max-width: auto;
504 | padding: 0;
505 | margin: 0;
506 | overflow: visible;
507 | line-height: inherit;
508 | word-wrap: normal;
509 | background-color: transparent;
510 | border: 0;
511 | }
512 | body pre code::after,
513 | body pre code::before {
514 | content: normal;
515 | }
516 | body .pl-0 {
517 | padding-left: 0 !important;
518 | }
519 | body .pl-1 {
520 | padding-left: 3px !important;
521 | }
522 | body .pl-2 {
523 | padding-left: 6px !important;
524 | }
525 | body .pl-3 {
526 | padding-left: 12px !important;
527 | }
528 | body .pl-4 {
529 | padding-left: 24px !important;
530 | }
531 | body .pl-5 {
532 | padding-left: 36px !important;
533 | }
534 | body .pl-6 {
535 | padding-left: 48px !important;
536 | }
537 | body .full-commit .btn-outline:not(:disabled):hover {
538 | color: #4078c0;
539 | border: 1px solid #4078c0;
540 | }
541 | body kbd {
542 | display: inline-block;
543 | padding: 3px 5px;
544 | font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
545 | line-height: 10px;
546 | color: #555;
547 | vertical-align: middle;
548 | background-color: #fcfcfc;
549 | border: solid 1px #ccc;
550 | border-bottom-color: #bbb;
551 | border-radius: 3px;
552 | box-shadow: inset 0 -1px 0 #bbb;
553 | }
554 | body :checked + .radio-label {
555 | position: relative;
556 | z-index: 1;
557 | border-color: #4078c0;
558 | }
559 | body .task-list-item {
560 | list-style-type: none;
561 | }
562 | body .task-list-item + .task-list-item {
563 | margin-top: 3px;
564 | }
565 | body .task-list-item input {
566 | margin: 0 0.2em 0.25em -1.6em;
567 | vertical-align: middle;
568 | }
569 | body hr {
570 | border-bottom-color: #eee;
571 | }
572 | .codehilite .c {
573 | color: #999;
574 | }
575 | .codehilite .err {
576 | color: red;
577 | }
578 | .codehilite .g {
579 | color: #363636;
580 | }
581 | .codehilite .k {
582 | color: #4998ff;
583 | }
584 | .codehilite .l {
585 | color: #93a1a1;
586 | }
587 | .codehilite .n {
588 | color: #363636;
589 | }
590 | .codehilite .o {
591 | color: #aa25ff;
592 | }
593 | .codehilite .x {
594 | color: #cb4b16;
595 | }
596 | .codehilite .p {
597 | color: #93a1a1;
598 | }
599 | .codehilite .cm {
600 | color: #586e75;
601 | }
602 | .codehilite .cp {
603 | color: #aa25ff;
604 | }
605 | .codehilite .c1 {
606 | color: #586e75;
607 | }
608 | .codehilite .cs {
609 | color: #aa25ff;
610 | }
611 | .codehilite .gd {
612 | color: #2aa198;
613 | }
614 | .codehilite .ge {
615 | color: #93a1a1;
616 | font-style: italic;
617 | }
618 | .codehilite .gr {
619 | color: #dc322f;
620 | }
621 | .codehilite .gh {
622 | color: #cb4b16;
623 | }
624 | .codehilite .gi {
625 | color: #aa25ff;
626 | }
627 | .codehilite .go {
628 | color: #93a1a1;
629 | }
630 | .codehilite .gp {
631 | color: #93a1a1;
632 | }
633 | .codehilite .gs {
634 | color: #93a1a1;
635 | font-weight: 700;
636 | }
637 | .codehilite .gu {
638 | color: #cb4b16;
639 | }
640 | .codehilite .gt {
641 | color: #93a1a1;
642 | }
643 | .codehilite .kc {
644 | color: #cb4b16;
645 | }
646 | .codehilite .kd {
647 | color: #268bd2;
648 | }
649 | .codehilite .kn {
650 | color: #4998ff;
651 | }
652 | .codehilite .kp {
653 | color: #aa25ff;
654 | }
655 | .codehilite .kr {
656 | color: #268bd2;
657 | }
658 | .codehilite .kt {
659 | color: #dc322f;
660 | }
661 | .codehilite .ld {
662 | color: #c42f07;
663 | }
664 | .codehilite .m {
665 | color: #c42f07;
666 | }
667 | .codehilite .s {
668 | color: #ff05da;
669 | }
670 | .codehilite .na {
671 | color: #93a1a1;
672 | }
673 | .codehilite .nb {
674 | color: #0bd51e;
675 | }
676 | .codehilite .nc {
677 | color: #ff3ca8;
678 | }
679 | .codehilite .no {
680 | color: #ff3ca8;
681 | }
682 | .codehilite .nd {
683 | color: #ff3ca8;
684 | }
685 | .codehilite .ni {
686 | color: #ff3ca8;
687 | }
688 | .codehilite .ne {
689 | color: #ff3ca8;
690 | }
691 | .codehilite .nf {
692 | color: #ff3ca8;
693 | }
694 | .codehilite .nl {
695 | color: #ff3ca8;
696 | }
697 | .codehilite .nn {
698 | color: #354980;
699 | }
700 | .codehilite .nx {
701 | color: #555;
702 | }
703 | .codehilite .py {
704 | color: #93a1a1;
705 | }
706 | .codehilite .nt {
707 | color: #268bd2;
708 | }
709 | .codehilite .nv {
710 | color: #268bd2;
711 | }
712 | .codehilite .ow {
713 | color: #aa25ff;
714 | }
715 | .codehilite .w {
716 | color: #93a1a1;
717 | }
718 | .codehilite .mf {
719 | color: #c42f07;
720 | }
721 | .codehilite .mh {
722 | color: #c42f07;
723 | }
724 | .codehilite .mi {
725 | color: #c42f07;
726 | }
727 | .codehilite .mo {
728 | color: #c42f07;
729 | }
730 | .codehilite .sb {
731 | color: #ff05da;
732 | }
733 | .codehilite .sc {
734 | color: #ff05da;
735 | }
736 | .codehilite .sd {
737 | color: #ff05da;
738 | }
739 | .codehilite .s2 {
740 | color: #ff05da;
741 | }
742 | .codehilite .se {
743 | color: #ff05da;
744 | }
745 | .codehilite .sh {
746 | color: #ff05da;
747 | }
748 | .codehilite .si {
749 | color: #ff05da;
750 | }
751 | .codehilite .sx {
752 | color: #ff05da;
753 | }
754 | .codehilite .sr {
755 | color: #ff05da;
756 | }
757 | .codehilite .s1 {
758 | color: #ff05da;
759 | }
760 | .codehilite .ss {
761 | color: #ff05da;
762 | }
763 | .codehilite .bp {
764 | color: #f29108;
765 | }
766 | .codehilite .vc {
767 | color: #268bd2;
768 | }
769 | .codehilite .vg {
770 | color: #268bd2;
771 | }
772 | .codehilite .vi {
773 | color: #268bd2;
774 | }
775 | .codehilite .il {
776 | color: #c42f07;
777 | }
778 |
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/toolbar_25_25_info.circle.fill.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_axes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_axes.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_instances.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_instances.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_location_labels.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_location_labels.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_notes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_notes.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_notifications.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_notifications.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_problems.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_problems.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_rules.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_rules.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_save.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_settings.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_sources.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_sources.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_variable_fonts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/html/toolbar_500_500_icon_variable_fonts.png
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | addToMenu
6 |
7 |
8 | developer
9 | Letterror
10 | developerURL
11 | https://letterror.com
12 | html
13 |
14 | launchAtStartUp
15 | 1
16 | mainScript
17 | main.py
18 | name
19 | Designspace Editor 2
20 | requiresVersionMajor
21 | 4
22 | requiresVersionMinor
23 | 5b
24 | timeStamp
25 | 1653936779.9141068
26 | version
27 | 2.8
28 |
29 |
30 |
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/lib/designspaceEditor/__init__.py:
--------------------------------------------------------------------------------
1 | extensionIdentifier = "com.letterror.designspaceEditor"
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/lib/designspaceEditor/designspaceLexer.py:
--------------------------------------------------------------------------------
1 | from pygments.lexer import RegexLexer, include, bygroups
2 | from pygments.lexers.special import TextLexer
3 | from pygments.token import *
4 |
5 |
6 | class DesignspaceLexer(RegexLexer):
7 | name = "Designspace"
8 | aliases = ['designspace']
9 | filenames = ['*.designspace']
10 |
11 | tokens = {
12 | 'root': [
13 | (r'\n', Whitespace),
14 | (r'#.*$', Comment),
15 | (r'[\'|\"].*[\'|\"]', String),
16 | (r'(\?)\s+((?:[a-zA-Z0-9\-]+))\s+', bygroups(Name.Builtin, Name.Variable)),
17 | (r'\((elidable|olderSibling)\)', Name.Variable),
18 | (r'\[([0-9\.]+)\]', Name.Variable),
19 | (r'\>|\?|\-|\*', Name.Builtin),
20 | include('numbers'),
21 | (r'^[^\s].*$', Keyword.Namespace), # Name.Class
22 | (r'(weight|width|italic|optical|slant)\b', Keyword),
23 | (r'[\w\.\*\+\-\:\^\|\~]+', Text),
24 | ],
25 | 'numbers': [
26 | (r'(\d+\.\d*|\d*\.\d+)([eE][+-]?[0-9]+)?j?', Number.Float),
27 | (r'\d+[eE][+-]?[0-9]+j?', Number.Float),
28 | (r'0[0-7]+j?', Number.Oct),
29 | (r'0[xX][a-fA-F0-9]+', Number.Hex),
30 | (r'\d+L', Number.Integer.Long),
31 | (r'\d+j?', Number.Integer)
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/lib/designspaceEditor/designspaceSubscribers.py:
--------------------------------------------------------------------------------
1 | import AppKit
2 | from objc import python_method, super
3 |
4 | from lib.tools.debugTools import ClassNameIncrementer
5 |
6 | from mojo.subscriber import Subscriber, registerGlyphEditorSubscriber, registerCurrentFontSubscriber, registerRoboFontSubscriber
7 |
8 | from designspaceEditor.tools import SendNotification
9 |
10 |
11 | class OperatorRegistry(AppKit.NSObject, metaclass=ClassNameIncrementer):
12 |
13 | def init(self):
14 | self = super().init()
15 | self.operators = []
16 | self.currentOperator = None
17 |
18 | center = AppKit.NSNotificationCenter.defaultCenter()
19 | center.addObserver_selector_name_object_(self, "windowBecomeMain:", AppKit.NSWindowDidBecomeMainNotification, None)
20 | center.addObserver_selector_name_object_(self, "windowResignMain:", AppKit.NSWindowDidResignMainNotification, None)
21 | return self
22 |
23 | @python_method
24 | def append(self, operator):
25 | if operator not in self.operators:
26 | self.operators.append(operator)
27 |
28 | @python_method
29 | def remove(self, operator):
30 | if operator in self.operators:
31 | self.operators.remove(operator)
32 |
33 | def windowBecomeMain_(self, notification):
34 | window = notification.object()
35 | delegate = window.delegate()
36 | if hasattr(delegate, "vanillaWrapper"):
37 | controller = delegate.vanillaWrapper()
38 | if controller.__class__.__name__ == "DesignspaceEditorController":
39 | self.updateCurrentDesignspace_(controller.operator)
40 |
41 | def windowResignMain_(self, notification):
42 | window = notification.object()
43 | delegate = window.delegate()
44 | if hasattr(delegate, "vanillaWrapper"):
45 | controller = delegate.vanillaWrapper()
46 | if controller.__class__.__name__ == "DesignspaceEditorController":
47 | self.updateCurrentDesignspace_(controller.operator)
48 |
49 | def updateCurrentDesignspace_(self, operator):
50 | if operator != self.currentOperator:
51 | if self.currentOperator is not None:
52 | SendNotification.single(action="ResignCurrent", designspace=self.currentOperator)
53 | if operator is not None:
54 | SendNotification.single(action="BecomeCurrent", designspace=operator)
55 | self.currentOperator = operator
56 |
57 |
58 | _operatorRegistry = OperatorRegistry.alloc().init()
59 |
60 |
61 | def registerOperator(operator):
62 | _operatorRegistry.append(operator)
63 |
64 |
65 | def unregisterOperator(operator):
66 | _operatorRegistry.remove(operator)
67 |
68 |
69 | def notifyOperator(font, who, action="Change", operatorMethod="changed", operatorKwargs=dict(), notificationKwargs=dict()):
70 | for operator in _operatorRegistry.operators:
71 | for sourceDescriptor in operator.sources:
72 | if sourceDescriptor.path == font.path:
73 | if operatorMethod:
74 | callback = getattr(operator, operatorMethod)
75 | callback(**operatorKwargs)
76 | SendNotification.single(who=who, action=action, designspace=operator, **notificationKwargs)
77 | return
78 |
79 |
80 | class DesignspaceEditorPreviewGlyphSubscriber(Subscriber):
81 |
82 | debug = True
83 |
84 | operators = []
85 |
86 | def glyphDidChange(self, info):
87 | glyph = info["glyph"]
88 | font = glyph.font
89 | notifyOperator(
90 | font,
91 | who="SourceGlyph",
92 | operatorMethod="glyphChanged",
93 | operatorKwargs=dict(
94 | glyphName=glyph.name,
95 | includeDependencies=True
96 | ),
97 | notificationKwargs=dict(
98 | glyph=glyph
99 | )
100 | )
101 |
102 |
103 | class DesignspaceEditorCurrentFontSubscriber(Subscriber):
104 |
105 | debug = True
106 |
107 | def currentFontInfoDidChange(self, info):
108 | font = info["font"]
109 | notifyOperator(
110 | font,
111 | who="SourceInfo",
112 | notificationKwargs=dict(
113 | font=font
114 | )
115 | )
116 |
117 | def currentFontKerningDidChange(self, info):
118 | font = info["font"]
119 | notifyOperator(
120 | font,
121 | who="SourceKerning",
122 | notificationKwargs=dict(
123 | font=font
124 | )
125 | )
126 |
127 | def currentFontGroupsDidChange(self, info):
128 | font = info["font"]
129 | notifyOperator(
130 | font,
131 | who="SourceGroups",
132 | notificationKwargs=dict(
133 | font=font
134 | )
135 | )
136 |
137 |
138 | class DesignspaceEditorFontDocumentSubscriber(Subscriber):
139 |
140 | debug = True
141 |
142 | def fontDocumentDidChangeExternally(self, info):
143 | font = info["font"]
144 | notifyOperator(
145 | font,
146 | who="SourceFont",
147 | action="ChangedExternally",
148 | notificationKwargs=dict(
149 | font=font
150 | )
151 | )
152 |
153 |
154 | registerGlyphEditorSubscriber(DesignspaceEditorPreviewGlyphSubscriber)
155 | registerCurrentFontSubscriber(DesignspaceEditorCurrentFontSubscriber)
156 | registerRoboFontSubscriber(DesignspaceEditorFontDocumentSubscriber)
157 |
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/lib/designspaceEditor/locationPreview.py:
--------------------------------------------------------------------------------
1 | from operator import itemgetter
2 |
3 | import vanilla
4 | import ezui
5 |
6 | import mojo.drawingTools as ctx
7 |
8 | from mojo.UI import MultiLineView, splitText, GlyphRecord, StatusBar
9 | from mojo.extensions import getExtensionDefault, setExtensionDefault
10 | from mojo.subscriber import WindowController, Subscriber
11 | from mojo.events import addObserver, removeObserver
12 | from mojo.roboFont import RFont, internalFontClasses, CurrentFont, CurrentGlyph
13 |
14 | from designspaceEditor.tools import UseVarLib, symbolImage
15 | from designspaceEditor.parsers.parserTools import numberToString
16 |
17 | from mutatorMath import Location
18 |
19 | from designspaceEditor import extensionIdentifier
20 |
21 |
22 | skateboardPreviewTextLibKey = "com.letterror.skateboard.previewText"
23 | previewTextLibKey = f"{extensionIdentifier}.previewText"
24 |
25 | inverseDefaultKey = f"{extensionIdentifier}.inverse"
26 | singleLineDefaultKey = f"{extensionIdentifier}.singleLine"
27 | showSourcesDefaultKey = f"{extensionIdentifier}.showSources"
28 | showInstancesDefaultKey = f"{extensionIdentifier}.showInstances"
29 | shouldSortByDefaultKey = f"{extensionIdentifier}.shouldSortBy"
30 |
31 |
32 | previewLocationButtonImage = symbolImage("mappin.and.ellipse", "primary")
33 |
34 | indicatorImageMap = dict(
35 | source=symbolImage("smallcircle.filled.circle.fill", (1, .5, 0, 1)),
36 | instance=symbolImage("smallcircle.filled.circle", (0, 0, 1, 1)),
37 | previewLocation=symbolImage("mappin.and.ellipse", (1, 0, 0, 1), flipped=True)
38 | )
39 |
40 |
41 | class PreviewLocationFinder(ezui.WindowController):
42 |
43 | def build(self, parent, operator, previewLocation):
44 | self.operator = operator
45 | content = """
46 | = TwoColumnForm
47 | :
48 | [ ] Show Preview Location @showPreviewLocation
49 | """
50 | descriptionData = dict(
51 | content=dict(
52 | itemColumnWidth=200
53 | ),
54 | showPreviewLocation=dict(
55 | value=bool(previewLocation)
56 | )
57 | )
58 |
59 | for axisDescriptor in operator.axes:
60 | value = axisDescriptor.default
61 | if previewLocation:
62 | value = previewLocation.get(axisDescriptor.name, value)
63 |
64 | if hasattr(axisDescriptor, "values"):
65 | # discrete axis
66 | content += f"""
67 | : {axisDescriptor.name}:
68 | ( ...) @{axisDescriptor.name}
69 | """
70 | descriptionData[axisDescriptor.name] = dict(
71 | items=[numberToString(value) for value in axisDescriptor.values]
72 | )
73 | else:
74 | content += f"""
75 | : {axisDescriptor.name}:
76 | ---X--- [__] @{axisDescriptor.name}
77 | """
78 | minimum, default, maximum = operator.getAxisExtremes(axisDescriptor)
79 | descriptionData[axisDescriptor.name] = dict(
80 | minValue=minimum,
81 | maxValue=maximum,
82 | value=value
83 | )
84 |
85 | content += """
86 | =====
87 | ( Add as Instance ) @addAsInstance
88 | """
89 | self.w = ezui.EZPopover(
90 | content=content,
91 | descriptionData=descriptionData,
92 | parent=parent,
93 | parentAlignment="bottom",
94 | behavior="transient",
95 | size="auto",
96 | controller=self
97 | )
98 |
99 | def started(self):
100 | self.w.open()
101 |
102 | def destroy(self):
103 | self.operator = None
104 |
105 | def getLocation(self):
106 | location = self.w.getItemValues()
107 | for axisDescriptor in self.operator.axes:
108 | if hasattr(axisDescriptor, "values"):
109 | index = location[axisDescriptor.name]
110 | location[axisDescriptor.name] = axisDescriptor.values[index]
111 | del location["showPreviewLocation"]
112 | return location
113 |
114 | def contentCallback(self, sender):
115 | if self.w.getItemValue("showPreviewLocation"):
116 | self.operator.setPreviewLocation(location=self.getLocation())
117 |
118 | def addAsInstanceCallback(self, sender):
119 | self.operator.addInstanceDescriptor(
120 | designLocation=self.getLocation()
121 | )
122 |
123 | def showPreviewLocationCallback(self, sender):
124 | if sender.get():
125 | self.operator.setPreviewLocation(location=self.getLocation())
126 | else:
127 | self.operator.setPreviewLocation(location=None)
128 |
129 |
130 | class PreviewInstance:
131 |
132 | flavor = "previewLocation"
133 |
134 | def __init__(self, designLocation):
135 | self.designLocation = designLocation
136 |
137 | def getFullDesignLocation(self, doc):
138 | return self.designLocation
139 |
140 |
141 | class LocationPreview(Subscriber, WindowController):
142 |
143 | debug = True
144 |
145 | def build(self, operator=None, selectedSources=None, selectedInstances=None, previewString=None):
146 | self.operator = operator
147 |
148 | self.dummyFont = RFont(showInterface=False)
149 |
150 | upms = set()
151 | for font in self.operator.fonts.values():
152 | if font is not None:
153 | upms.add(font.info.unitsPerEm)
154 |
155 | with UseVarLib(self.operator, useVarLib=False):
156 | for instance in self.operator.instances:
157 | #continuousLocation, discreteLocation = self.operator.splitLocation(instance.location)
158 | #infoMutator = self.operator.getInfoMutator(discreteLocation)
159 | #info = infoMutator.makeInstance(continuousLocation)
160 | info = self.operator.makeOneInfo(instance.getFullDesignLocation(self.operator))
161 | upms.add(info.unitsPerEm)
162 |
163 | self.dummyFont.info.unitsPerEm = max(upms) if upms else 1000
164 |
165 | self.displayPrefs = {}
166 | self.displayPrefs['Inverse'] = getExtensionDefault(inverseDefaultKey, False)
167 | self.displayPrefs['Beam'] = False
168 | self.displayPrefs['displayMode'] = "Single Line" if getExtensionDefault(singleLineDefaultKey, False) else "Multi Line"
169 | self.displayPrefs['Stroke'] = False
170 | self.displayPrefs['Fill'] = True
171 |
172 | self.shouldShowSources = getExtensionDefault(showSourcesDefaultKey, False)
173 | self.shouldShowInstances = getExtensionDefault(showInstancesDefaultKey, True)
174 | self.shouldShowPreviewLocation = operator.getPreviewLocation()
175 |
176 | self.shouldSortBy = set(getExtensionDefault(shouldSortByDefaultKey, []))
177 |
178 | self.w = vanilla.FloatingWindow((700, 400), "Location Preview", minSize=(500, 300))
179 | self.w.input = vanilla.EditText((10, 10, -80, 22), callback=self.inputCallback)
180 | self.w.options = vanilla.ActionButton(
181 | (-80, 10, 30, 22),
182 | [
183 | dict(title="Single Line", callback=self.singleLineMenuItemCallback, state=self.displayPrefs['displayMode'] == "Single Line"),
184 | dict(title="Invert", callback=self.invertMenuItemCallback, state=self.displayPrefs['Inverse']),
185 | "----",
186 | dict(title="Show Sources", callback=self.showSourcesMenuItemCallback, state=self.shouldShowSources),
187 | dict(title="Show Instances", callback=self.showInstancesMenuItemCallback, state=self.shouldShowInstances),
188 | "----",
189 | dict(title="Sort Line by Area", callback=self.sortByLineAreaMenuItemCallback, state="area" in self.shouldSortBy),
190 | dict(title="Sort Line by Length", callback=self.sortByLineLengthMenuItemCallback, state="length" in self.shouldSortBy),
191 | dict(title="Sort Line by Density", callback=self.sortByLineDensityMenuItemCallback, state="density" in self.shouldSortBy),
192 | ],
193 | bordered=False
194 | )
195 | self.w.currentLocation = vanilla.Button((-40, 10, 30, 22), "", callback=self.currentLocationCallback)
196 | self.w.currentLocation.getNSButton().setImage_(previewLocationButtonImage)
197 | self.w.hl = vanilla.HorizontalLine((0, 41, 0, 1))
198 | self.w.preview = MultiLineView(
199 | (0, 42, 0, -20),
200 | pointSize=60,
201 | displayOptions=self.displayPrefs,
202 | selectionCallback=self.previewSelectionCallback
203 | )
204 | self.w.infoText = StatusBar((0, -20, -0, 20))
205 | self.w.preview.setFont(self.dummyFont)
206 |
207 | self.selectedSources = selectedSources or []
208 | self.selectedInstances = selectedInstances or []
209 | self.previewLocation = None
210 |
211 | if previewString is None:
212 | # check if there is an old skateboard previewtext
213 | if skateboardPreviewTextLibKey in self.operator.lib:
214 | previewString = self.operator.lib[previewTextLibKey] = self.operator.lib[skateboardPreviewTextLibKey]
215 | del self.operator.lib[skateboardPreviewTextLibKey]
216 | else:
217 | previewString = self.operator.lib.get(previewTextLibKey, "Abc")
218 | addObserver(self, "locationPreviewLineViewDidDrawGlyph", "spaceCenterDraw")
219 | self.setPreviewString(previewString)
220 |
221 | def started(self):
222 | self.w.open()
223 |
224 | def destroy(self):
225 | removeObserver(self, "spaceCenterDraw")
226 | self.operator = None
227 | self.selectedInstances = None
228 | self.selectedSources = None
229 |
230 | def setPreviewString(self, value):
231 | self.w.input.set(value)
232 | self.updatePreview()
233 |
234 | def updatePreview(self):
235 | self.inputCallback(self.w.input)
236 | self.populateInfoStatusBar()
237 |
238 | def inputCallback(self, sender):
239 | previewString = sender.get()
240 | self.operator.lib[previewTextLibKey] = previewString
241 | glyphNames = []
242 | for glyphName in splitText(previewString, self.operator.getCharacterMapping()):
243 | if glyphName == "/?":
244 | currentGlyph = CurrentGlyph()
245 | if currentGlyph is not None:
246 | glyphNames.append(currentGlyph.name)
247 | elif glyphName == "/!":
248 | currentFont = CurrentFont()
249 | if currentFont is not None:
250 | glyphNames.extend(currentFont.selectedGlyphNames)
251 | else:
252 | glyphNames.append(glyphName)
253 |
254 | possibleKerningPairs = ((side1, side2) for side1, side2 in zip(glyphNames[:-1], glyphNames[1:]))
255 | possibleKerningPairs = list(possibleKerningPairs)
256 |
257 | selectedDescriptors = []
258 | if self.shouldShowSources:
259 | if self.selectedSources:
260 | selectedDescriptors.extend(self.selectedSources)
261 | else:
262 | selectedDescriptors.extend(self.operator.sources)
263 |
264 | if self.shouldShowInstances:
265 | if self.selectedInstances:
266 | selectedDescriptors.extend(self.selectedInstances)
267 | else:
268 | selectedDescriptors.extend(self.operator.instances)
269 |
270 | if self.shouldShowPreviewLocation is not None:
271 | selectedDescriptors.append(PreviewInstance(self.shouldShowPreviewLocation))
272 |
273 | lines = []
274 |
275 | with UseVarLib(self.operator, useVarLib=False):
276 | try:
277 | for descriptor in selectedDescriptors:
278 | lineItem = dict(
279 | area=0,
280 | length=0,
281 | density=0,
282 | glyphRecords=[]
283 | )
284 |
285 | previousGlyphName = None
286 | fullDesignLocation = descriptor.getFullDesignLocation(self.operator)
287 | kerningObject = self.operator.makeOneKerning(fullDesignLocation, pairs=possibleKerningPairs)
288 | for glyphName in glyphNames:
289 | # do not bend, reasoning: the descriptor locations are in designspace values.
290 | mathGlyph = self.operator.makeOneGlyph(glyphName, fullDesignLocation, decomposeComponents=True)
291 | if mathGlyph is not None:
292 | dest = internalFontClasses.createGlyphObject()
293 | mathGlyph.extractGlyph(dest)
294 | dest.tempLib['designLocation'] = Location(fullDesignLocation).asString()
295 | dest.tempLib['descriptor'] = descriptor
296 |
297 | glyphRecord = GlyphRecord(dest)
298 |
299 | if previousGlyphName and lineItem["glyphRecords"]:
300 | lineItem["glyphRecords"][-1].xAdvance = kerningObject.get((previousGlyphName, glyphName))
301 | else:
302 | # mark the first glyph
303 | dest.tempLib["indicator"] = descriptor.flavor
304 |
305 | lineItem["glyphRecords"].append(glyphRecord)
306 |
307 | lineItem["length"] += dest.width
308 | lineItem["area"] += dest.area
309 |
310 | previousGlyphName = glyphName
311 |
312 | if lineItem["length"] != 0:
313 | lineItem["density"] = lineItem["area"] / lineItem["length"]
314 | lines.append(lineItem)
315 | except Exception:
316 | lines = []
317 | self.w.infoText.set(["This designspace may not work as expected, check the Designspace Problems."], warning=True)
318 |
319 | glyphRecords = []
320 | iterator = lines
321 | if self.shouldSortBy:
322 | iterator = sorted(lines, key=itemgetter(*self.shouldSortBy))
323 | for line in iterator:
324 | glyphRecords.extend(line["glyphRecords"])
325 | glyphRecords.append(GlyphRecord(self.w.preview.createNewLineGlyph()))
326 |
327 | self.w.preview.setGlyphRecords(glyphRecords)
328 | # hacking into the multiline view
329 | self.w.preview._glyphLineView._shouldSendEvents = True
330 |
331 | def previewSelectionCallback(self, sender):
332 | self.populateInfoStatusBar()
333 |
334 | def populateInfoStatusBar(self):
335 | selection = self.w.preview.getSelectedGlyph()
336 | if selection:
337 | # selection.removeOverlap()
338 | self.w.infoText.set([
339 | f"location: {selection.tempLib['designLocation']}",
340 | f"glyph: {selection.name}",
341 | f"width: {selection.width:3.1f}",
342 | f"area: {selection.area:3.1f}"
343 | ])
344 | else:
345 | self.w.infoText.set([])
346 |
347 | def currentLocationCallback(self, sender):
348 | PreviewLocationFinder(sender, self.operator, self.shouldShowPreviewLocation)
349 |
350 | # menu callbacks
351 |
352 | def invertMenuItemCallback(self, sender):
353 | choice = not sender.state()
354 | sender.setState_(choice)
355 | setExtensionDefault(inverseDefaultKey, choice)
356 | if choice:
357 | self.displayPrefs['Inverse'] = True
358 | else:
359 | self.displayPrefs['Inverse'] = False
360 | self.w.preview.setDisplayStates(self.displayPrefs)
361 |
362 | def singleLineMenuItemCallback(self, sender):
363 | choice = not sender.state()
364 | sender.setState_(choice)
365 | setExtensionDefault(singleLineDefaultKey, choice)
366 | if choice:
367 | self.displayPrefs['displayMode'] = "Single Line"
368 | else:
369 | self.displayPrefs['displayMode'] = "Multi Line"
370 | self.w.preview.setDisplayStates(dict(displayMode=self.displayPrefs['displayMode']))
371 |
372 | def showSourcesMenuItemCallback(self, sender):
373 | self.shouldShowSources = not sender.state()
374 | setExtensionDefault(showSourcesDefaultKey, self.shouldShowSources)
375 | sender.setState_(self.shouldShowSources)
376 | self.updatePreview()
377 |
378 | def showInstancesMenuItemCallback(self, sender):
379 | self.shouldShowInstances = not sender.state()
380 | setExtensionDefault(showInstancesDefaultKey, self.shouldShowInstances)
381 | sender.setState_(self.shouldShowInstances)
382 | self.updatePreview()
383 |
384 | def _resolveSortBy(self, sender, key):
385 | choice = not sender.state()
386 | sender.setState_(choice)
387 | if choice:
388 | self.shouldSortBy.add(key)
389 | elif not choice and key in self.shouldSortBy:
390 | self.shouldSortBy.remove(key)
391 | setExtensionDefault(shouldSortByDefaultKey, list(self.shouldSortBy))
392 | self.updatePreview()
393 |
394 | def sortByLineAreaMenuItemCallback(self, sender):
395 | self._resolveSortBy(sender, "area")
396 |
397 | def sortByLineLengthMenuItemCallback(self, sender):
398 | self._resolveSortBy(sender, "length")
399 |
400 | def sortByLineDensityMenuItemCallback(self, sender):
401 | self._resolveSortBy(sender, "density")
402 |
403 | # robofont notifications
404 |
405 | def locationPreviewLineViewDidDrawGlyph(self, notification):
406 | # old style drawing!
407 | glyph = notification["glyph"]
408 | if "indicator" in glyph.tempLib:
409 | indicator = indicatorImageMap[glyph.tempLib["indicator"]]
410 | ctx.save()
411 | if self.displayPrefs['displayMode'] == "Single Line":
412 | ctx.translate(glyph.width / 2, self.dummyFont.info.descender)
413 | x = -indicator.size().width / 2
414 | else:
415 | ctx.translate(0, self.dummyFont.info.unitsPerEm * .4)
416 | x = 0
417 | ctx.scale(-notification["scale"])
418 | ctx.image(indicator, (x, 0))
419 | ctx.restore()
420 |
421 | # subscriber notifications
422 |
423 | designspaceEditorInstancesDidChangeDelay = 0.1
424 |
425 | def designspaceEditorInstancesDidChange(self, notification):
426 | self.updatePreview()
427 |
428 | def designspaceEditorSourcesDidChanged(self, notification):
429 | self.updatePreview()
430 |
431 | def designspaceEditorAxesDidChange(self, notification):
432 | self.updatePreview()
433 |
434 | def designspaceEditorSourceGlyphDidChange(self, notification):
435 | self.updatePreview()
436 |
437 | def designspaceEditorInfoKerningDidChange(self, notification):
438 | self.updatePreview()
439 |
440 | def designspaceEditorSourceKerningDidChange(self, notification):
441 | self.updatePreview()
442 |
443 | def designspaceEditorGroupsKerningDidChange(self, notification):
444 | self.updatePreview()
445 |
446 | def designspaceEditorGroupsFontDidChangedExternally(self, notification):
447 | self.updatePreview()
448 |
449 | designspaceEditorPreviewLocationDidChangeDelay = 0.01
450 |
451 | def designspaceEditorPreviewLocationDidChange(self, notification):
452 | self.shouldShowPreviewLocation = notification["location"]
453 | self.updatePreview()
454 |
455 | def designspaceEditorInstancesDidChangeSelection(self, notification):
456 | self.selectedInstances = notification["selectedItems"]
457 | self.updatePreview()
458 |
459 | def designspaceEditorSourcesDidChangeSelection(self, notification):
460 | self.selectedSources = notification["selectedItems"]
461 | self.updatePreview()
462 |
463 | def roboFontDidSwitchCurrentGlyph(self, notification):
464 | if not self.w.getNSWindow().isKeyWindow():
465 | self.updatePreview()
466 |
467 |
468 | if __name__ == '__main__':
469 | designspace = CurrentDesignspace()
470 | if designspace is None:
471 | print("Open a design space!")
472 | else:
473 | c = LocationPreview(operator=designspace)
474 | # c.setPreviewString("HELLOVAH")
475 |
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/lib/designspaceEditor/parsers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LettError/designSpaceRoboFontExtension/b32cb50a976c63def69e6b69fd5327ed374b31a0/DesignspaceEditor2.roboFontExt/lib/designspaceEditor/parsers/__init__.py
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/lib/designspaceEditor/parsers/glyphNameParser.py:
--------------------------------------------------------------------------------
1 | """
2 | # glyphname text spec
3 |
4 | ...
5 | """
6 |
7 |
8 | def parseGlyphNames(text):
9 | return [glyphName.strip() for glyphName in text.split()]
10 |
11 |
12 | def dumpGlyphNames(glyphNames):
13 | return " ".join(glyphNames)
14 |
15 |
16 | # tests
17 |
18 | def test_parseGlyphNames():
19 | text = "a b c agrave \tb.alt ccedilla"
20 | expected = ["a", "b", "c", "agrave", "b.alt", "ccedilla"]
21 | result = parseGlyphNames(text)
22 | assert expected == result
23 |
24 |
25 | def test_dumpGlyphNames():
26 | glyphNames = ["a", "b", "c", "agrave", "b.alt", "ccedilla"]
27 | expected = "a b c agrave b.alt ccedilla"
28 | result = dumpGlyphNames(glyphNames)
29 | assert expected == result
30 |
31 |
32 | if __name__ == '__main__':
33 | import pytest
34 | pytest.main([__file__])
35 |
--------------------------------------------------------------------------------
/DesignspaceEditor2.roboFontExt/lib/designspaceEditor/parsers/labelsParser.py:
--------------------------------------------------------------------------------
1 | """
2 | # axis label text spec
3 |
4 | # add localised axis label for language tag
5 | ? ''
6 | ...
7 |
8 | # add axis label in a between minimum value, default value, maximum value
9 |
10 | # add localised axis lables for language tag
11 | ? ' # optional
12 | ...
13 |
14 | # add axis label add a uservalue
15 |
16 | # add localised axis lables for language tag
17 | ? ' # optional
18 | ...
19 |
20 | # optionally add (elidable) or (olderSibling) or [linkedUserValue]
21 | (elidable) (olderSibling) []
22 |
23 |
24 | # location label text spec
25 |
26 |