pict-section-flow 1.0.0 → 1.0.1
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.
- package/docs/Theme_Integration.md +2 -2
- package/docs/index.html +0 -2
- package/package.json +3 -3
- package/source/PictFlowCard.js +2 -2
- package/source/providers/PictProvider-Flow-CSS.js +38 -12
- package/source/providers/PictProvider-Flow-ConnectorShapes.js +8 -8
- package/source/providers/PictProvider-Flow-Icons.js +33 -33
- package/source/providers/PictProvider-Flow-NodeTypes.js +9 -9
- package/source/providers/PictProvider-Flow-Renderer.js +516 -0
- package/source/providers/PictProvider-Flow-StylePresets.js +259 -0
- package/source/providers/PictProvider-Flow-Theme.js +97 -669
- package/source/services/PictService-Flow-ConnectionRenderer.js +6 -6
- package/source/services/PictService-Flow-PortRenderer.js +6 -6
- package/source/views/PictView-Flow-Node.js +1 -1
- package/source/views/PictView-Flow-PropertiesPanel.js +1 -1
- package/source/views/PictView-Flow-Toolbar.js +24 -16
- package/source/views/PictView-Flow.js +172 -47
- package/test/Renderer_tests.js +133 -0
- package/test/StylePresets_tests.js +153 -0
- package/docs/css/docuserve.css +0 -327
|
@@ -15,13 +15,13 @@ const _CHIP_PER_CHAR_PX = 5;
|
|
|
15
15
|
// badge borders so the hint bezier matches its port's affinity color.
|
|
16
16
|
const PORT_TYPE_COLORS =
|
|
17
17
|
{
|
|
18
|
-
'event-in': '#3498db',
|
|
19
|
-
'event-out': '#2ecc71',
|
|
20
|
-
'setting': '#e67e22',
|
|
21
|
-
'value': '#f1c40f',
|
|
22
|
-
'error': '#e74c3c'
|
|
18
|
+
'event-in': 'var(--theme-color-status-info, #3498db)',
|
|
19
|
+
'event-out': 'var(--theme-color-status-success, #2ecc71)',
|
|
20
|
+
'setting': 'var(--theme-color-status-warning, #e67e22)',
|
|
21
|
+
'value': 'var(--theme-color-status-warning, #f1c40f)',
|
|
22
|
+
'error': 'var(--theme-color-status-error, #e74c3c)'
|
|
23
23
|
};
|
|
24
|
-
const PORT_TYPE_DEFAULT_COLOR = '#95a5a6';
|
|
24
|
+
const PORT_TYPE_DEFAULT_COLOR = 'var(--theme-color-border-default, #95a5a6)';
|
|
25
25
|
|
|
26
26
|
class PictServiceFlowConnectionRenderer extends libFableServiceProviderBase
|
|
27
27
|
{
|
|
@@ -88,13 +88,13 @@ class PictServiceFlowPortRenderer extends libFableServiceProviderBase
|
|
|
88
88
|
{
|
|
89
89
|
let tmpPortTypeColorMap =
|
|
90
90
|
{
|
|
91
|
-
'event-in': '#3498db',
|
|
92
|
-
'event-out': '#2ecc71',
|
|
93
|
-
'setting': '#e67e22',
|
|
94
|
-
'value': '#f1c40f',
|
|
95
|
-
'error': '#e74c3c'
|
|
91
|
+
'event-in': 'var(--theme-color-status-info, #3498db)',
|
|
92
|
+
'event-out': 'var(--theme-color-status-success, #2ecc71)',
|
|
93
|
+
'setting': 'var(--theme-color-status-warning, #e67e22)',
|
|
94
|
+
'value': 'var(--theme-color-status-warning, #f1c40f)',
|
|
95
|
+
'error': 'var(--theme-color-status-error, #e74c3c)'
|
|
96
96
|
};
|
|
97
|
-
let tmpBorderColor = tmpPort.PortType ? (tmpPortTypeColorMap[tmpPort.PortType] || '#95a5a6') : '#95a5a6';
|
|
97
|
+
let tmpBorderColor = tmpPort.PortType ? (tmpPortTypeColorMap[tmpPort.PortType] || 'var(--theme-color-border-default, #95a5a6)') : 'var(--theme-color-border-default, #95a5a6)';
|
|
98
98
|
|
|
99
99
|
let tmpBadgeHeight = 12;
|
|
100
100
|
let tmpBadgePadH = 5;
|
|
@@ -239,7 +239,7 @@ class PictViewFlowNode extends libPictView
|
|
|
239
239
|
tmpCodeText.setAttribute('class', 'pict-flow-node-card-code');
|
|
240
240
|
tmpCodeText.setAttribute('font-size', '10');
|
|
241
241
|
tmpCodeText.setAttribute('font-family', 'monospace');
|
|
242
|
-
tmpCodeText.setAttribute('fill', '#7f8c8d');
|
|
242
|
+
tmpCodeText.setAttribute('fill', 'var(--theme-color-text-secondary, #7f8c8d)');
|
|
243
243
|
tmpCodeText.setAttribute('text-anchor', 'middle');
|
|
244
244
|
tmpCodeText.setAttribute('dominant-baseline', 'central');
|
|
245
245
|
tmpCodeText.setAttribute('pointer-events', 'none');
|
|
@@ -547,7 +547,7 @@ class PictViewFlowPropertiesPanel extends libPictView
|
|
|
547
547
|
|
|
548
548
|
// Resolve default colors from the node type config or CSS token defaults
|
|
549
549
|
let tmpNodeTypeConfig = this._FlowView._NodeTypeProvider.getNodeType(tmpNodeData.Type);
|
|
550
|
-
let tmpDefaultTitleBarColor = '#2c3e50';
|
|
550
|
+
let tmpDefaultTitleBarColor = 'var(--theme-color-text-primary, #2c3e50)';
|
|
551
551
|
let tmpDefaultBodyFill = '#ffffff';
|
|
552
552
|
let tmpDefaultBodyStroke = '#d0d4d8';
|
|
553
553
|
if (tmpNodeTypeConfig)
|
|
@@ -1500,30 +1500,36 @@ class PictViewFlowToolbar extends libPictView
|
|
|
1500
1500
|
*/
|
|
1501
1501
|
_buildSettingsPopup(pContainer)
|
|
1502
1502
|
{
|
|
1503
|
-
if (!this._FlowView
|
|
1503
|
+
if (!this._FlowView) return;
|
|
1504
1504
|
|
|
1505
1505
|
let tmpFlowViewIdentifier = this.options.FlowViewIdentifier;
|
|
1506
|
-
let
|
|
1507
|
-
let
|
|
1508
|
-
|
|
1506
|
+
let tmpPresetsProvider = this._FlowView._StylePresetsProvider;
|
|
1507
|
+
let tmpRendererProvider = this._FlowView._RendererProvider;
|
|
1508
|
+
if (!tmpPresetsProvider || !tmpRendererProvider) return;
|
|
1509
|
+
|
|
1510
|
+
// The single "Style" picker surfaces curated presets — each one bundles
|
|
1511
|
+
// a ColorTheme + Renderer + EdgeTheme. Per-axis overrides live behind
|
|
1512
|
+
// future "Customize" UI; the toolbar shows the preset list only.
|
|
1513
|
+
let tmpPresets = tmpPresetsProvider.listPresets();
|
|
1514
|
+
let tmpActivePreset = tmpPresetsProvider.getActivePresetHash();
|
|
1509
1515
|
|
|
1510
1516
|
let tmpThemeOptions = [];
|
|
1511
|
-
for (let i = 0; i <
|
|
1517
|
+
for (let i = 0; i < tmpPresets.length; i++)
|
|
1512
1518
|
{
|
|
1513
|
-
let
|
|
1519
|
+
let tmpPreset = tmpPresets[i];
|
|
1514
1520
|
tmpThemeOptions.push(
|
|
1515
1521
|
{
|
|
1516
|
-
Value:
|
|
1517
|
-
Label:
|
|
1518
|
-
SelectedAttr: (
|
|
1522
|
+
Value: tmpPreset.Hash,
|
|
1523
|
+
Label: tmpPreset.Label || tmpPreset.Hash,
|
|
1524
|
+
SelectedAttr: (tmpPreset.Hash === tmpActivePreset) ? ' selected="selected"' : ''
|
|
1519
1525
|
});
|
|
1520
1526
|
}
|
|
1521
1527
|
|
|
1522
1528
|
let tmpThemeOptionsHTML = this.pict.parseTemplateByHash('Flow-Layout-OptionList', { Options: tmpThemeOptions });
|
|
1523
1529
|
|
|
1524
|
-
let tmpNoiseLevel = Math.round(
|
|
1525
|
-
let
|
|
1526
|
-
let tmpNoiseEnabled = !!(
|
|
1530
|
+
let tmpNoiseLevel = Math.round(tmpRendererProvider.getNoiseLevel() * 100);
|
|
1531
|
+
let tmpActiveRenderer = tmpRendererProvider.getActiveRenderer();
|
|
1532
|
+
let tmpNoiseEnabled = !!(tmpActiveRenderer && tmpActiveRenderer.NoiseConfig && tmpActiveRenderer.NoiseConfig.Enabled);
|
|
1527
1533
|
let tmpNoiseDisplay = tmpNoiseEnabled ? '' : 'display:none;';
|
|
1528
1534
|
|
|
1529
1535
|
this.pict.ContentAssignment.assignContent(pContainer,
|
|
@@ -1585,16 +1591,18 @@ class PictViewFlowToolbar extends libPictView
|
|
|
1585
1591
|
let tmpNoiseSection = pContainer.querySelector('[data-settings-type="noise"]');
|
|
1586
1592
|
if (!tmpNoiseSection) return;
|
|
1587
1593
|
|
|
1588
|
-
let
|
|
1589
|
-
if (
|
|
1594
|
+
let tmpRendererProvider = this._FlowView._RendererProvider;
|
|
1595
|
+
if (!tmpRendererProvider) { tmpNoiseSection.style.display = 'none'; return; }
|
|
1596
|
+
let tmpRenderer = tmpRendererProvider.getActiveRenderer();
|
|
1597
|
+
if (tmpRenderer && tmpRenderer.NoiseConfig && tmpRenderer.NoiseConfig.Enabled)
|
|
1590
1598
|
{
|
|
1591
1599
|
tmpNoiseSection.style.display = '';
|
|
1592
|
-
// Update slider value to reflect
|
|
1600
|
+
// Update slider value to reflect renderer default
|
|
1593
1601
|
let tmpSlider = tmpNoiseSection.querySelector('.pict-flow-popup-settings-slider');
|
|
1594
1602
|
let tmpValueLabel = tmpNoiseSection.querySelector('.pict-flow-popup-settings-slider-value');
|
|
1595
1603
|
if (tmpSlider)
|
|
1596
1604
|
{
|
|
1597
|
-
let tmpLevel = Math.round(
|
|
1605
|
+
let tmpLevel = Math.round(tmpRendererProvider.getNoiseLevel() * 100);
|
|
1598
1606
|
tmpSlider.value = String(tmpLevel);
|
|
1599
1607
|
if (tmpValueLabel) tmpValueLabel.textContent = tmpLevel + '%';
|
|
1600
1608
|
}
|
|
@@ -23,6 +23,8 @@ const libPictProviderFlowCSS = require('../providers/PictProvider-Flow-CSS.js');
|
|
|
23
23
|
const libPictProviderFlowIcons = require('../providers/PictProvider-Flow-Icons.js');
|
|
24
24
|
const libPictProviderFlowConnectorShapes = require('../providers/PictProvider-Flow-ConnectorShapes.js');
|
|
25
25
|
const libPictProviderFlowTheme = require('../providers/PictProvider-Flow-Theme.js');
|
|
26
|
+
const libPictProviderFlowRenderer = require('../providers/PictProvider-Flow-Renderer.js');
|
|
27
|
+
const libPictProviderFlowStylePresets = require('../providers/PictProvider-Flow-StylePresets.js');
|
|
26
28
|
const libPictProviderFlowNoise = require('../providers/PictProvider-Flow-Noise.js');
|
|
27
29
|
|
|
28
30
|
const libPictViewFlowNode = require('./PictView-Flow-Node.js');
|
|
@@ -165,6 +167,11 @@ class PictViewFlow extends libPictView
|
|
|
165
167
|
{ ServiceType: 'PictProviderFlowNoise', Library: libPictProviderFlowNoise, Property: '_NoiseProvider', NoFlowView: true },
|
|
166
168
|
|
|
167
169
|
// Providers (need FlowView)
|
|
170
|
+
// Renderer + StylePresets must be created before the legacy Theme
|
|
171
|
+
// shim (which delegates to them) and before CSS PostInit so that
|
|
172
|
+
// registerCSS() sees an initialized renderer.
|
|
173
|
+
{ ServiceType: 'PictProviderFlowRenderer', Library: libPictProviderFlowRenderer, Property: '_RendererProvider' },
|
|
174
|
+
{ ServiceType: 'PictProviderFlowStylePresets', Library: libPictProviderFlowStylePresets, Property: '_StylePresetsProvider' },
|
|
168
175
|
{ ServiceType: 'PictProviderFlowTheme', Library: libPictProviderFlowTheme, Property: '_ThemeProvider' },
|
|
169
176
|
{ ServiceType: 'PictProviderFlowCSS', Library: libPictProviderFlowCSS, Property: '_CSSProvider', PostInit: 'registerCSS' },
|
|
170
177
|
{ ServiceType: 'PictProviderFlowIcons', Library: libPictProviderFlowIcons, Property: '_IconProvider', PostInit: 'registerIconTemplates' },
|
|
@@ -255,6 +262,8 @@ class PictViewFlow extends libPictView
|
|
|
255
262
|
this._IconProvider = null;
|
|
256
263
|
this._ConnectorShapesProvider = null;
|
|
257
264
|
this._ThemeProvider = null;
|
|
265
|
+
this._RendererProvider = null;
|
|
266
|
+
this._StylePresetsProvider = null;
|
|
258
267
|
this._NoiseProvider = null;
|
|
259
268
|
this._SVGHelperProvider = null;
|
|
260
269
|
this._GeometryProvider = null;
|
|
@@ -343,23 +352,40 @@ class PictViewFlow extends libPictView
|
|
|
343
352
|
{
|
|
344
353
|
super.onBeforeInitialize();
|
|
345
354
|
|
|
346
|
-
//
|
|
347
|
-
|
|
348
|
-
this._NoiseProvider
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
355
|
+
// Noise + Renderer + StylePresets + Theme shim must be created before
|
|
356
|
+
// CSS PostInit so registerCSS() sees an initialized renderer + presets.
|
|
357
|
+
this._NoiseProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowNoise');
|
|
358
|
+
this._RendererProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowRenderer', { FlowView: this });
|
|
359
|
+
this._StylePresetsProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowStylePresets', { FlowView: this });
|
|
360
|
+
this._ThemeProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowTheme', { FlowView: this });
|
|
361
|
+
|
|
362
|
+
// Apply initial style preset / per-axis overrides from options.
|
|
363
|
+
// `Theme` and `StylePreset` are aliases for the same preset-by-hash apply.
|
|
364
|
+
let tmpInitialPreset = this.options.StylePreset || this.options.Theme;
|
|
365
|
+
if (tmpInitialPreset)
|
|
366
|
+
{
|
|
367
|
+
this._StylePresetsProvider.applyPreset(tmpInitialPreset);
|
|
368
|
+
}
|
|
369
|
+
if (this.options.Renderer)
|
|
352
370
|
{
|
|
353
|
-
this.
|
|
371
|
+
this._RendererProvider.setRenderer(this.options.Renderer);
|
|
372
|
+
this._StylePresetsProvider.markCustomized();
|
|
354
373
|
}
|
|
355
374
|
if (typeof this.options.NoiseLevel === 'number')
|
|
356
375
|
{
|
|
357
|
-
this.
|
|
376
|
+
this._RendererProvider.setNoiseLevel(this.options.NoiseLevel);
|
|
358
377
|
}
|
|
359
378
|
|
|
360
|
-
// Instantiate all remaining services (skips Theme
|
|
379
|
+
// Instantiate all remaining services (skips Noise/Renderer/StylePresets/Theme
|
|
380
|
+
// since already set above)
|
|
361
381
|
this._instantiateServices();
|
|
362
382
|
|
|
383
|
+
// Now that CSSProvider exists, inject the active renderer's GeometryCSS.
|
|
384
|
+
if (this._CSSProvider && typeof this._CSSProvider.registerRendererCSS === 'function')
|
|
385
|
+
{
|
|
386
|
+
this._CSSProvider.registerRendererCSS(this._RendererProvider.getActiveRenderer());
|
|
387
|
+
}
|
|
388
|
+
|
|
363
389
|
// Subscribe to the host application's pict-provider-theme so the flow
|
|
364
390
|
// editor's marker arrowhead colors and shape overrides update when the
|
|
365
391
|
// host swaps light/dark or palette themes. CSS variables (--theme-*)
|
|
@@ -902,89 +928,188 @@ class PictViewFlow extends libPictView
|
|
|
902
928
|
return this._ViewportManager.exitFullscreen();
|
|
903
929
|
}
|
|
904
930
|
|
|
905
|
-
// ── Theme API
|
|
931
|
+
// ── Theme / Renderer / Style-Preset API ─────────────────────────────
|
|
932
|
+
//
|
|
933
|
+
// Three axes you can drive independently:
|
|
934
|
+
// - ColorTheme — delegates to pict-provider-theme (a pict-section-theme
|
|
935
|
+
// catalog hash like 'flow-sketch' or 'pict-default')
|
|
936
|
+
// - Renderer — delegates to PictProviderFlowRenderer (controls
|
|
937
|
+
// bracket/rect node body, jitter, shadows, fonts)
|
|
938
|
+
// - EdgeTheme — delegates to PictService-Flow-Layout (Bezier /
|
|
939
|
+
// Straight / Orthogonal / Perimeter / …; see
|
|
940
|
+
// PictView-Flow.setEdgeTheme below)
|
|
941
|
+
//
|
|
942
|
+
// Most users pick a curated combo via `setStylePreset()` — the preset
|
|
943
|
+
// applies all three axes in order. Per-axis overrides mark the active
|
|
944
|
+
// preset as 'customized' (getStylePreset returns null afterward).
|
|
945
|
+
//
|
|
946
|
+
// For backwards-compatibility, `setTheme()` / `getThemeKey()` continue
|
|
947
|
+
// to work as aliases for `setStylePreset()` / `getStylePreset()`.
|
|
906
948
|
|
|
907
949
|
/**
|
|
908
|
-
*
|
|
909
|
-
*
|
|
950
|
+
* Apply a named style preset — sets ColorTheme, Renderer, EdgeTheme
|
|
951
|
+
* (and optional NoiseLevel) in one call.
|
|
952
|
+
* @param {string} pPresetHash
|
|
910
953
|
*/
|
|
911
|
-
|
|
954
|
+
setStylePreset(pPresetHash)
|
|
912
955
|
{
|
|
913
|
-
if (!this.
|
|
956
|
+
if (!this._StylePresetsProvider)
|
|
914
957
|
{
|
|
915
|
-
this.log.warn('PictSectionFlow
|
|
958
|
+
this.log.warn('PictSectionFlow setStylePreset: StylePresets provider not available');
|
|
916
959
|
return;
|
|
917
960
|
}
|
|
961
|
+
let tmpApplied = this._StylePresetsProvider.applyPreset(pPresetHash);
|
|
962
|
+
if (!tmpApplied) { return; }
|
|
963
|
+
this._refreshAfterStyleChange();
|
|
964
|
+
if (this._EventHandlerProvider)
|
|
965
|
+
{
|
|
966
|
+
this._EventHandlerProvider.fireEvent('onStylePresetChanged', pPresetHash);
|
|
967
|
+
// Back-compat — old code listens for 'onThemeChanged'
|
|
968
|
+
this._EventHandlerProvider.fireEvent('onThemeChanged', pPresetHash);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
918
971
|
|
|
919
|
-
|
|
920
|
-
|
|
972
|
+
/**
|
|
973
|
+
* Hash of the active style preset, or null when in customized state.
|
|
974
|
+
* @returns {string|null}
|
|
975
|
+
*/
|
|
976
|
+
getStylePreset()
|
|
977
|
+
{
|
|
978
|
+
return this._StylePresetsProvider ? this._StylePresetsProvider.getActivePresetHash() : null;
|
|
979
|
+
}
|
|
921
980
|
|
|
922
|
-
|
|
923
|
-
|
|
981
|
+
/**
|
|
982
|
+
* Override just the color theme — delegates to pict-provider-theme.
|
|
983
|
+
* @param {string} pThemeHash - a pict-section-theme catalog hash
|
|
984
|
+
*/
|
|
985
|
+
setColorTheme(pThemeHash)
|
|
986
|
+
{
|
|
987
|
+
if (this.fable.providers && this.fable.providers.Theme)
|
|
924
988
|
{
|
|
925
|
-
this.
|
|
989
|
+
try { this.fable.providers.Theme.applyTheme(pThemeHash); }
|
|
990
|
+
catch (pErr) { this.log.warn(`PictSectionFlow setColorTheme: applyTheme failed — ${pErr.message}`); return; }
|
|
926
991
|
}
|
|
992
|
+
else
|
|
993
|
+
{
|
|
994
|
+
this.log.warn('PictSectionFlow setColorTheme: pict-provider-theme not available in host');
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
if (this._StylePresetsProvider) { this._StylePresetsProvider.markCustomized(); }
|
|
998
|
+
this._refreshAfterStyleChange();
|
|
999
|
+
if (this._EventHandlerProvider)
|
|
1000
|
+
{
|
|
1001
|
+
this._EventHandlerProvider.fireEvent('onColorThemeChanged', pThemeHash);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
927
1004
|
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
1005
|
+
/**
|
|
1006
|
+
* The active color theme hash (from pict-provider-theme).
|
|
1007
|
+
* @returns {string|null}
|
|
1008
|
+
*/
|
|
1009
|
+
getColorThemeKey()
|
|
1010
|
+
{
|
|
1011
|
+
if (this.fable.providers && this.fable.providers.Theme && typeof this.fable.providers.Theme.getActiveTheme === 'function')
|
|
933
1012
|
{
|
|
934
|
-
this.
|
|
1013
|
+
let tmpActive = this.fable.providers.Theme.getActiveTheme();
|
|
1014
|
+
if (tmpActive && tmpActive.Hash) { return tmpActive.Hash; }
|
|
935
1015
|
}
|
|
1016
|
+
return null;
|
|
1017
|
+
}
|
|
936
1018
|
|
|
1019
|
+
/**
|
|
1020
|
+
* Override just the renderer — controls node body shape, jitter, shadows.
|
|
1021
|
+
* @param {string} pRendererKey
|
|
1022
|
+
*/
|
|
1023
|
+
setRenderer(pRendererKey)
|
|
1024
|
+
{
|
|
1025
|
+
if (!this._RendererProvider)
|
|
1026
|
+
{
|
|
1027
|
+
this.log.warn('PictSectionFlow setRenderer: Renderer provider not available');
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
let tmpApplied = this._RendererProvider.setRenderer(pRendererKey);
|
|
1031
|
+
if (!tmpApplied) { return; }
|
|
1032
|
+
if (this._StylePresetsProvider) { this._StylePresetsProvider.markCustomized(); }
|
|
1033
|
+
this._refreshAfterStyleChange();
|
|
937
1034
|
if (this._EventHandlerProvider)
|
|
938
1035
|
{
|
|
939
|
-
this._EventHandlerProvider.fireEvent('
|
|
1036
|
+
this._EventHandlerProvider.fireEvent('onRendererChanged', pRendererKey);
|
|
940
1037
|
}
|
|
941
1038
|
}
|
|
942
1039
|
|
|
943
1040
|
/**
|
|
944
|
-
*
|
|
1041
|
+
* The active renderer key.
|
|
1042
|
+
* @returns {string}
|
|
1043
|
+
*/
|
|
1044
|
+
getRendererKey()
|
|
1045
|
+
{
|
|
1046
|
+
return this._RendererProvider ? this._RendererProvider.getActiveRendererKey() : 'clean';
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
/**
|
|
1050
|
+
* Set the noise level (0 to 1) and re-render. Noise applies only when
|
|
1051
|
+
* the active renderer enables it (see Renderer.NoiseConfig).
|
|
945
1052
|
* @param {number} pLevel - 0 = precise, 1 = maximum wobble
|
|
946
1053
|
*/
|
|
947
1054
|
setNoiseLevel(pLevel)
|
|
948
1055
|
{
|
|
949
|
-
if (
|
|
1056
|
+
if (this._RendererProvider)
|
|
950
1057
|
{
|
|
951
|
-
this.
|
|
952
|
-
return;
|
|
1058
|
+
this._RendererProvider.setNoiseLevel(pLevel);
|
|
953
1059
|
}
|
|
954
|
-
|
|
955
|
-
this._ThemeProvider.setNoiseLevel(pLevel);
|
|
956
|
-
|
|
957
|
-
// Full re-render to apply new noise
|
|
958
|
-
if (this.initialRenderComplete)
|
|
1060
|
+
else if (this._ThemeProvider)
|
|
959
1061
|
{
|
|
960
|
-
this.
|
|
1062
|
+
this._ThemeProvider.setNoiseLevel(pLevel);
|
|
961
1063
|
}
|
|
1064
|
+
if (this.initialRenderComplete) { this.renderFlow(); }
|
|
962
1065
|
}
|
|
963
1066
|
|
|
964
1067
|
/**
|
|
965
|
-
*
|
|
1068
|
+
* Current noise level (0 to 1).
|
|
966
1069
|
* @returns {number}
|
|
967
1070
|
*/
|
|
968
1071
|
getNoiseLevel()
|
|
969
1072
|
{
|
|
970
|
-
if (this.
|
|
971
|
-
{
|
|
972
|
-
return this._ThemeProvider.getNoiseLevel();
|
|
973
|
-
}
|
|
1073
|
+
if (this._RendererProvider) { return this._RendererProvider.getNoiseLevel(); }
|
|
1074
|
+
if (this._ThemeProvider) { return this._ThemeProvider.getNoiseLevel(); }
|
|
974
1075
|
return 0;
|
|
975
1076
|
}
|
|
976
1077
|
|
|
977
1078
|
/**
|
|
978
|
-
*
|
|
979
|
-
*
|
|
1079
|
+
* @deprecated since the 3-axis refactor — use setStylePreset() instead.
|
|
1080
|
+
* Kept as an alias for back-compat with existing host apps and views.
|
|
1081
|
+
* @param {string} pPresetHash
|
|
1082
|
+
*/
|
|
1083
|
+
setTheme(pPresetHash)
|
|
1084
|
+
{
|
|
1085
|
+
this.setStylePreset(pPresetHash);
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
/**
|
|
1089
|
+
* @deprecated since the 3-axis refactor — use getStylePreset() instead.
|
|
1090
|
+
* Returns the active preset hash (or null if customized).
|
|
1091
|
+
* @returns {string|null}
|
|
980
1092
|
*/
|
|
981
1093
|
getThemeKey()
|
|
982
1094
|
{
|
|
983
|
-
|
|
1095
|
+
return this.getStylePreset();
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
/**
|
|
1099
|
+
* Common refresh path used by all axis-change methods.
|
|
1100
|
+
* Re-registers the renderer CSS, re-injects marker defs (arrowhead colors
|
|
1101
|
+
* may have shifted with the new theme), and full-renders the flow.
|
|
1102
|
+
* @private
|
|
1103
|
+
*/
|
|
1104
|
+
_refreshAfterStyleChange()
|
|
1105
|
+
{
|
|
1106
|
+
if (this._CSSProvider && typeof this._CSSProvider.registerRendererCSS === 'function' && this._RendererProvider)
|
|
984
1107
|
{
|
|
985
|
-
|
|
1108
|
+
this._CSSProvider.registerRendererCSS(this._RendererProvider.getActiveRenderer());
|
|
986
1109
|
}
|
|
987
|
-
|
|
1110
|
+
if (this._CSSProvider) { this._CSSProvider.registerCSS(); }
|
|
1111
|
+
this._reinjectMarkerDefs();
|
|
1112
|
+
if (this.initialRenderComplete) { this.renderFlow(); }
|
|
988
1113
|
}
|
|
989
1114
|
|
|
990
1115
|
_reinjectMarkerDefs() { return this._RenderManager.reinjectMarkerDefs(); }
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
const libFable = require('fable');
|
|
2
|
+
const libChai = require('chai');
|
|
3
|
+
const libExpect = libChai.expect;
|
|
4
|
+
|
|
5
|
+
const libRenderer = require('../source/providers/PictProvider-Flow-Renderer.js');
|
|
6
|
+
|
|
7
|
+
suite('PictProvider-Flow-Renderer',
|
|
8
|
+
function ()
|
|
9
|
+
{
|
|
10
|
+
let _Fable;
|
|
11
|
+
let _Renderer;
|
|
12
|
+
|
|
13
|
+
setup(function ()
|
|
14
|
+
{
|
|
15
|
+
_Fable = new libFable({});
|
|
16
|
+
_Renderer = new libRenderer(_Fable, {}, 'Renderer-Test');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
suite('Built-in renderer registry', function ()
|
|
20
|
+
{
|
|
21
|
+
test('registers clean, bracket, sketch, crt, workstation by default', function ()
|
|
22
|
+
{
|
|
23
|
+
let tmpKeys = _Renderer.getRendererKeys();
|
|
24
|
+
libExpect(tmpKeys).to.include('clean');
|
|
25
|
+
libExpect(tmpKeys).to.include('bracket');
|
|
26
|
+
libExpect(tmpKeys).to.include('sketch');
|
|
27
|
+
libExpect(tmpKeys).to.include('crt');
|
|
28
|
+
libExpect(tmpKeys).to.include('workstation');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('clean is the default active renderer', function ()
|
|
32
|
+
{
|
|
33
|
+
libExpect(_Renderer.getActiveRendererKey()).to.equal('clean');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('each built-in renderer has the required shape', function ()
|
|
37
|
+
{
|
|
38
|
+
let tmpKeys = _Renderer.getRendererKeys();
|
|
39
|
+
for (let i = 0; i < tmpKeys.length; i++)
|
|
40
|
+
{
|
|
41
|
+
let tmpR = _Renderer.getActiveRenderer.call(
|
|
42
|
+
{ _Renderers: _Renderer._Renderers, _ActiveRendererKey: tmpKeys[i] });
|
|
43
|
+
libExpect(tmpR, `renderer ${tmpKeys[i]}`).to.have.property('Key', tmpKeys[i]);
|
|
44
|
+
libExpect(tmpR).to.have.property('NodeBodyMode');
|
|
45
|
+
libExpect(tmpR).to.have.property('NoiseConfig');
|
|
46
|
+
libExpect(tmpR).to.have.property('ConnectionConfig');
|
|
47
|
+
libExpect(tmpR).to.have.property('GeometryCSS');
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
suite('setRenderer()', function ()
|
|
53
|
+
{
|
|
54
|
+
test('switches the active renderer + updates noise default', function ()
|
|
55
|
+
{
|
|
56
|
+
_Renderer.setRenderer('sketch');
|
|
57
|
+
libExpect(_Renderer.getActiveRendererKey()).to.equal('sketch');
|
|
58
|
+
let tmpActive = _Renderer.getActiveRenderer();
|
|
59
|
+
libExpect(tmpActive.NodeBodyMode).to.equal('bracket');
|
|
60
|
+
libExpect(_Renderer.getNoiseLevel()).to.equal(0.4);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('returns false for unknown renderer + leaves state unchanged', function ()
|
|
64
|
+
{
|
|
65
|
+
_Renderer.setRenderer('sketch');
|
|
66
|
+
let tmpResult = _Renderer.setRenderer('nonexistent');
|
|
67
|
+
libExpect(tmpResult).to.equal(false);
|
|
68
|
+
libExpect(_Renderer.getActiveRendererKey()).to.equal('sketch');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('switching to a renderer with noise disabled resets noise to 0', function ()
|
|
72
|
+
{
|
|
73
|
+
_Renderer.setRenderer('sketch'); // 0.4
|
|
74
|
+
_Renderer.setRenderer('clean'); // 0
|
|
75
|
+
libExpect(_Renderer.getNoiseLevel()).to.equal(0);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
suite('register()', function ()
|
|
80
|
+
{
|
|
81
|
+
test('registers a custom renderer + reads back through getActiveRenderer', function ()
|
|
82
|
+
{
|
|
83
|
+
_Renderer.register('custom', {
|
|
84
|
+
Label: 'Custom',
|
|
85
|
+
NodeBodyMode: 'rect',
|
|
86
|
+
NoiseConfig: { Enabled: false, DefaultLevel: 0, MaxJitterPx: 0, AffectsNodes: false, AffectsConnections: false },
|
|
87
|
+
ConnectionConfig: { StrokeWidth: 3, ArrowheadStyle: 'triangle' },
|
|
88
|
+
GeometryCSS: '',
|
|
89
|
+
AdditionalCSS: ''
|
|
90
|
+
});
|
|
91
|
+
let tmpResult = _Renderer.setRenderer('custom');
|
|
92
|
+
libExpect(tmpResult).to.equal(true);
|
|
93
|
+
let tmpActive = _Renderer.getActiveRenderer();
|
|
94
|
+
libExpect(tmpActive.Key).to.equal('custom');
|
|
95
|
+
libExpect(tmpActive.Label).to.equal('Custom');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
suite('Noise APIs', function ()
|
|
100
|
+
{
|
|
101
|
+
test('setNoiseLevel clamps to [0,1]', function ()
|
|
102
|
+
{
|
|
103
|
+
_Renderer.setNoiseLevel(-1);
|
|
104
|
+
libExpect(_Renderer.getNoiseLevel()).to.equal(0);
|
|
105
|
+
_Renderer.setNoiseLevel(2);
|
|
106
|
+
libExpect(_Renderer.getNoiseLevel()).to.equal(1);
|
|
107
|
+
_Renderer.setNoiseLevel(0.5);
|
|
108
|
+
libExpect(_Renderer.getNoiseLevel()).to.equal(0.5);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('getNodeNoiseAmplitude is 0 when active renderer disables noise', function ()
|
|
112
|
+
{
|
|
113
|
+
_Renderer.setRenderer('clean');
|
|
114
|
+
_Renderer.setNoiseLevel(1);
|
|
115
|
+
libExpect(_Renderer.getNodeNoiseAmplitude()).to.equal(0);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('getNodeNoiseAmplitude scales with noise level when sketch is active', function ()
|
|
119
|
+
{
|
|
120
|
+
_Renderer.setRenderer('sketch');
|
|
121
|
+
_Renderer.setNoiseLevel(0.5);
|
|
122
|
+
// sketch.MaxJitterPx is 4 — 0.5 * 4 = 2
|
|
123
|
+
libExpect(_Renderer.getNodeNoiseAmplitude()).to.equal(2);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('processPathString is a no-op when noise is disabled', function ()
|
|
127
|
+
{
|
|
128
|
+
_Renderer.setRenderer('clean');
|
|
129
|
+
let tmpResult = _Renderer.processPathString('M 0 0 L 10 10', 'seed');
|
|
130
|
+
libExpect(tmpResult).to.equal('M 0 0 L 10 10');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
});
|