figrecipe 0.6.0__py3-none-any.whl → 0.7.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- figrecipe/__init__.py +106 -973
- figrecipe/_api/__init__.py +48 -0
- figrecipe/_api/_extract.py +108 -0
- figrecipe/_api/_notebook.py +61 -0
- figrecipe/_api/_panel.py +46 -0
- figrecipe/_api/_save.py +191 -0
- figrecipe/_api/_seaborn_proxy.py +34 -0
- figrecipe/_api/_style_manager.py +153 -0
- figrecipe/_api/_subplots.py +333 -0
- figrecipe/_api/_validate.py +82 -0
- figrecipe/_dev/__init__.py +2 -93
- figrecipe/_dev/_plotters.py +76 -0
- figrecipe/_dev/_run_demos.py +56 -0
- figrecipe/_dev/demo_plotters/__init__.py +35 -166
- figrecipe/_dev/demo_plotters/_categories.py +81 -0
- figrecipe/_dev/demo_plotters/_figure_creators.py +119 -0
- figrecipe/_dev/demo_plotters/_helpers.py +31 -0
- figrecipe/_dev/demo_plotters/_registry.py +50 -0
- figrecipe/_dev/demo_plotters/bar_categorical/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/contour_surface/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/distribution/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/image_matrix/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/line_curve/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/{plot_plot.py → line_curve/plot_plot.py} +3 -2
- figrecipe/_dev/demo_plotters/scatter_points/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/special/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/{plot_pie.py → special/plot_pie.py} +5 -1
- figrecipe/_dev/demo_plotters/spectral_signal/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/vector_flow/__init__.py +4 -0
- figrecipe/_editor/__init__.py +57 -9
- figrecipe/_editor/_bbox/__init__.py +43 -0
- figrecipe/_editor/_bbox/_collections.py +177 -0
- figrecipe/_editor/_bbox/_elements.py +159 -0
- figrecipe/_editor/_bbox/_extract.py +256 -0
- figrecipe/_editor/_bbox/_extract_axes.py +370 -0
- figrecipe/_editor/_bbox/_extract_text.py +342 -0
- figrecipe/_editor/_bbox/_lines.py +173 -0
- figrecipe/_editor/_bbox/_transforms.py +146 -0
- figrecipe/_editor/_flask_app.py +68 -1039
- figrecipe/_editor/_helpers.py +242 -0
- figrecipe/_editor/_hitmap/__init__.py +76 -0
- figrecipe/_editor/_hitmap/_artists/__init__.py +21 -0
- figrecipe/_editor/_hitmap/_artists/_collections.py +345 -0
- figrecipe/_editor/_hitmap/_artists/_images.py +68 -0
- figrecipe/_editor/_hitmap/_artists/_lines.py +107 -0
- figrecipe/_editor/_hitmap/_artists/_patches.py +163 -0
- figrecipe/_editor/_hitmap/_artists/_text.py +190 -0
- figrecipe/_editor/_hitmap/_colors.py +181 -0
- figrecipe/_editor/_hitmap/_detect.py +137 -0
- figrecipe/_editor/_hitmap/_restore.py +154 -0
- figrecipe/_editor/_hitmap_main.py +182 -0
- figrecipe/_editor/_preferences.py +135 -0
- figrecipe/_editor/_render_overrides.py +480 -0
- figrecipe/_editor/_renderer.py +35 -185
- figrecipe/_editor/_routes_axis.py +453 -0
- figrecipe/_editor/_routes_core.py +284 -0
- figrecipe/_editor/_routes_element.py +317 -0
- figrecipe/_editor/_routes_style.py +223 -0
- figrecipe/_editor/_templates/__init__.py +78 -1
- figrecipe/_editor/_templates/_html.py +109 -13
- figrecipe/_editor/_templates/_scripts/__init__.py +120 -0
- figrecipe/_editor/_templates/_scripts/_api.py +228 -0
- figrecipe/_editor/_templates/_scripts/_colors.py +485 -0
- figrecipe/_editor/_templates/_scripts/_core.py +436 -0
- figrecipe/_editor/_templates/_scripts/_debug_snapshot.py +186 -0
- figrecipe/_editor/_templates/_scripts/_element_editor.py +310 -0
- figrecipe/_editor/_templates/_scripts/_files.py +195 -0
- figrecipe/_editor/_templates/_scripts/_hitmap.py +509 -0
- figrecipe/_editor/_templates/_scripts/_inspector.py +315 -0
- figrecipe/_editor/_templates/_scripts/_labels.py +464 -0
- figrecipe/_editor/_templates/_scripts/_legend_drag.py +265 -0
- figrecipe/_editor/_templates/_scripts/_modals.py +226 -0
- figrecipe/_editor/_templates/_scripts/_overlays.py +292 -0
- figrecipe/_editor/_templates/_scripts/_panel_drag.py +334 -0
- figrecipe/_editor/_templates/_scripts/_panel_position.py +279 -0
- figrecipe/_editor/_templates/_scripts/_selection.py +237 -0
- figrecipe/_editor/_templates/_scripts/_tabs.py +89 -0
- figrecipe/_editor/_templates/_scripts/_view_mode.py +107 -0
- figrecipe/_editor/_templates/_scripts/_zoom.py +179 -0
- figrecipe/_editor/_templates/_styles/__init__.py +69 -0
- figrecipe/_editor/_templates/_styles/_base.py +64 -0
- figrecipe/_editor/_templates/_styles/_buttons.py +206 -0
- figrecipe/_editor/_templates/_styles/_color_input.py +123 -0
- figrecipe/_editor/_templates/_styles/_controls.py +265 -0
- figrecipe/_editor/_templates/_styles/_dynamic_props.py +144 -0
- figrecipe/_editor/_templates/_styles/_forms.py +126 -0
- figrecipe/_editor/_templates/_styles/_hitmap.py +184 -0
- figrecipe/_editor/_templates/_styles/_inspector.py +90 -0
- figrecipe/_editor/_templates/_styles/_labels.py +118 -0
- figrecipe/_editor/_templates/_styles/_modals.py +98 -0
- figrecipe/_editor/_templates/_styles/_overlays.py +130 -0
- figrecipe/_editor/_templates/_styles/_preview.py +225 -0
- figrecipe/_editor/_templates/_styles/_selection.py +73 -0
- figrecipe/_params/_DECORATION_METHODS.py +6 -0
- figrecipe/_recorder.py +35 -106
- figrecipe/_recorder_utils.py +124 -0
- figrecipe/_reproducer/__init__.py +18 -0
- figrecipe/_reproducer/_core.py +498 -0
- figrecipe/_reproducer/_custom_plots.py +279 -0
- figrecipe/_reproducer/_seaborn.py +100 -0
- figrecipe/_reproducer/_violin.py +186 -0
- figrecipe/_signatures/_kwargs.py +273 -0
- figrecipe/_signatures/_loader.py +21 -423
- figrecipe/_signatures/_parsing.py +147 -0
- figrecipe/_wrappers/_axes.py +119 -910
- figrecipe/_wrappers/_axes_helpers.py +136 -0
- figrecipe/_wrappers/_axes_plots.py +418 -0
- figrecipe/_wrappers/_axes_seaborn.py +157 -0
- figrecipe/_wrappers/_figure.py +162 -0
- figrecipe/_wrappers/_panel_labels.py +127 -0
- figrecipe/_wrappers/_plot_helpers.py +143 -0
- figrecipe/_wrappers/_violin_helpers.py +180 -0
- figrecipe/styles/__init__.py +8 -6
- figrecipe/styles/_dotdict.py +72 -0
- figrecipe/styles/_finalize.py +134 -0
- figrecipe/styles/_fonts.py +77 -0
- figrecipe/styles/_kwargs_converter.py +178 -0
- figrecipe/styles/_plot_styles.py +209 -0
- figrecipe/styles/_style_applier.py +32 -478
- figrecipe/styles/_style_loader.py +16 -192
- figrecipe/styles/_themes.py +151 -0
- figrecipe/styles/presets/MATPLOTLIB.yaml +2 -1
- figrecipe/styles/presets/SCITEX.yaml +29 -24
- {figrecipe-0.6.0.dist-info → figrecipe-0.7.4.dist-info}/METADATA +37 -2
- figrecipe-0.7.4.dist-info/RECORD +188 -0
- figrecipe/_editor/_bbox.py +0 -978
- figrecipe/_editor/_hitmap.py +0 -937
- figrecipe/_editor/_templates/_scripts.py +0 -2778
- figrecipe/_editor/_templates/_styles.py +0 -1326
- figrecipe/_reproducer.py +0 -975
- figrecipe-0.6.0.dist-info/RECORD +0 -90
- /figrecipe/_dev/demo_plotters/{plot_bar.py → bar_categorical/plot_bar.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_barh.py → bar_categorical/plot_barh.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_contour.py → contour_surface/plot_contour.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_contourf.py → contour_surface/plot_contourf.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_tricontour.py → contour_surface/plot_tricontour.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_tricontourf.py → contour_surface/plot_tricontourf.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_tripcolor.py → contour_surface/plot_tripcolor.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_triplot.py → contour_surface/plot_triplot.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_boxplot.py → distribution/plot_boxplot.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_ecdf.py → distribution/plot_ecdf.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_hist.py → distribution/plot_hist.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_hist2d.py → distribution/plot_hist2d.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_violinplot.py → distribution/plot_violinplot.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_hexbin.py → image_matrix/plot_hexbin.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_imshow.py → image_matrix/plot_imshow.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_matshow.py → image_matrix/plot_matshow.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_pcolor.py → image_matrix/plot_pcolor.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_pcolormesh.py → image_matrix/plot_pcolormesh.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_spy.py → image_matrix/plot_spy.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_errorbar.py → line_curve/plot_errorbar.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_fill.py → line_curve/plot_fill.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_fill_between.py → line_curve/plot_fill_between.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_fill_betweenx.py → line_curve/plot_fill_betweenx.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_stackplot.py → line_curve/plot_stackplot.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_stairs.py → line_curve/plot_stairs.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_step.py → line_curve/plot_step.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_scatter.py → scatter_points/plot_scatter.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_eventplot.py → special/plot_eventplot.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_loglog.py → special/plot_loglog.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_semilogx.py → special/plot_semilogx.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_semilogy.py → special/plot_semilogy.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_stem.py → special/plot_stem.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_acorr.py → spectral_signal/plot_acorr.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_angle_spectrum.py → spectral_signal/plot_angle_spectrum.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_cohere.py → spectral_signal/plot_cohere.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_csd.py → spectral_signal/plot_csd.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_magnitude_spectrum.py → spectral_signal/plot_magnitude_spectrum.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_phase_spectrum.py → spectral_signal/plot_phase_spectrum.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_psd.py → spectral_signal/plot_psd.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_specgram.py → spectral_signal/plot_specgram.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_xcorr.py → spectral_signal/plot_xcorr.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_barbs.py → vector_flow/plot_barbs.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_quiver.py → vector_flow/plot_quiver.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_streamplot.py → vector_flow/plot_streamplot.py} +0 -0
- {figrecipe-0.6.0.dist-info → figrecipe-0.7.4.dist-info}/WHEEL +0 -0
- {figrecipe-0.6.0.dist-info → figrecipe-0.7.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Style and theme Flask route handlers for the figure editor.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from flask import jsonify, request
|
|
8
|
+
|
|
9
|
+
from ._helpers import get_form_values_from_style, render_with_overrides
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def register_style_routes(app, editor):
|
|
13
|
+
"""Register style/theme routes with the Flask app."""
|
|
14
|
+
from ._overrides import save_overrides
|
|
15
|
+
|
|
16
|
+
@app.route("/style")
|
|
17
|
+
def get_style():
|
|
18
|
+
"""Get current style configuration."""
|
|
19
|
+
return jsonify(
|
|
20
|
+
{
|
|
21
|
+
"base_style": editor.style_overrides.base_style,
|
|
22
|
+
"programmatic_style": editor.style_overrides.programmatic_style,
|
|
23
|
+
"manual_overrides": editor.style_overrides.manual_overrides,
|
|
24
|
+
"effective_style": editor.get_effective_style(),
|
|
25
|
+
"has_overrides": editor.style_overrides.has_manual_overrides(),
|
|
26
|
+
"manual_timestamp": editor.style_overrides.manual_timestamp,
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
@app.route("/theme")
|
|
31
|
+
def get_theme():
|
|
32
|
+
"""Get current theme YAML content for display."""
|
|
33
|
+
import io as yaml_io
|
|
34
|
+
|
|
35
|
+
from ruamel.yaml import YAML
|
|
36
|
+
|
|
37
|
+
style = editor.get_effective_style()
|
|
38
|
+
style_name = style.get("_name", "SCITEX")
|
|
39
|
+
|
|
40
|
+
yaml = YAML()
|
|
41
|
+
yaml.default_flow_style = False
|
|
42
|
+
yaml.indent(mapping=2, sequence=4, offset=2)
|
|
43
|
+
stream = yaml_io.StringIO()
|
|
44
|
+
yaml.dump(style, stream)
|
|
45
|
+
yaml_content = stream.getvalue()
|
|
46
|
+
|
|
47
|
+
return jsonify(
|
|
48
|
+
{
|
|
49
|
+
"name": style_name,
|
|
50
|
+
"content": yaml_content,
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
@app.route("/list_themes")
|
|
55
|
+
def list_themes():
|
|
56
|
+
"""List available theme presets."""
|
|
57
|
+
from ..styles._style_loader import list_presets
|
|
58
|
+
|
|
59
|
+
presets = list_presets()
|
|
60
|
+
current = editor.get_effective_style().get("_name", "SCITEX")
|
|
61
|
+
|
|
62
|
+
return jsonify(
|
|
63
|
+
{
|
|
64
|
+
"themes": presets,
|
|
65
|
+
"current": current,
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
@app.route("/switch_theme", methods=["POST"])
|
|
70
|
+
def switch_theme():
|
|
71
|
+
"""Switch to a different theme preset by reproducing the figure."""
|
|
72
|
+
from .._reproducer import reproduce_from_record
|
|
73
|
+
from ..styles._style_loader import load_preset
|
|
74
|
+
|
|
75
|
+
data = request.get_json() or {}
|
|
76
|
+
theme_name = data.get("theme")
|
|
77
|
+
|
|
78
|
+
if not theme_name:
|
|
79
|
+
return jsonify({"error": "No theme specified"}), 400
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
new_style = load_preset(theme_name)
|
|
83
|
+
|
|
84
|
+
if new_style is None:
|
|
85
|
+
return jsonify({"error": f"Theme '{theme_name}' not found"}), 404
|
|
86
|
+
|
|
87
|
+
# Convert nested style to flat style dict with color_palette
|
|
88
|
+
flat_style = dict(new_style)
|
|
89
|
+
flat_style["_name"] = theme_name
|
|
90
|
+
|
|
91
|
+
# Extract color_palette from nested colors.palette
|
|
92
|
+
if "colors" in new_style and isinstance(new_style["colors"], dict):
|
|
93
|
+
colors_dict = new_style["colors"]
|
|
94
|
+
if "palette" in colors_dict:
|
|
95
|
+
flat_style["color_palette"] = list(colors_dict["palette"])
|
|
96
|
+
|
|
97
|
+
editor.style_overrides.base_style = flat_style
|
|
98
|
+
|
|
99
|
+
if hasattr(editor.fig, "record") and editor.fig.record is not None:
|
|
100
|
+
editor.fig.record.style = flat_style
|
|
101
|
+
new_fig, _ = reproduce_from_record(editor.fig.record)
|
|
102
|
+
editor.fig = new_fig
|
|
103
|
+
# Keep the new style (don't restore old style)
|
|
104
|
+
|
|
105
|
+
mpl_fig = editor.fig.fig if hasattr(editor.fig, "fig") else editor.fig
|
|
106
|
+
behavior = new_style.get("behavior", {})
|
|
107
|
+
for ax in mpl_fig.get_axes():
|
|
108
|
+
hide_top = behavior.get("hide_top_spine", True)
|
|
109
|
+
hide_right = behavior.get("hide_right_spine", True)
|
|
110
|
+
ax.spines["top"].set_visible(not hide_top)
|
|
111
|
+
ax.spines["right"].set_visible(not hide_right)
|
|
112
|
+
|
|
113
|
+
if behavior.get("grid", False):
|
|
114
|
+
ax.grid(True, alpha=0.3)
|
|
115
|
+
else:
|
|
116
|
+
ax.grid(False)
|
|
117
|
+
|
|
118
|
+
base64_img, bboxes, img_size = render_with_overrides(
|
|
119
|
+
editor.fig,
|
|
120
|
+
editor.get_effective_style(),
|
|
121
|
+
editor.dark_mode,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
form_values = get_form_values_from_style(editor.get_effective_style())
|
|
125
|
+
|
|
126
|
+
return jsonify(
|
|
127
|
+
{
|
|
128
|
+
"success": True,
|
|
129
|
+
"theme": theme_name,
|
|
130
|
+
"image": base64_img,
|
|
131
|
+
"bboxes": bboxes,
|
|
132
|
+
"img_size": {"width": img_size[0], "height": img_size[1]},
|
|
133
|
+
"values": form_values,
|
|
134
|
+
}
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
except Exception as e:
|
|
138
|
+
import traceback
|
|
139
|
+
|
|
140
|
+
traceback.print_exc()
|
|
141
|
+
return jsonify({"error": f"Failed to switch theme: {str(e)}"}), 500
|
|
142
|
+
|
|
143
|
+
@app.route("/save", methods=["POST"])
|
|
144
|
+
def save():
|
|
145
|
+
"""Save style overrides (stored separately from recipe)."""
|
|
146
|
+
data = request.get_json() or {}
|
|
147
|
+
editor.style_overrides.update_manual_overrides(data.get("overrides", {}))
|
|
148
|
+
|
|
149
|
+
if editor.recipe_path:
|
|
150
|
+
path = save_overrides(editor.style_overrides, editor.recipe_path)
|
|
151
|
+
return jsonify(
|
|
152
|
+
{
|
|
153
|
+
"success": True,
|
|
154
|
+
"path": str(path),
|
|
155
|
+
"has_overrides": editor.style_overrides.has_manual_overrides(),
|
|
156
|
+
"timestamp": editor.style_overrides.manual_timestamp,
|
|
157
|
+
}
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
return jsonify(
|
|
161
|
+
{
|
|
162
|
+
"success": True,
|
|
163
|
+
"overrides": editor.overrides,
|
|
164
|
+
"has_overrides": editor.style_overrides.has_manual_overrides(),
|
|
165
|
+
}
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
@app.route("/restore", methods=["POST"])
|
|
169
|
+
def restore():
|
|
170
|
+
"""Restore to original style (clear manual overrides and axes positions)."""
|
|
171
|
+
from ._bbox import extract_bboxes
|
|
172
|
+
|
|
173
|
+
# Clear all manual overrides (including position overrides)
|
|
174
|
+
editor.style_overrides.clear_manual_overrides()
|
|
175
|
+
|
|
176
|
+
# Restore original axes positions
|
|
177
|
+
editor.restore_axes_positions()
|
|
178
|
+
|
|
179
|
+
if editor._initial_base64 and not editor.dark_mode:
|
|
180
|
+
base64_img = editor._initial_base64
|
|
181
|
+
import base64 as b64
|
|
182
|
+
import io
|
|
183
|
+
|
|
184
|
+
from PIL import Image
|
|
185
|
+
|
|
186
|
+
img_data = b64.b64decode(base64_img)
|
|
187
|
+
img = Image.open(io.BytesIO(img_data))
|
|
188
|
+
img_size = img.size
|
|
189
|
+
mpl_fig = editor.fig.fig if hasattr(editor.fig, "fig") else editor.fig
|
|
190
|
+
original_dpi = mpl_fig.dpi
|
|
191
|
+
mpl_fig.set_dpi(150)
|
|
192
|
+
mpl_fig.canvas.draw()
|
|
193
|
+
bboxes = extract_bboxes(mpl_fig, img_size[0], img_size[1])
|
|
194
|
+
mpl_fig.set_dpi(original_dpi)
|
|
195
|
+
else:
|
|
196
|
+
base64_img, bboxes, img_size = render_with_overrides(
|
|
197
|
+
editor.fig,
|
|
198
|
+
None,
|
|
199
|
+
editor.dark_mode,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
return jsonify(
|
|
203
|
+
{
|
|
204
|
+
"success": True,
|
|
205
|
+
"image": base64_img,
|
|
206
|
+
"bboxes": bboxes,
|
|
207
|
+
"img_size": {"width": img_size[0], "height": img_size[1]},
|
|
208
|
+
"original_style": editor.style,
|
|
209
|
+
}
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
@app.route("/diff")
|
|
213
|
+
def get_diff():
|
|
214
|
+
"""Get differences between original and manual overrides."""
|
|
215
|
+
return jsonify(
|
|
216
|
+
{
|
|
217
|
+
"diff": editor.style_overrides.get_diff(),
|
|
218
|
+
"has_overrides": editor.style_overrides.has_manual_overrides(),
|
|
219
|
+
}
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
__all__ = ["register_style_routes"]
|
|
@@ -8,13 +8,28 @@ single source of truth. No custom key mapping is needed since all keys
|
|
|
8
8
|
now match the HTML input IDs directly.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
+
import base64
|
|
11
12
|
import json
|
|
13
|
+
from datetime import datetime
|
|
14
|
+
from pathlib import Path
|
|
12
15
|
from typing import Any, Dict, Tuple
|
|
13
16
|
|
|
14
17
|
from ._html import HTML_TEMPLATE
|
|
15
18
|
from ._scripts import SCRIPTS
|
|
16
19
|
from ._styles import STYLES
|
|
17
20
|
|
|
21
|
+
# Server start time for debugging template reloads
|
|
22
|
+
_SERVER_START_TIME = datetime.now().strftime("%H:%M:%S")
|
|
23
|
+
|
|
24
|
+
# Load SciTeX icon as base64
|
|
25
|
+
_SCITEX_ICON_PATH = (
|
|
26
|
+
Path(__file__).parent.parent.parent.parent.parent / "docs" / "scitex-icon.png"
|
|
27
|
+
)
|
|
28
|
+
_SCITEX_ICON_BASE64 = ""
|
|
29
|
+
if _SCITEX_ICON_PATH.exists():
|
|
30
|
+
with open(_SCITEX_ICON_PATH, "rb") as f:
|
|
31
|
+
_SCITEX_ICON_BASE64 = base64.b64encode(f.read()).decode("utf-8")
|
|
32
|
+
|
|
18
33
|
|
|
19
34
|
def build_html_template(
|
|
20
35
|
image_base64: str,
|
|
@@ -24,6 +39,8 @@ def build_html_template(
|
|
|
24
39
|
overrides: Dict[str, Any],
|
|
25
40
|
img_size: Tuple[int, int],
|
|
26
41
|
style_name: str = "SCITEX",
|
|
42
|
+
hot_reload: bool = False,
|
|
43
|
+
dark_mode: bool = False,
|
|
27
44
|
) -> str:
|
|
28
45
|
"""
|
|
29
46
|
Build complete HTML template for figure editor.
|
|
@@ -47,6 +64,10 @@ def build_html_template(
|
|
|
47
64
|
(width, height) of preview image.
|
|
48
65
|
style_name : str
|
|
49
66
|
Name of the applied style preset (e.g., "SCITEX", "MATPLOTLIB").
|
|
67
|
+
hot_reload : bool
|
|
68
|
+
Enable hot reload auto-reconnect JavaScript.
|
|
69
|
+
dark_mode : bool
|
|
70
|
+
Initial dark mode state from saved preferences.
|
|
50
71
|
|
|
51
72
|
Returns
|
|
52
73
|
-------
|
|
@@ -57,10 +78,58 @@ def build_html_template(
|
|
|
57
78
|
# Keys should already match HTML input IDs (YAML-compatible flattened)
|
|
58
79
|
initial_values = {**style, **overrides}
|
|
59
80
|
|
|
81
|
+
# Hot reload JavaScript for auto-reconnect on server restart
|
|
82
|
+
hot_reload_script = ""
|
|
83
|
+
if hot_reload:
|
|
84
|
+
hot_reload_script = """
|
|
85
|
+
// Hot Reload: Auto-reconnect when server restarts
|
|
86
|
+
(function() {
|
|
87
|
+
let isReconnecting = false;
|
|
88
|
+
let pingInterval = null;
|
|
89
|
+
|
|
90
|
+
function showReloadBanner(show) {
|
|
91
|
+
let banner = document.getElementById('hot-reload-banner');
|
|
92
|
+
if (!banner && show) {
|
|
93
|
+
banner = document.createElement('div');
|
|
94
|
+
banner.id = 'hot-reload-banner';
|
|
95
|
+
banner.style.cssText = 'position:fixed;top:0;left:0;right:0;background:#f59e0b;' +
|
|
96
|
+
'color:#000;text-align:center;padding:8px;z-index:9999;font-weight:bold;';
|
|
97
|
+
banner.textContent = 'Server restarting... will reload automatically';
|
|
98
|
+
document.body.prepend(banner);
|
|
99
|
+
}
|
|
100
|
+
if (banner) {
|
|
101
|
+
banner.style.display = show ? 'block' : 'none';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function ping() {
|
|
106
|
+
fetch('/ping', {cache: 'no-store'})
|
|
107
|
+
.then(r => {
|
|
108
|
+
if (r.ok && isReconnecting) {
|
|
109
|
+
// Server is back! Reload the page
|
|
110
|
+
console.log('[Hot Reload] Server is back, reloading...');
|
|
111
|
+
window.location.reload();
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
.catch(() => {
|
|
115
|
+
if (!isReconnecting) {
|
|
116
|
+
console.log('[Hot Reload] Server disconnected, waiting for restart...');
|
|
117
|
+
isReconnecting = true;
|
|
118
|
+
showReloadBanner(true);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Start pinging every 500ms
|
|
124
|
+
pingInterval = setInterval(ping, 500);
|
|
125
|
+
console.log('[Hot Reload] Enabled - watching for server restarts');
|
|
126
|
+
})();
|
|
127
|
+
"""
|
|
128
|
+
|
|
60
129
|
# Inject data into template
|
|
61
130
|
html = HTML_TEMPLATE
|
|
62
131
|
html = html.replace("/* STYLES_PLACEHOLDER */", STYLES)
|
|
63
|
-
html = html.replace("/* SCRIPTS_PLACEHOLDER */", SCRIPTS)
|
|
132
|
+
html = html.replace("/* SCRIPTS_PLACEHOLDER */", SCRIPTS + hot_reload_script)
|
|
64
133
|
html = html.replace("IMAGE_BASE64_PLACEHOLDER", image_base64)
|
|
65
134
|
html = html.replace("BBOXES_PLACEHOLDER", json.dumps(bboxes))
|
|
66
135
|
html = html.replace("COLOR_MAP_PLACEHOLDER", json.dumps(color_map))
|
|
@@ -68,6 +137,14 @@ def build_html_template(
|
|
|
68
137
|
html = html.replace("IMG_WIDTH_PLACEHOLDER", str(img_size[0]))
|
|
69
138
|
html = html.replace("IMG_HEIGHT_PLACEHOLDER", str(img_size[1]))
|
|
70
139
|
html = html.replace("STYLE_NAME_PLACEHOLDER", style_name)
|
|
140
|
+
html = html.replace("SCITEX_ICON_PLACEHOLDER", _SCITEX_ICON_BASE64)
|
|
141
|
+
|
|
142
|
+
# Dark mode preference - set initial state
|
|
143
|
+
html = html.replace("DARK_MODE_THEME_PLACEHOLDER", "dark" if dark_mode else "light")
|
|
144
|
+
html = html.replace("DARK_MODE_CHECKED_PLACEHOLDER", "checked" if dark_mode else "")
|
|
145
|
+
|
|
146
|
+
# Server start time for debugging
|
|
147
|
+
html = html.replace("SERVER_START_TIME_PLACEHOLDER", _SERVER_START_TIME)
|
|
71
148
|
|
|
72
149
|
return html
|
|
73
150
|
|
|
@@ -6,11 +6,12 @@ HTML template for figure editor.
|
|
|
6
6
|
|
|
7
7
|
HTML_TEMPLATE = """
|
|
8
8
|
<!DOCTYPE html>
|
|
9
|
-
<html lang="en" data-theme="
|
|
9
|
+
<html lang="en" data-theme="DARK_MODE_THEME_PLACEHOLDER">
|
|
10
10
|
<head>
|
|
11
11
|
<meta charset="UTF-8">
|
|
12
12
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
13
13
|
<title>figrecipe Editor</title>
|
|
14
|
+
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
|
|
14
15
|
<style>
|
|
15
16
|
/* STYLES_PLACEHOLDER */
|
|
16
17
|
</style>
|
|
@@ -20,7 +21,17 @@ HTML_TEMPLATE = """
|
|
|
20
21
|
<!-- Preview Panel -->
|
|
21
22
|
<div class="preview-panel">
|
|
22
23
|
<div class="preview-header">
|
|
23
|
-
<
|
|
24
|
+
<a href="https://scitex.ai" target="_blank" class="scitex-branding" title="FigRecipe - Part of SciTeX">
|
|
25
|
+
<img src="data:image/png;base64,SCITEX_ICON_PLACEHOLDER" alt="SciTeX" class="scitex-icon">
|
|
26
|
+
<span class="figrecipe-title">FigRecipe Editor</span>
|
|
27
|
+
</a>
|
|
28
|
+
<span id="server-start-time" style="font-size: 10px; color: #888; margin-left: 8px;">Started: SERVER_START_TIME_PLACEHOLDER</span>
|
|
29
|
+
<div class="file-switcher">
|
|
30
|
+
<select id="file-selector" class="file-selector" title="Switch between recipe files">
|
|
31
|
+
<option value="">Loading files...</option>
|
|
32
|
+
</select>
|
|
33
|
+
<button id="btn-new-figure" class="btn-new" title="Create new blank figure">+</button>
|
|
34
|
+
</div>
|
|
24
35
|
<div class="preview-controls">
|
|
25
36
|
<div class="download-dropdown">
|
|
26
37
|
<button id="btn-download-main" class="btn-primary download-main" title="Download as PNG">Download PNG</button>
|
|
@@ -29,24 +40,36 @@ HTML_TEMPLATE = """
|
|
|
29
40
|
<button id="btn-download-png-menu" class="download-option active" data-format="png">PNG</button>
|
|
30
41
|
<button id="btn-download-svg-menu" class="download-option" data-format="svg">SVG</button>
|
|
31
42
|
<button id="btn-download-pdf-menu" class="download-option" data-format="pdf">PDF</button>
|
|
43
|
+
<hr style="margin: 4px 0; border: none; border-top: 1px solid #ddd;">
|
|
44
|
+
<button id="btn-download-csv-menu" class="download-option" data-format="csv" title="Export plot data as CSV">CSV (Data)</button>
|
|
32
45
|
</div>
|
|
33
46
|
</div>
|
|
34
47
|
<button id="btn-refresh" title="Refresh preview">Refresh</button>
|
|
35
|
-
<
|
|
48
|
+
<div class="zoom-controls">
|
|
49
|
+
<button id="btn-zoom-out" title="Zoom out (-)">−</button>
|
|
50
|
+
<span id="zoom-level">100%</span>
|
|
51
|
+
<button id="btn-zoom-in" title="Zoom in (+)">+</button>
|
|
52
|
+
<button id="btn-zoom-reset" title="Reset zoom (0)">⟲</button>
|
|
53
|
+
<button id="btn-zoom-fit" title="Fit to view (F)">Fit</button>
|
|
54
|
+
</div>
|
|
55
|
+
<button id="btn-ruler-grid" class="btn-ruler" title="Toggle rulers and grid overlay (G)">Ruler & Grid</button>
|
|
56
|
+
<button id="btn-shortcuts" class="btn-shortcuts" title="Show keyboard shortcuts (?)">⌨</button>
|
|
36
57
|
<label class="theme-toggle">
|
|
37
|
-
<input type="checkbox" id="dark-mode-toggle">
|
|
58
|
+
<input type="checkbox" id="dark-mode-toggle" DARK_MODE_CHECKED_PLACEHOLDER>
|
|
38
59
|
<span>Dark Mode</span>
|
|
39
60
|
</label>
|
|
40
61
|
</div>
|
|
41
62
|
</div>
|
|
42
|
-
<div class="preview-wrapper">
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
63
|
+
<div class="preview-wrapper" id="preview-wrapper">
|
|
64
|
+
<div class="zoom-container" id="zoom-container">
|
|
65
|
+
<img id="preview-image" src="data:image/png;base64,IMAGE_BASE64_PLACEHOLDER" alt="Figure preview">
|
|
66
|
+
<svg id="hitregion-overlay" class="hitregion-overlay"></svg>
|
|
67
|
+
<svg id="selection-overlay" class="selection-overlay"></svg>
|
|
68
|
+
<svg id="ruler-overlay" class="ruler-overlay"></svg>
|
|
69
|
+
<svg id="grid-overlay" class="grid-overlay"></svg>
|
|
70
|
+
<svg id="column-overlay" class="column-overlay"></svg>
|
|
71
|
+
<canvas id="hitmap-canvas" style="display: none;"></canvas>
|
|
72
|
+
</div>
|
|
50
73
|
</div>
|
|
51
74
|
</div>
|
|
52
75
|
|
|
@@ -86,6 +109,45 @@ HTML_TEMPLATE = """
|
|
|
86
109
|
</div>
|
|
87
110
|
</div>
|
|
88
111
|
</div>
|
|
112
|
+
<!-- Shortcuts Modal -->
|
|
113
|
+
<div id="shortcuts-modal" class="modal" style="display: none;">
|
|
114
|
+
<div class="modal-content shortcuts-modal-content">
|
|
115
|
+
<div class="modal-header">
|
|
116
|
+
<h3>Keyboard Shortcuts</h3>
|
|
117
|
+
<button id="shortcuts-modal-close" class="modal-close">×</button>
|
|
118
|
+
</div>
|
|
119
|
+
<div class="shortcuts-content">
|
|
120
|
+
<div class="shortcut-section">
|
|
121
|
+
<h4>General</h4>
|
|
122
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>Ctrl</kbd>+<kbd>S</kbd></span><span class="shortcut-desc">Save overrides</span></div>
|
|
123
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>S</kbd></span><span class="shortcut-desc">Download PNG</span></div>
|
|
124
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>I</kbd></span><span class="shortcut-desc">Debug snapshot</span></div>
|
|
125
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>F5</kbd> / <kbd>Ctrl</kbd>+<kbd>R</kbd></span><span class="shortcut-desc">Refresh preview</span></div>
|
|
126
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>Esc</kbd></span><span class="shortcut-desc">Clear selection</span></div>
|
|
127
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>R</kbd></span><span class="shortcut-desc">Reset to theme defaults</span></div>
|
|
128
|
+
</div>
|
|
129
|
+
<div class="shortcut-section">
|
|
130
|
+
<h4>Navigation</h4>
|
|
131
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>1</kbd></span><span class="shortcut-desc">Figure tab</span></div>
|
|
132
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>2</kbd></span><span class="shortcut-desc">Axis tab</span></div>
|
|
133
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>3</kbd></span><span class="shortcut-desc">Element tab</span></div>
|
|
134
|
+
</div>
|
|
135
|
+
<div class="shortcut-section">
|
|
136
|
+
<h4>View</h4>
|
|
137
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>G</kbd></span><span class="shortcut-desc">Toggle ruler & grid</span></div>
|
|
138
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>+</kbd> / <kbd>-</kbd></span><span class="shortcut-desc">Zoom in/out</span></div>
|
|
139
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>0</kbd></span><span class="shortcut-desc">Reset zoom</span></div>
|
|
140
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>F</kbd></span><span class="shortcut-desc">Fit to view</span></div>
|
|
141
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>?</kbd></span><span class="shortcut-desc">Show this help</span></div>
|
|
142
|
+
</div>
|
|
143
|
+
<div class="shortcut-section">
|
|
144
|
+
<h4>Developer</h4>
|
|
145
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>Alt</kbd>+<kbd>I</kbd></span><span class="shortcut-desc">Toggle element inspector</span></div>
|
|
146
|
+
<div class="shortcut-row"><span class="shortcut-keys"><kbd>Alt</kbd>+<kbd>Shift</kbd>+<kbd>I</kbd></span><span class="shortcut-desc">Screenshot + console logs</span></div>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
89
151
|
<div id="override-status" class="override-status" style="display: none;">
|
|
90
152
|
<span class="override-indicator">Manual overrides active</span>
|
|
91
153
|
<span id="override-timestamp" class="override-timestamp"></span>
|
|
@@ -160,8 +222,42 @@ HTML_TEMPLATE = """
|
|
|
160
222
|
<div id="tab-content-axis" class="tab-content">
|
|
161
223
|
<div class="tab-hint" id="axis-tab-hint">Select an axis element (title, label, ticks, legend) to edit</div>
|
|
162
224
|
|
|
163
|
-
<!--
|
|
225
|
+
<!-- Panel Position Section -->
|
|
164
226
|
<details class="section" open>
|
|
227
|
+
<summary>Panel Position</summary>
|
|
228
|
+
<div class="section-content">
|
|
229
|
+
<div class="form-row">
|
|
230
|
+
<label>Panel</label>
|
|
231
|
+
<select id="panel_selector">
|
|
232
|
+
<option value="0">Panel 0</option>
|
|
233
|
+
</select>
|
|
234
|
+
</div>
|
|
235
|
+
<div class="position-grid">
|
|
236
|
+
<div class="form-row">
|
|
237
|
+
<label>Left (mm)</label>
|
|
238
|
+
<input type="number" id="panel_left" step="1" min="0" placeholder="20">
|
|
239
|
+
</div>
|
|
240
|
+
<div class="form-row">
|
|
241
|
+
<label>Top (mm)</label>
|
|
242
|
+
<input type="number" id="panel_top" step="1" min="0" placeholder="15">
|
|
243
|
+
</div>
|
|
244
|
+
<div class="form-row">
|
|
245
|
+
<label>Width (mm)</label>
|
|
246
|
+
<input type="number" id="panel_width" step="1" min="0" placeholder="120">
|
|
247
|
+
</div>
|
|
248
|
+
<div class="form-row">
|
|
249
|
+
<label>Height (mm)</label>
|
|
250
|
+
<input type="number" id="panel_height" step="1" min="0" placeholder="90">
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
<div class="form-row" style="margin-top: 8px;">
|
|
254
|
+
<button id="apply_panel_position" class="btn-small">Apply Position</button>
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
</details>
|
|
258
|
+
|
|
259
|
+
<!-- Axes Size Section -->
|
|
260
|
+
<details class="section">
|
|
165
261
|
<summary>Axes Size</summary>
|
|
166
262
|
<div class="section-content">
|
|
167
263
|
<div class="form-row">
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""JavaScript modules for the figure editor.
|
|
4
|
+
|
|
5
|
+
This package contains modular JavaScript organized by functionality:
|
|
6
|
+
- _api.py: API calls (save, load, update, download)
|
|
7
|
+
- _colors.py: Color presets and conversion utilities
|
|
8
|
+
- _core.py: State variables and initialization
|
|
9
|
+
- _debug_snapshot.py: Screenshot + console log capture (Ctrl+Alt+I)
|
|
10
|
+
- _element_editor.py: Dynamic form fields and call properties
|
|
11
|
+
- _files.py: File switching functionality
|
|
12
|
+
- _hitmap.py: Hitmap loading and hit region drawing
|
|
13
|
+
- _inspector.py: Element inspector debugging
|
|
14
|
+
- _labels.py: Label inputs and axis/legend controls
|
|
15
|
+
- _modals.py: Theme and shortcuts modals
|
|
16
|
+
- _panel_drag.py: Panel drag-to-move (click+drag on empty panel area)
|
|
17
|
+
- _legend_drag.py: Legend drag-to-move (click+drag on legend)
|
|
18
|
+
- _panel_position.py: Panel position editing (left, bottom, width, height)
|
|
19
|
+
- _overlays.py: Measurement overlays (ruler, grid, columns)
|
|
20
|
+
- _selection.py: Selection drawing and property sync
|
|
21
|
+
- _tabs.py: Tab navigation (Figure/Axis/Element)
|
|
22
|
+
- _view_mode.py: View mode management (all/selected)
|
|
23
|
+
- _zoom.py: Zoom/pan functionality
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from ._api import SCRIPTS_API
|
|
27
|
+
from ._colors import SCRIPTS_COLORS
|
|
28
|
+
from ._core import SCRIPTS_CORE
|
|
29
|
+
from ._debug_snapshot import SCRIPTS_DEBUG_SNAPSHOT
|
|
30
|
+
from ._element_editor import SCRIPTS_ELEMENT_EDITOR
|
|
31
|
+
from ._files import SCRIPTS_FILES
|
|
32
|
+
from ._hitmap import SCRIPTS_HITMAP
|
|
33
|
+
from ._inspector import SCRIPTS_INSPECTOR
|
|
34
|
+
from ._labels import SCRIPTS_LABELS
|
|
35
|
+
from ._legend_drag import SCRIPTS_LEGEND_DRAG
|
|
36
|
+
from ._modals import SCRIPTS_MODALS
|
|
37
|
+
from ._overlays import SCRIPTS_OVERLAYS
|
|
38
|
+
from ._panel_drag import SCRIPTS_PANEL_DRAG
|
|
39
|
+
from ._panel_position import SCRIPTS_PANEL_POSITION
|
|
40
|
+
from ._selection import SCRIPTS_SELECTION
|
|
41
|
+
from ._tabs import SCRIPTS_TABS
|
|
42
|
+
from ._view_mode import SCRIPTS_VIEW_MODE
|
|
43
|
+
from ._zoom import SCRIPTS_ZOOM
|
|
44
|
+
|
|
45
|
+
# Combined SCRIPTS constant for backward compatibility
|
|
46
|
+
# Order matters: debug snapshot first (for console interception), then core/state, then features
|
|
47
|
+
SCRIPTS = (
|
|
48
|
+
SCRIPTS_DEBUG_SNAPSHOT
|
|
49
|
+
+ SCRIPTS_CORE
|
|
50
|
+
+ SCRIPTS_TABS
|
|
51
|
+
+ SCRIPTS_VIEW_MODE
|
|
52
|
+
+ SCRIPTS_COLORS
|
|
53
|
+
+ SCRIPTS_HITMAP
|
|
54
|
+
+ SCRIPTS_SELECTION
|
|
55
|
+
+ SCRIPTS_ELEMENT_EDITOR
|
|
56
|
+
+ SCRIPTS_LABELS
|
|
57
|
+
+ SCRIPTS_API
|
|
58
|
+
+ SCRIPTS_MODALS
|
|
59
|
+
+ SCRIPTS_ZOOM
|
|
60
|
+
+ SCRIPTS_OVERLAYS
|
|
61
|
+
+ SCRIPTS_INSPECTOR
|
|
62
|
+
+ SCRIPTS_FILES
|
|
63
|
+
+ SCRIPTS_PANEL_POSITION
|
|
64
|
+
+ SCRIPTS_PANEL_DRAG
|
|
65
|
+
+ SCRIPTS_LEGEND_DRAG
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def get_all_scripts():
|
|
70
|
+
"""Return all scripts as a dictionary for testing.
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
dict
|
|
75
|
+
Mapping of script name to script content.
|
|
76
|
+
"""
|
|
77
|
+
return {
|
|
78
|
+
"api": SCRIPTS_API,
|
|
79
|
+
"colors": SCRIPTS_COLORS,
|
|
80
|
+
"core": SCRIPTS_CORE,
|
|
81
|
+
"debug_snapshot": SCRIPTS_DEBUG_SNAPSHOT,
|
|
82
|
+
"element_editor": SCRIPTS_ELEMENT_EDITOR,
|
|
83
|
+
"files": SCRIPTS_FILES,
|
|
84
|
+
"hitmap": SCRIPTS_HITMAP,
|
|
85
|
+
"inspector": SCRIPTS_INSPECTOR,
|
|
86
|
+
"labels": SCRIPTS_LABELS,
|
|
87
|
+
"legend_drag": SCRIPTS_LEGEND_DRAG,
|
|
88
|
+
"modals": SCRIPTS_MODALS,
|
|
89
|
+
"overlays": SCRIPTS_OVERLAYS,
|
|
90
|
+
"panel_drag": SCRIPTS_PANEL_DRAG,
|
|
91
|
+
"panel_position": SCRIPTS_PANEL_POSITION,
|
|
92
|
+
"selection": SCRIPTS_SELECTION,
|
|
93
|
+
"tabs": SCRIPTS_TABS,
|
|
94
|
+
"view_mode": SCRIPTS_VIEW_MODE,
|
|
95
|
+
"zoom": SCRIPTS_ZOOM,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
__all__ = [
|
|
100
|
+
"SCRIPTS",
|
|
101
|
+
"SCRIPTS_API",
|
|
102
|
+
"SCRIPTS_COLORS",
|
|
103
|
+
"SCRIPTS_CORE",
|
|
104
|
+
"SCRIPTS_DEBUG_SNAPSHOT",
|
|
105
|
+
"SCRIPTS_ELEMENT_EDITOR",
|
|
106
|
+
"SCRIPTS_FILES",
|
|
107
|
+
"SCRIPTS_HITMAP",
|
|
108
|
+
"SCRIPTS_INSPECTOR",
|
|
109
|
+
"SCRIPTS_LABELS",
|
|
110
|
+
"SCRIPTS_LEGEND_DRAG",
|
|
111
|
+
"SCRIPTS_MODALS",
|
|
112
|
+
"SCRIPTS_OVERLAYS",
|
|
113
|
+
"SCRIPTS_PANEL_DRAG",
|
|
114
|
+
"SCRIPTS_PANEL_POSITION",
|
|
115
|
+
"SCRIPTS_SELECTION",
|
|
116
|
+
"SCRIPTS_TABS",
|
|
117
|
+
"SCRIPTS_VIEW_MODE",
|
|
118
|
+
"SCRIPTS_ZOOM",
|
|
119
|
+
"get_all_scripts",
|
|
120
|
+
]
|