Skip to content

Commit 706726b

Browse files
committed
Version bump
- context menu option to clone filter selector filters - fixed scroll position targeting for PresetSearch app - implemented sorting for filter drag/drop placeables detection - control and form added to allow editing of preset name/defaultTexture - expanded preset searches to the param types - updating default presets to include latest filters
1 parent 156fa24 commit 706726b

10 files changed

Lines changed: 381 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
# Token Magic FX - Update v0.7.6
2+
3+
**Filter Editor**
4+
5+
- `Clone` context menu option has been added
6+
- Clones/Duplicates selected filter
7+
- Scroll position is now retained when deleting presets
8+
- Filters/Presets dragged onto canvas will now apply to top-most placeable based on `elevation` and `sort`
9+
- New control added to `Preset Search`; `Edit`
10+
- Opens a form to change preset name and/or default texture
11+
- Searches within `Preset Search` app in addition to name will now also match against filter types contained within the preset params
12+
13+
**Misc**
14+
15+
- New default presets have been added:
16+
- `DungeonDraft Tint`, `Replace Color`, `Dot Shade`, `CRT Monitor`, `RGB Split`, `Criss-Cross`, `Star Mask`
17+
118
# Token Magic FX - Update v0.7.5.1
219

320
**Filter Editor**

tokenmagic/gui/apps/FilterEditor.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,27 @@ class FilterSelector extends HandlebarsApplicationMixin(ApplicationV2) {
443443
});
444444
this._hooks.push({ hook, id });
445445
}
446+
447+
this._createContextMenu(this._getFilterContextOptions, '.filter', {
448+
hookName: 'getFilterContextOptions',
449+
});
450+
}
451+
452+
_getFilterContextOptions() {
453+
return [
454+
{
455+
id: 'clone',
456+
name: 'TMFX.app.filterSelector.controls.clone',
457+
icon: '<i class="fa-solid fa-clone"></i>',
458+
callback: (element) => this._onCloneFilter(element),
459+
},
460+
];
461+
}
462+
463+
_onCloneFilter(element) {
464+
const { filterId, filterType, filterInternalId } = element.dataset;
465+
const filter = FilterSelector.getFilter(this._document, { filterId, filterType, filterInternalId });
466+
if (filter) TokenMagic.addFilters(this._document, [deepClone(filter)]);
446467
}
447468

448469
/**

tokenmagic/gui/apps/PresetSearch.js

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ export class PresetSearch extends HandlebarsApplicationMixin(ApplicationV2) {
2525
resizable: true,
2626
},
2727
position: {
28-
width: 300,
28+
width: 350,
2929
height: 500,
3030
},
3131
classes: ['tokenmagic', 'search', 'flexcol'],
3232
actions: {
3333
delete: PresetSearch._onDeletePreset,
34+
edit: PresetSearch._onEditPreset,
3435
toggleTemplates: PresetSearch._onToggleTemplates,
3536
},
3637
};
@@ -45,7 +46,7 @@ export class PresetSearch extends HandlebarsApplicationMixin(ApplicationV2) {
4546
},
4647
presets: {
4748
template: `modules/tokenmagic/templates/apps/filter-editor/filter-list.hbs`,
48-
scrollable: ['.filter-list'],
49+
scrollable: [''],
4950
},
5051
};
5152

@@ -60,7 +61,7 @@ export class PresetSearch extends HandlebarsApplicationMixin(ApplicationV2) {
6061
context.controls = [
6162
{
6263
action: 'toggleTemplates',
63-
tooltip: 'Toggle Template presets',
64+
tooltip: game.i18n.localize('TMFX.app.searchPreset.controls.templateToggle'),
6465
icon: 'fa-fw fa-solid fa-ruler-combined',
6566
active: Boolean(this._templates),
6667
},
@@ -88,16 +89,23 @@ export class PresetSearch extends HandlebarsApplicationMixin(ApplicationV2) {
8889
if (terms.length) {
8990
presets = presets.filter((p) => {
9091
const name = p.name.toLocaleLowerCase();
91-
return terms.every((t) => name.includes(t));
92+
const filterTypes = p.params.map((param) => param.filterType.toLocaleLowerCase());
93+
return terms.every((t) => name.includes(t) || filterTypes.some((type) => type.includes(t)));
9294
});
9395
}
9496
}
9597

9698
const controls = [
99+
{
100+
class: 'edit',
101+
action: 'edit',
102+
tooltip: game.i18n.localize('SIDEBAR.Edit'),
103+
icon: 'fa-solid fa-pen-to-square',
104+
},
97105
{
98106
class: 'delete',
99107
action: 'delete',
100-
tooltip: 'Delete',
108+
tooltip: game.i18n.localize('SIDEBAR.Delete'),
101109
icon: 'fa-solid fa-trash',
102110
},
103111
];
@@ -169,4 +177,87 @@ export class PresetSearch extends HandlebarsApplicationMixin(ApplicationV2) {
169177
this.render({ parts: ['presets'] });
170178
}
171179
}
180+
181+
static async _onEditPreset(event, element) {
182+
const { filterId: name, filterType: library } = element.closest('.filter').dataset;
183+
const preset = TokenMagic.getPresets(library).find((p) => p.name === name);
184+
if (preset) new PresetEdit({ preset, parentApp: this }).render(true);
185+
}
186+
}
187+
188+
export class PresetEdit extends HandlebarsApplicationMixin(ApplicationV2) {
189+
constructor({ preset, parentApp }) {
190+
super({});
191+
this._preset = foundry.utils.deepClone(preset);
192+
this._parentApp = parentApp;
193+
}
194+
195+
/** @override */
196+
static DEFAULT_OPTIONS = {
197+
id: 'tmfx-preset-edit',
198+
tag: 'form',
199+
window: {
200+
resizable: false,
201+
contentClasses: ['standard-form'],
202+
},
203+
form: {
204+
handler: PresetEdit._onSubmit,
205+
submitOnChange: false,
206+
closeOnSubmit: true,
207+
},
208+
position: {
209+
width: 450,
210+
height: 'auto',
211+
},
212+
classes: ['tokenmagic', 'flexcol'],
213+
actions: {
214+
delete: PresetSearch._onDeletePreset,
215+
edit: PresetSearch._onEditPreset,
216+
toggleTemplates: PresetSearch._onToggleTemplates,
217+
},
218+
};
219+
220+
get title() {
221+
return this._preset.name;
222+
}
223+
224+
/** @override */
225+
static PARTS = {
226+
main: {
227+
template: `modules/tokenmagic/templates/apps/preset-search/preset-edit.hbs`,
228+
},
229+
footer: { template: 'templates/generic/form-footer.hbs' },
230+
};
231+
232+
/** @override */
233+
async _preparePartContext(partId, context, options) {
234+
context.partId = partId;
235+
switch (partId) {
236+
case 'main':
237+
context.name = this._preset.name;
238+
context.library = this._preset.library;
239+
context.defaultTexture = this._preset.defaultTexture;
240+
context.params = JSON.stringify(this._preset.params, null, 2);
241+
break;
242+
case 'footer':
243+
context.buttons = [
244+
{ type: 'submit', icon: 'fa-solid fa-floppy-disk', label: game.i18n.localize('TMFX.save'), action: 'save' },
245+
];
246+
break;
247+
}
248+
return context;
249+
}
250+
251+
static async _onSubmit(event, form, formData) {
252+
const name = formData.object.name.trim();
253+
const defaultTexture = formData.object.defaultTexture?.trim();
254+
if (this._preset.name === name && this._preset.defaultTexture === defaultTexture) return;
255+
if (!name) return;
256+
257+
await TokenMagic.deletePreset({ name: this._preset.name, library: this._preset.library }, true);
258+
await TokenMagic.addPreset({ name, library: this._preset.library, defaultTexture }, this._preset.params, true);
259+
if (this._parentApp.state === ApplicationV2.RENDER_STATES.RENDERED) {
260+
this._parentApp.render({ parts: ['presets'] });
261+
}
262+
}
172263
}
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
[
2+
{
3+
"name": "DungeonDraft Tint",
4+
"library": "tmfx-main",
5+
"params": [
6+
{
7+
"filterType": "ddTint",
8+
"filterId": "DungeonDraft Tint",
9+
"tint": [
10+
0,
11+
1,
12+
0
13+
],
14+
"rank": 10001,
15+
"enabled": true
16+
}
17+
]
18+
},
19+
{
20+
"name": "Replace Color",
21+
"library": "tmfx-main",
22+
"params": [
23+
{
24+
"filterType": "replaceColor",
25+
"filterId": "Replace Color",
26+
"originalColor": [
27+
1,
28+
0,
29+
0
30+
],
31+
"newColor": [
32+
0,
33+
1,
34+
0
35+
],
36+
"epsilon": 0.7,
37+
"rank": 10001,
38+
"enabled": true,
39+
"animated": {}
40+
}
41+
]
42+
},
43+
{
44+
"name": "Dot Shade",
45+
"library": "tmfx-main",
46+
"params": [
47+
{
48+
"filterType": "dot",
49+
"filterId": "Dot Shade",
50+
"scale": 0.76,
51+
"angle": 0,
52+
"grayscale": true,
53+
"rank": 10002,
54+
"enabled": true
55+
}
56+
]
57+
},
58+
{
59+
"name": "CRT Monitor",
60+
"library": "tmfx-main",
61+
"params": [
62+
{
63+
"filterType": "crt",
64+
"filterId": "CRT Monitor",
65+
"curvature": 4,
66+
"lineWidth": 5,
67+
"lineContrast": 0.25,
68+
"verticalLine": false,
69+
"noise": 0.3,
70+
"noiseSize": 1,
71+
"vignetting": 0,
72+
"vignettingAlpha": 1,
73+
"vignettingBlur": 0.3,
74+
"animated": {
75+
"seed": {
76+
"active": true,
77+
"animType": "randomNumber",
78+
"val1": 0,
79+
"val2": 1
80+
},
81+
"time": {
82+
"active": true,
83+
"speed": -0.01,
84+
"animType": "move"
85+
}
86+
},
87+
"enabled": true,
88+
"rank": 10003
89+
},
90+
{
91+
"filterType": "outline",
92+
"filterId": "CRT Monitor",
93+
"color": 0,
94+
"thickness": 0,
95+
"zOrder": 321,
96+
"enabled": true,
97+
"rank": 10004
98+
}
99+
]
100+
},
101+
{
102+
"name": "RGB Split",
103+
"library": "tmfx-main",
104+
"params": [
105+
{
106+
"filterType": "rgbSplit",
107+
"filterId": "RGB Split",
108+
"redX": -10,
109+
"redY": 0,
110+
"greenX": 0,
111+
"greenY": 10,
112+
"blueX": 0,
113+
"blueY": 0,
114+
"enabled": true,
115+
"rank": 10005
116+
}
117+
]
118+
},
119+
{
120+
"name": "Criss-Cross",
121+
"library": "tmfx-main",
122+
"params": [
123+
{
124+
"filterType": "sprite",
125+
"filterId": "Criss-Cross",
126+
"imagePath": "modules/tokenmagic/fx/assets/box.webp",
127+
"repeat": true,
128+
"alphaDiscard": true,
129+
"colorize": true,
130+
"color": 16688682,
131+
"inverse": true,
132+
"gridPadding": 1,
133+
"maintainAspectRatio": false,
134+
"maintainScale": false,
135+
"scaleX": 0.16,
136+
"scaleY": 0.16,
137+
"translationX": 0,
138+
"translationY": 0,
139+
"rotation": 45,
140+
"alpha": 1,
141+
"top": true,
142+
"animated": {},
143+
"rank": 10006,
144+
"enabled": true,
145+
"play": true,
146+
"loop": true
147+
}
148+
]
149+
},
150+
{
151+
"name": "Star Mask",
152+
"library": "tmfx-main",
153+
"params": [
154+
{
155+
"filterType": "spriteMask",
156+
"filterId": "Star Mask",
157+
"imagePath": "modules/tokenmagic/fx/assets/star.webp",
158+
"repeat": false,
159+
"gridPadding": 1,
160+
"maintainAspectRatio": false,
161+
"maintainScale": false,
162+
"scaleX": 1,
163+
"scaleY": 1,
164+
"translationX": 0,
165+
"translationY": 0,
166+
"rotation": 0,
167+
"alpha": 1,
168+
"rank": 10000,
169+
"enabled": true
170+
}
171+
]
172+
}
173+
]

tokenmagic/lang/en.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"TMFX.app.filterSelector.controls.save": "Save as Preset",
6363
"TMFX.app.filterSelector.controls.macro": "Display as a Macro",
6464
"TMFX.app.filterSelector.controls.randomize": "Re-roll Randomized Fields",
65+
"TMFX.app.filterSelector.controls.clone": "Clone",
6566
"TMFX.app.filterEditor.title": "Filter",
6667
"TMFX.app.animationEditor.title": "Animate",
6768
"TMFX.app.randomizationEditor.title": "Randomize",
@@ -87,5 +88,8 @@
8788
"TMFX.app.savePreset.autoDestroy.hint": "Check to auto-destroy/remove filter once a looping animation finishes.",
8889
"TMFX.app.savePreset.confirm.title": "Overwrite Preset",
8990
"TMFX.app.savePreset.confirm.message": "A preset with the same name already exists. Would you like to overwrite it?",
91+
"TMFX.app.searchPreset.controls.templateToggle": "Toggle Template Presets",
92+
"TMFX.app.editPreset.option.library": "Library",
93+
"TMFX.app.editPreset.option.defaultTexture": "Default Texture",
9094
"TMFX.save": "Save"
9195
}

0 commit comments

Comments
 (0)