mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-13 00:55:20 +01:00
Filterrific! (#55246)
Filter refactor + In Game Filter Editor Accessed via VV in the dropdown of atoms. "Edit Filters. Makes filters actually usable. Co-authored-by: ghgh <hghgh>
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#define COLOR_FLOORTILE_GRAY "#8D8B8B"
|
||||
#define COLOR_ALMOST_BLACK "#333333"
|
||||
#define COLOR_BLACK "#000000"
|
||||
#define COLOR_HALF_TRANSPARENT_BLACK "#0000007A"
|
||||
|
||||
#define COLOR_RED "#FF0000"
|
||||
#define COLOR_MOSTLY_PURE_RED "#FF3300"
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
#define VV_HK_TRIGGER_EXPLOSION "explode"
|
||||
#define VV_HK_AUTO_RENAME "auto_rename"
|
||||
#define VV_HK_RADIATE "radiate"
|
||||
#define VV_HK_EDIT_FILTERS "edit_filters"
|
||||
#define VV_HK_ADD_AI "add_ai"
|
||||
|
||||
// /obj
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
#define ICON_NOT_SET "Not Set"
|
||||
|
||||
//This is stored as a nested list instead of datums or whatever because it json encodes nicely for usage in tgui
|
||||
GLOBAL_LIST_INIT(master_filter_info, list(
|
||||
"alpha" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"icon" = ICON_NOT_SET,
|
||||
"render_source" = "",
|
||||
"flags" = 0
|
||||
),
|
||||
"flags" = list(
|
||||
"MASK_INVERSE" = MASK_INVERSE,
|
||||
"MASK_SWAP" = MASK_SWAP
|
||||
)
|
||||
),
|
||||
"angular_blur" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"size" = 1
|
||||
)
|
||||
),
|
||||
/* Not supported because making a proper matrix editor on the frontend would be a huge dick pain.
|
||||
Uncomment if you ever implement it
|
||||
"color" = list(
|
||||
"defaults" = list(
|
||||
"color" = matrix(),
|
||||
"space" = FILTER_COLOR_RGB
|
||||
)
|
||||
),
|
||||
*/
|
||||
"displace" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"size" = null,
|
||||
"icon" = ICON_NOT_SET,
|
||||
"render_source" = ""
|
||||
)
|
||||
),
|
||||
"drop_shadow" = list(
|
||||
"defaults" = list(
|
||||
"x" = 1,
|
||||
"y" = -1,
|
||||
"size" = 1,
|
||||
"offset" = 0,
|
||||
"color" = COLOR_HALF_TRANSPARENT_BLACK
|
||||
)
|
||||
),
|
||||
"blur" = list(
|
||||
"defaults" = list(
|
||||
"size" = 1
|
||||
)
|
||||
),
|
||||
"layer" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"icon" = ICON_NOT_SET,
|
||||
"render_source" = "",
|
||||
"flags" = FILTER_OVERLAY,
|
||||
"color" = "",
|
||||
"transform" = null,
|
||||
"blend_mode" = BLEND_DEFAULT
|
||||
)
|
||||
),
|
||||
"motion_blur" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0
|
||||
)
|
||||
),
|
||||
"outline" = list(
|
||||
"defaults" = list(
|
||||
"size" = 0,
|
||||
"color" = COLOR_BLACK,
|
||||
"flags" = NONE
|
||||
),
|
||||
"flags" = list(
|
||||
"OUTLINE_SHARP" = OUTLINE_SHARP,
|
||||
"OUTLINE_SQUARE" = OUTLINE_SQUARE
|
||||
)
|
||||
),
|
||||
"radial_blur" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"size" = 0.01
|
||||
)
|
||||
),
|
||||
"rays" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"size" = 16,
|
||||
"color" = COLOR_WHITE,
|
||||
"offset" = 0,
|
||||
"density" = 10,
|
||||
"threshold" = 0.5,
|
||||
"factor" = 0,
|
||||
"flags" = FILTER_OVERLAY | FILTER_UNDERLAY
|
||||
),
|
||||
"flags" = list(
|
||||
"FILTER_OVERLAY" = FILTER_OVERLAY,
|
||||
"FILTER_UNDERLAY" = FILTER_UNDERLAY
|
||||
)
|
||||
),
|
||||
"ripple" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"size" = 1,
|
||||
"repeat" = 2,
|
||||
"radius" = 0,
|
||||
"falloff" = 1,
|
||||
"flags" = NONE
|
||||
),
|
||||
"flags" = list(
|
||||
"WAVE_BOUNDED" = WAVE_BOUNDED
|
||||
)
|
||||
),
|
||||
"wave" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"size" = 1,
|
||||
"offset" = 0,
|
||||
"flags" = NONE
|
||||
),
|
||||
"flags" = list(
|
||||
"WAVE_SIDEWAYS" = WAVE_SIDEWAYS,
|
||||
"WAVE_BOUNDED" = WAVE_BOUNDED
|
||||
)
|
||||
)
|
||||
))
|
||||
|
||||
#undef ICON_NOT_SET
|
||||
|
||||
//Helpers to generate lists for filter helpers
|
||||
//This is the only practical way of writing these that actually produces sane lists
|
||||
/proc/alpha_mask_filter(x, y, icon/icon, render_source, flags)
|
||||
. = list("type" = "alpha")
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
if(!isnull(icon))
|
||||
.["icon"] = icon
|
||||
if(!isnull(render_source))
|
||||
.["render_source"] = render_source
|
||||
if(!isnull(flags))
|
||||
.["flags"] = flags
|
||||
|
||||
/proc/angular_blur_filter(x, y, size)
|
||||
. = list("type" = "angular_blur")
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
|
||||
/proc/color_matrix_filter(matrix/in_matrix, space)
|
||||
. = list("type" = "color")
|
||||
.["color"] = in_matrix
|
||||
if(!isnull(space))
|
||||
.["space"] = space
|
||||
|
||||
/proc/displacement_map_filter(icon, render_source, x, y, size = 32)
|
||||
. = list("type" = "displace")
|
||||
if(!isnull(icon))
|
||||
.["icon"] = icon
|
||||
if(!isnull(render_source))
|
||||
.["render_source"] = render_source
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
|
||||
/proc/drop_shadow_filter(x, y, size, offset, color)
|
||||
. = list("type" = "drop_shadow")
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
if(!isnull(offset))
|
||||
.["offset"] = offset
|
||||
if(!isnull(color))
|
||||
.["color"] = color
|
||||
|
||||
/proc/gauss_blur_filter(size)
|
||||
. = list("type" = "blur")
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
|
||||
/proc/layering_filter(icon, render_source, x, y, flags, color, transform, blend_mode)
|
||||
. = list("type" = "layer")
|
||||
if(!isnull(icon))
|
||||
.["icon"] = icon
|
||||
if(!isnull(render_source))
|
||||
.["render_source"] = render_source
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
if(!isnull(color))
|
||||
.["color"] = color
|
||||
if(!isnull(flags))
|
||||
.["flags"] = flags
|
||||
if(!isnull(transform))
|
||||
.["transform"] = transform
|
||||
if(!isnull(blend_mode))
|
||||
.["blend_mode"] = blend_mode
|
||||
|
||||
/proc/motion_blur_filter(x, y)
|
||||
. = list("type" = "motion_blur")
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
|
||||
/proc/outline_filter(size, color, flags)
|
||||
. = list("type" = "outline")
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
if(!isnull(color))
|
||||
.["color"] = color
|
||||
if(!isnull(flags))
|
||||
.["flags"] = flags
|
||||
|
||||
/proc/radial_blur_filter(size, x, y)
|
||||
. = list("type" = "radial_blur")
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
|
||||
/proc/rays_filter(size, color, offset, density, threshold, factor, x, y, flags)
|
||||
. = list("type" = "rays")
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
if(!isnull(color))
|
||||
.["color"] = color
|
||||
if(!isnull(offset))
|
||||
.["offset"] = offset
|
||||
if(!isnull(density))
|
||||
.["density"] = density
|
||||
if(!isnull(threshold))
|
||||
.["threshold"] = threshold
|
||||
if(!isnull(factor))
|
||||
.["factor"] = factor
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
if(!isnull(flags))
|
||||
.["flags"] = flags
|
||||
|
||||
/proc/ripple_filter(radius, size, falloff, repeat, x, y, flags)
|
||||
. = list("type" = "ripple")
|
||||
if(!isnull(radius))
|
||||
.["radius"] = radius
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
if(!isnull(falloff))
|
||||
.["falloff"] = falloff
|
||||
if(!isnull(repeat))
|
||||
.["repeat"] = repeat
|
||||
if(!isnull(flags))
|
||||
.["flags"] = flags
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
|
||||
/proc/wave_filter(x, y, size, offset, flags)
|
||||
. = list("type" = "wave")
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
if(!isnull(offset))
|
||||
.["offset"] = offset
|
||||
if(!isnull(flags))
|
||||
.["flags"] = flags
|
||||
|
||||
/proc/apply_wibbly_filters(atom/in_atom, length)
|
||||
for(var/i in 1 to 7)
|
||||
//This is a very baffling and strange way of doing this but I am just preserving old functionality
|
||||
var/X
|
||||
var/Y
|
||||
var/rsq
|
||||
do
|
||||
X = 60*rand() - 30
|
||||
Y = 60*rand() - 30
|
||||
rsq = X*X + Y*Y
|
||||
while(rsq<100 || rsq>900) // Yeah let's just loop infinitely due to bad luck what's the worst that could happen?
|
||||
var/random_roll = rand()
|
||||
in_atom.add_filter("wibbly-[i]", 5, wave_filter(x = X, y = Y, size = rand() * 2.5 + 0.5, offset = random_roll))
|
||||
var/filter = in_atom.get_filter("wibbly-[i]")
|
||||
animate(filter, offset = random_roll, time = 0, loop = -1, flags = ANIMATION_PARALLEL)
|
||||
animate(offset = random_roll - 1, time = rand() * 20 + 10)
|
||||
|
||||
/proc/remove_wibbly_filters(atom/in_atom)
|
||||
var/filter
|
||||
for(var/i in 1 to 7)
|
||||
filter = in_atom.get_filter("wibbly-[i]")
|
||||
animate(filter)
|
||||
in_atom.remove_filter("wibbly-[i]")
|
||||
@@ -26,18 +26,9 @@
|
||||
|
||||
/atom/movable/screen/plane_master/openspace/Initialize()
|
||||
. = ..()
|
||||
filters += filter(type = "drop_shadow", color = "#04080FAA", size = -10)
|
||||
filters += filter(type = "drop_shadow", color = "#04080FAA", size = -15)
|
||||
filters += filter(type = "drop_shadow", color = "#04080FAA", size = -20)
|
||||
|
||||
/atom/movable/screen/plane_master/proc/outline(_size, _color)
|
||||
filters += filter(type = "outline", size = _size, color = _color)
|
||||
|
||||
/atom/movable/screen/plane_master/proc/shadow(_size, _border, _offset = 0, _x = 0, _y = 0, _color = "#04080FAA")
|
||||
filters += filter(type = "drop_shadow", x = _x, y = _y, color = _color, size = _size, offset = _offset)
|
||||
|
||||
/atom/movable/screen/plane_master/proc/clear_filters()
|
||||
filters = list()
|
||||
add_filter("first_stage_openspace", 1, drop_shadow_filter(color = "#04080FAA", size = -10))
|
||||
add_filter("second_stage_openspace", 2, drop_shadow_filter(color = "#04080FAA", size = -15))
|
||||
add_filter("third_stage_openspace", 2, drop_shadow_filter(color = "#04080FAA", size = -20))
|
||||
|
||||
///Contains just the floor
|
||||
/atom/movable/screen/plane_master/floor
|
||||
@@ -47,9 +38,9 @@
|
||||
blend_mode = BLEND_OVERLAY
|
||||
|
||||
/atom/movable/screen/plane_master/floor/backdrop(mob/mymob)
|
||||
filters = list()
|
||||
clear_filters()
|
||||
if(istype(mymob) && mymob.eye_blurry)
|
||||
filters += GAUSSIAN_BLUR(clamp(mymob.eye_blurry*0.1,0.6,3))
|
||||
add_filter("eye_blur", 1, gauss_blur_filter(clamp(mymob.eye_blurry * 0.1, 0.6, 3)))
|
||||
|
||||
///Contains most things in the game world
|
||||
/atom/movable/screen/plane_master/game_world
|
||||
@@ -59,11 +50,11 @@
|
||||
blend_mode = BLEND_OVERLAY
|
||||
|
||||
/atom/movable/screen/plane_master/game_world/backdrop(mob/mymob)
|
||||
filters = list()
|
||||
clear_filters()
|
||||
if(istype(mymob) && mymob.client && mymob.client.prefs && mymob.client.prefs.ambientocclusion)
|
||||
filters += AMBIENT_OCCLUSION
|
||||
add_filter("AO", 1, drop_shadow_filter(x = 0, y = -2, size = 4, color = "#04080FAA"))
|
||||
if(istype(mymob) && mymob.eye_blurry)
|
||||
filters += GAUSSIAN_BLUR(clamp(mymob.eye_blurry*0.1,0.6,3))
|
||||
add_filter("eye_blur", 1, gauss_blur_filter(clamp(mymob.eye_blurry * 0.1, 0.6, 3)))
|
||||
|
||||
|
||||
///Contains all lighting objects
|
||||
@@ -79,9 +70,9 @@
|
||||
|
||||
/atom/movable/screen/plane_master/lighting/Initialize()
|
||||
. = ..()
|
||||
filters += filter(type="alpha", render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE)
|
||||
filters += filter(type="alpha", render_source = EMISSIVE_UNBLOCKABLE_RENDER_TARGET, flags = MASK_INVERSE)
|
||||
filters += filter(type="alpha", render_source = O_LIGHTING_VISUAL_RENDER_TARGET, flags = MASK_INVERSE)
|
||||
add_filter("emissives", 1, alpha_mask_filter(render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE))
|
||||
add_filter("unblockable_emissives", 2, alpha_mask_filter(render_source = EMISSIVE_UNBLOCKABLE_RENDER_TARGET, flags = MASK_INVERSE))
|
||||
add_filter("object_lighting", 3, alpha_mask_filter(render_source = O_LIGHTING_VISUAL_RENDER_TARGET, flags = MASK_INVERSE))
|
||||
|
||||
/**
|
||||
* Things placed on this mask the lighting plane. Doesn't render directly.
|
||||
@@ -97,7 +88,7 @@
|
||||
|
||||
/atom/movable/screen/plane_master/emissive/Initialize()
|
||||
. = ..()
|
||||
filters += filter(type="alpha", render_source=EMISSIVE_BLOCKER_RENDER_TARGET, flags=MASK_INVERSE)
|
||||
add_filter("emissive_block", 1, alpha_mask_filter(render_source = EMISSIVE_BLOCKER_RENDER_TARGET, flags = MASK_INVERSE))
|
||||
|
||||
/**
|
||||
* Things placed on this always mask the lighting plane. Doesn't render directly.
|
||||
@@ -163,4 +154,4 @@
|
||||
/atom/movable/screen/plane_master/runechat/backdrop(mob/mymob)
|
||||
filters = list()
|
||||
if(istype(mymob) && mymob.client?.prefs?.ambientocclusion)
|
||||
filters += AMBIENT_OCCLUSION
|
||||
add_filter("AO", 1, drop_shadow_filter(x = 0, y = -2, size = 4, color = "#04080FAA"))
|
||||
|
||||
+45
-7
@@ -1102,6 +1102,7 @@
|
||||
VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EMP, "EMP Pulse")
|
||||
VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EXPLOSION, "Explosion")
|
||||
VV_DROPDOWN_OPTION(VV_HK_RADIATE, "Radiate")
|
||||
VV_DROPDOWN_OPTION(VV_HK_EDIT_FILTERS, "Edit Filters")
|
||||
VV_DROPDOWN_OPTION(VV_HK_ADD_AI, "Add AI controller")
|
||||
|
||||
/atom/vv_do_topic(list/href_list)
|
||||
@@ -1181,6 +1182,10 @@
|
||||
if(newname && !(CHAT_FILTER_CHECK(newname) && alert(usr, "Your selected name contains words restricted by IC chat filters. Confirm this new name?", "IC Chat Filter Conflict", "Confirm", "Cancel") != "Confirm"))
|
||||
vv_auto_rename(newname)
|
||||
|
||||
if(href_list[VV_HK_EDIT_FILTERS] && check_rights(R_VAREDIT))
|
||||
var/client/C = usr.client
|
||||
C?.open_filter_editor(src)
|
||||
|
||||
/atom/vv_get_header()
|
||||
. = ..()
|
||||
var/refid = REF(src)
|
||||
@@ -1488,14 +1493,14 @@
|
||||
|
||||
victim.log_message(message, LOG_ATTACK, color="blue")
|
||||
|
||||
/atom/movable/proc/add_filter(name,priority,list/params)
|
||||
/atom/proc/add_filter(name,priority,list/params)
|
||||
LAZYINITLIST(filter_data)
|
||||
var/list/p = params.Copy()
|
||||
p["priority"] = priority
|
||||
filter_data[name] = p
|
||||
update_filters()
|
||||
|
||||
/atom/movable/proc/update_filters()
|
||||
/atom/proc/update_filters()
|
||||
filters = null
|
||||
filter_data = sortTim(filter_data, /proc/cmp_filter_data_priority, TRUE)
|
||||
for(var/f in filter_data)
|
||||
@@ -1503,6 +1508,29 @@
|
||||
var/list/arguments = data.Copy()
|
||||
arguments -= "priority"
|
||||
filters += filter(arglist(arguments))
|
||||
UNSETEMPTY(filter_data)
|
||||
|
||||
/atom/proc/transition_filter(name, time, list/new_params, easing, loop)
|
||||
var/filter = get_filter(name)
|
||||
if(!filter)
|
||||
return
|
||||
|
||||
var/list/old_filter_data = filter_data[name]
|
||||
|
||||
var/list/params = old_filter_data.Copy()
|
||||
for(var/thing in new_params)
|
||||
params[thing] = new_params[thing]
|
||||
|
||||
animate(filter, new_params, time = time, easing = easing, loop = loop)
|
||||
for(var/param in params)
|
||||
filter_data[name][param] = params[param]
|
||||
|
||||
/atom/proc/change_filter_priority(name, new_priority)
|
||||
if(!filter_data || !filter_data[name])
|
||||
return
|
||||
|
||||
filter_data[name]["priority"] = new_priority
|
||||
update_filters()
|
||||
|
||||
/obj/item/update_filters()
|
||||
. = ..()
|
||||
@@ -1510,14 +1538,24 @@
|
||||
var/datum/action/A = X
|
||||
A.UpdateButtonIcon()
|
||||
|
||||
/atom/movable/proc/get_filter(name)
|
||||
/atom/proc/get_filter(name)
|
||||
if(filter_data && filter_data[name])
|
||||
return filters[filter_data.Find(name)]
|
||||
|
||||
/atom/movable/proc/remove_filter(name)
|
||||
if(filter_data && filter_data[name])
|
||||
filter_data -= name
|
||||
update_filters()
|
||||
/atom/proc/remove_filter(name_or_names)
|
||||
if(!filter_data)
|
||||
return
|
||||
|
||||
var/list/names = islist(name_or_names) ? name_or_names : list(name_or_names)
|
||||
|
||||
for(var/name in names)
|
||||
if(filter_data[name])
|
||||
filter_data -= name
|
||||
update_filters()
|
||||
|
||||
/atom/proc/clear_filters()
|
||||
filter_data = null
|
||||
filters = null
|
||||
|
||||
/atom/proc/intercept_zImpact(atom/movable/AM, levels = 1)
|
||||
. |= SEND_SIGNAL(src, COMSIG_ATOM_INTERCEPT_Z_FALL, AM, levels)
|
||||
|
||||
@@ -426,8 +426,6 @@ Moving interrupts
|
||||
var/completion = 0
|
||||
/// Greyscaled target with cutout filter
|
||||
var/mutable_appearance/target_appearance_with_filters
|
||||
/// Cutout filter for main block sprite
|
||||
var/partial_uncover_filter
|
||||
/// HSV color filters parameters
|
||||
var/static/list/greyscale_with_value_bump = list(0,0,0, 0,0,0, 0,0,1, 0,0,-0.05)
|
||||
|
||||
@@ -490,20 +488,19 @@ Moving interrupts
|
||||
if(!target_appearance_with_filters)
|
||||
target_appearance_with_filters = new(current_target)
|
||||
target_appearance_with_filters.appearance_flags |= KEEP_TOGETHER
|
||||
//Doesn't use filter helpers because MAs aren't atoms
|
||||
target_appearance_with_filters.filters = filter(type="color",color=greyscale_with_value_bump,space=FILTER_COLOR_HSV)
|
||||
completion = value
|
||||
var/static/icon/white = icon('icons/effects/alphacolors.dmi', "white")
|
||||
switch(value)
|
||||
if(0)
|
||||
//delete uncovered and reset filters
|
||||
filters -= partial_uncover_filter
|
||||
remove_filter("partial_uncover")
|
||||
target_appearance_with_filters = null
|
||||
else
|
||||
var/mask_offset = min(world.icon_size,round(completion * world.icon_size))
|
||||
if(partial_uncover_filter)
|
||||
filters -= partial_uncover_filter
|
||||
partial_uncover_filter = filter(type="alpha",icon=white,y=-mask_offset)
|
||||
filters += partial_uncover_filter
|
||||
remove_filter("partial_uncover")
|
||||
add_filter("partial_uncover", 1, alpha_mask_filter(icon = white, y = -mask_offset))
|
||||
target_appearance_with_filters.filters = filter(type="alpha",icon=white,y=-mask_offset,flags=MASK_INVERSE)
|
||||
update_icon()
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ GLOBAL_PROTECT(href_token)
|
||||
|
||||
var/deadmined
|
||||
|
||||
var/datum/filter_editor/filteriffic
|
||||
|
||||
/datum/admins/New(datum/admin_rank/R, ckey, force_active = FALSE, protected)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/datum/filter_editor
|
||||
var/atom/target
|
||||
|
||||
/datum/filter_editor/New(atom/target)
|
||||
src.target = target
|
||||
|
||||
/datum/filter_editor/ui_state(mob/user)
|
||||
return GLOB.admin_state
|
||||
|
||||
/datum/filter_editor/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Filteriffic")
|
||||
ui.open()
|
||||
|
||||
/datum/filter_editor/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["filter_info"] = GLOB.master_filter_info
|
||||
return data
|
||||
|
||||
/datum/filter_editor/ui_data()
|
||||
var/list/data = list()
|
||||
data["target_name"] = target.name
|
||||
data["target_filter_data"] = target.filter_data
|
||||
return data
|
||||
|
||||
/datum/filter_editor/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("add_filter")
|
||||
var/target_name = params["name"]
|
||||
while(target.filter_data && target.filter_data[target_name])
|
||||
target_name = "[target_name]-dupe"
|
||||
target.add_filter(target_name, params["priority"], list("type" = params["type"]))
|
||||
. = TRUE
|
||||
if("remove_filter")
|
||||
target.remove_filter(params["name"])
|
||||
. = TRUE
|
||||
if("rename_filter")
|
||||
var/list/filter_data = target.filter_data[params["name"]]
|
||||
target.remove_filter(params["name"])
|
||||
target.add_filter(params["new_name"], filter_data["priority"], filter_data)
|
||||
. = TRUE
|
||||
if("edit_filter")
|
||||
target.remove_filter(params["name"])
|
||||
target.add_filter(params["name"], params["priority"], params["new_filter"])
|
||||
. = TRUE
|
||||
if("change_priority")
|
||||
var/new_priority = params["new_priority"]
|
||||
target.change_filter_priority(params["name"], new_priority)
|
||||
. = TRUE
|
||||
if("transition_filter_value")
|
||||
target.transition_filter(params["name"], 4, params["new_data"])
|
||||
. = TRUE
|
||||
if("modify_filter_value")
|
||||
var/list/old_filter_data = target.filter_data[params["name"]]
|
||||
var/list/new_filter_data = old_filter_data.Copy()
|
||||
for(var/entry in params["new_data"])
|
||||
new_filter_data[entry] = params["new_data"][entry]
|
||||
for(var/entry in new_filter_data)
|
||||
if(entry == GLOB.master_filter_info[old_filter_data["type"]]["defaults"][entry])
|
||||
new_filter_data.Remove(entry)
|
||||
target.remove_filter(params["name"])
|
||||
target.add_filter(params["name"], old_filter_data["priority"], new_filter_data)
|
||||
. = TRUE
|
||||
if("modify_color_value")
|
||||
var/new_color = input(usr, "Pick new filter color", "Filteriffic Colors!") as color|null
|
||||
if(new_color)
|
||||
target.transition_filter(params["name"], 4, list("color" = new_color))
|
||||
. = TRUE
|
||||
if("modify_icon_value")
|
||||
var/icon/new_icon = input("Pick icon:", "Icon") as null|icon
|
||||
if(new_icon)
|
||||
target.filter_data[params["name"]]["icon"] = new_icon
|
||||
target.update_filters()
|
||||
. = TRUE
|
||||
if("mass_apply")
|
||||
if(!check_rights_for(usr.client, R_FUN))
|
||||
to_chat(usr, "<span class='userdanger>Stay in your lane, jannie.</span>'")
|
||||
return
|
||||
var/target_path = text2path(params["path"])
|
||||
if(!target_path)
|
||||
return
|
||||
var/filters_to_copy = target.filters
|
||||
var/filter_data_to_copy = target.filter_data
|
||||
var/count = 0
|
||||
for(var/thing in world.contents)
|
||||
if(istype(thing, target_path))
|
||||
var/atom/thing_at = thing
|
||||
thing_at.filters = filters_to_copy
|
||||
thing_at.filter_data = filter_data_to_copy
|
||||
count += 1
|
||||
message_admins("LOCAL CLOWN [usr.ckey] JUST MASS FILTER EDITED [count] WITH PATH OF [params["path"]]!")
|
||||
log_admin("LOCAL CLOWN [usr.ckey] JUST MASS FILTER EDITED [count] WITH PATH OF [params["path"]]!")
|
||||
|
||||
|
||||
@@ -64,19 +64,7 @@
|
||||
animation_playing = TRUE
|
||||
to_chat(user, "<span class='notice'>You activate \the [src].</span>")
|
||||
playsound(src, 'sound/effects/seedling_chargeup.ogg', 100, TRUE, -6)
|
||||
var/start = user.filters.len
|
||||
var/X,Y,rsq,i,f
|
||||
for(i=1, i<=7, ++i)
|
||||
do
|
||||
X = 60*rand() - 30
|
||||
Y = 60*rand() - 30
|
||||
rsq = X*X + Y*Y
|
||||
while(rsq<100 || rsq>900)
|
||||
user.filters += filter(type="wave", x=X, y=Y, size=rand()*2.5+0.5, offset=rand())
|
||||
for(i=1, i<=7, ++i)
|
||||
f = user.filters[start+i]
|
||||
animate(f, offset=f:offset, time=0, loop=3, flags=ANIMATION_PARALLEL)
|
||||
animate(offset=f:offset-1, time=rand()*20+10)
|
||||
apply_wibbly_filters(user)
|
||||
if (do_after(user, 50, target=user) && user.cell.use(activationCost))
|
||||
playsound(src, 'sound/effects/bamf.ogg', 100, TRUE, -6)
|
||||
to_chat(user, "<span class='notice'>You are now disguised as the Nanotrasen engineering borg \"[friendlyName]\".</span>")
|
||||
@@ -84,10 +72,7 @@
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The chameleon field fizzles.</span>")
|
||||
do_sparks(3, FALSE, user)
|
||||
for(i=1, i<=min(7, user.filters.len), ++i) // removing filters that are animating does nothing, we gotta stop the animations first
|
||||
f = user.filters[start+i]
|
||||
animate(f)
|
||||
user.filters = null
|
||||
remove_wibbly_filters(user)
|
||||
animation_playing = FALSE
|
||||
|
||||
/obj/item/borg_chameleon/process()
|
||||
|
||||
@@ -617,7 +617,7 @@
|
||||
smoke_effects[i] = smoke_part
|
||||
smoke_part.pixel_x = sin(rotation)*32 * i
|
||||
smoke_part.pixel_y = abs(cos(rotation))*32 * i
|
||||
smoke_part.filters += filter(type = "blur", size = 4)
|
||||
smoke_part.add_filter("smoke_blur", 1, gauss_blur_filter(size = 4))
|
||||
var/time = (pod.delays[POD_FALLING] / length(smoke_effects))*(length(smoke_effects)-i)
|
||||
addtimer(CALLBACK(smoke_part, /obj/effect/supplypod_smoke/.proc/drawSelf, i), time, TIMER_CLIENT_TIME) //Go onto the last step after a very short falling animation
|
||||
QDEL_IN(smoke_part, pod.delays[POD_FALLING] + 35)
|
||||
@@ -627,7 +627,7 @@
|
||||
return
|
||||
for (var/obj/effect/supplypod_smoke/smoke_part in smoke_effects)
|
||||
animate(smoke_part, alpha = 0, time = 20, flags = ANIMATION_PARALLEL)
|
||||
animate(smoke_part.filters[1], size = 6, time = 15, easing = CUBIC_EASING|EASE_OUT, flags = ANIMATION_PARALLEL)
|
||||
animate(smoke_part.get_filter("smoke_blur"), size = 6, time = 15, easing = CUBIC_EASING|EASE_OUT, flags = ANIMATION_PARALLEL)
|
||||
|
||||
/obj/effect/pod_landingzone/proc/endLaunch()
|
||||
pod.tryMakeRubble(drop_location())
|
||||
|
||||
@@ -1080,3 +1080,8 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
var/datum/verbs/menu/menuitem = GLOB.menulist[thing]
|
||||
if (menuitem)
|
||||
menuitem.Load_checked(src)
|
||||
|
||||
/client/proc/open_filter_editor(atom/in_atom)
|
||||
if(holder)
|
||||
holder.filteriffic = new /datum/filter_editor(in_atom)
|
||||
holder.filteriffic.ui_interact(mob)
|
||||
|
||||
@@ -610,8 +610,8 @@
|
||||
if(mob_mask.Height() > world.icon_size || mob_mask.Width() > world.icon_size)
|
||||
var/health_doll_icon_state = health_doll_icon ? health_doll_icon : "megasprite"
|
||||
mob_mask = icon('icons/hud/screen_gen.dmi', health_doll_icon_state) //swap to something generic if they have no special doll
|
||||
livingdoll.filters += filter(type="alpha", icon = mob_mask)
|
||||
livingdoll.filters += filter(type="drop_shadow", size = -1)
|
||||
livingdoll.add_filter("mob_shape_mask", 1, alpha_mask_filter(icon = mob_mask))
|
||||
livingdoll.add_filter("inset_drop_shadow", 2, drop_shadow_filter(size = -1))
|
||||
if(severity > 0)
|
||||
overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity)
|
||||
else
|
||||
|
||||
@@ -148,6 +148,7 @@
|
||||
#include "code\__HELPERS\dates.dm"
|
||||
#include "code\__HELPERS\dna.dm"
|
||||
#include "code\__HELPERS\files.dm"
|
||||
#include "code\__HELPERS\filters.dm"
|
||||
#include "code\__HELPERS\game.dm"
|
||||
#include "code\__HELPERS\global_lists.dm"
|
||||
#include "code\__HELPERS\heap.dm"
|
||||
@@ -1450,6 +1451,7 @@
|
||||
#include "code\modules\admin\verbs\SDQL2\SDQL_2_wrappers.dm"
|
||||
#include "code\modules\admin\view_variables\admin_delete.dm"
|
||||
#include "code\modules\admin\view_variables\debug_variables.dm"
|
||||
#include "code\modules\admin\view_variables\filterrific.dm"
|
||||
#include "code\modules\admin\view_variables\get_variables.dm"
|
||||
#include "code\modules\admin\view_variables\mark_datum.dm"
|
||||
#include "code\modules\admin\view_variables\mass_edit_variables.dm"
|
||||
|
||||
@@ -361,12 +361,16 @@ and displays selected entry.
|
||||
**Props:**
|
||||
|
||||
- See inherited props: [Box](#box)
|
||||
- See inherited props: [Icon](#icon)
|
||||
- `options: string[]` - An array of strings which will be displayed in the
|
||||
dropdown when open
|
||||
- `selected: string` - Currently selected entry
|
||||
- `width: number` - Width of dropdown button and resulting menu
|
||||
- `over: boolean` - dropdown renders over instead of below
|
||||
- `color: string` - color of dropdown button
|
||||
- `over: boolean` - Dropdown renders over instead of below
|
||||
- `color: string` - Color of dropdown button
|
||||
- `nochevron: boolean` - Whether or not the arrow on the right hand side of the dropdown button is visible
|
||||
- `noscroll: boolean` - Whether or not the dropdown menu should have a scroll bar
|
||||
- `displayText: string` - Text to always display in place of the selected text
|
||||
- `onClick: (e) => void` - Called when dropdown button is clicked
|
||||
- `onSelected: (value) => void` - Called when a value is picked from the list, `value` is the value that was picked
|
||||
|
||||
|
||||
@@ -88,3 +88,13 @@ export const keyOfMatchingRange = (value, ranges) => {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get number of digits following the decimal point in a number
|
||||
*/
|
||||
export const numberOfDecimalDigits = value => {
|
||||
if (Math.floor(value) !== value) {
|
||||
return value.toString().split('.')[1].length || 0;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -64,6 +64,9 @@ export class Dropdown extends Component {
|
||||
render() {
|
||||
const { props } = this;
|
||||
const {
|
||||
icon,
|
||||
iconRotation,
|
||||
iconSpin,
|
||||
color = 'default',
|
||||
over,
|
||||
noscroll,
|
||||
@@ -72,6 +75,7 @@ export class Dropdown extends Component {
|
||||
onClick,
|
||||
selected,
|
||||
disabled,
|
||||
displayText,
|
||||
...boxProps
|
||||
} = props;
|
||||
const {
|
||||
@@ -114,8 +118,15 @@ export class Dropdown extends Component {
|
||||
}
|
||||
this.setOpen(!this.state.open);
|
||||
}}>
|
||||
{icon && (
|
||||
<Icon
|
||||
name={icon}
|
||||
rotation={iconRotation}
|
||||
spin={iconSpin}
|
||||
mr={1} />
|
||||
)}
|
||||
<span className="Dropdown__selected-text">
|
||||
{this.state.selected}
|
||||
{displayText ? displayText : this.state.selected}
|
||||
</span>
|
||||
{!!nochevron || (
|
||||
<span className="Dropdown__arrow-button">
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
import { useBackend, useLocalState } from "../backend";
|
||||
import { Fragment } from 'inferno';
|
||||
import { Box, Button, Collapsible, ColorBox, Dropdown, Input, LabeledList, NoticeBox, NumberInput, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { map } from 'common/collections';
|
||||
import { toFixed } from 'common/math';
|
||||
import { numberOfDecimalDigits } from "../../common/math";
|
||||
|
||||
const FilterIntegerEntry = (props, context) => {
|
||||
const { value, name, filterName } = props;
|
||||
const { act } = useBackend(context);
|
||||
return (
|
||||
<NumberInput
|
||||
value={value}
|
||||
minValue={-500}
|
||||
maxValue={500}
|
||||
stepPixelSize={5}
|
||||
width="39px"
|
||||
onDrag={(e, value) => act('modify_filter_value', {
|
||||
name: filterName,
|
||||
new_data: {
|
||||
[name]: value,
|
||||
},
|
||||
})} />
|
||||
);
|
||||
};
|
||||
|
||||
const FilterFloatEntry = (props, context) => {
|
||||
const { value, name, filterName } = props;
|
||||
const { act } = useBackend(context);
|
||||
const [step, setStep] = useLocalState(context, `${filterName}-${name}`, 0.01);
|
||||
return (
|
||||
<Fragment>
|
||||
<NumberInput
|
||||
value={value}
|
||||
minValue={-500}
|
||||
maxValue={500}
|
||||
stepPixelSize={4}
|
||||
step={step}
|
||||
format={value => toFixed(value, numberOfDecimalDigits(step))}
|
||||
width="80px"
|
||||
onDrag={(e, value) => act('transition_filter_value', {
|
||||
name: filterName,
|
||||
new_data: {
|
||||
[name]: value,
|
||||
},
|
||||
})} />
|
||||
<Box
|
||||
inline
|
||||
ml={2}
|
||||
mr={1}>
|
||||
Step:
|
||||
</Box>
|
||||
<NumberInput
|
||||
value={step}
|
||||
step={0.001}
|
||||
format={value => toFixed(value, 4)}
|
||||
width="70px"
|
||||
onChange={(e, value) => setStep(value)} />
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const FilterTextEntry = (props, context) => {
|
||||
const { value, name, filterName } = props;
|
||||
const { act } = useBackend(context);
|
||||
|
||||
return (
|
||||
<Input
|
||||
value={value}
|
||||
width="250px"
|
||||
onInput={(e, value) => act('modify_filter_value', {
|
||||
name: filterName,
|
||||
new_data: {
|
||||
[name]: value,
|
||||
},
|
||||
})} />
|
||||
);
|
||||
};
|
||||
|
||||
const FilterColorEntry = (props, context) => {
|
||||
const { value, filterName, name } = props;
|
||||
const { act } = useBackend(context);
|
||||
return (
|
||||
<Fragment>
|
||||
<Button
|
||||
icon="pencil-alt"
|
||||
onClick={() => act('modify_color_value', {
|
||||
name: filterName,
|
||||
})} />
|
||||
<ColorBox
|
||||
color={value}
|
||||
mr={0.5} />
|
||||
<Input
|
||||
value={value}
|
||||
width="90px"
|
||||
onInput={(e, value) => act('transition_filter_value', {
|
||||
name: filterName,
|
||||
new_data: {
|
||||
[name]: value,
|
||||
},
|
||||
})} />
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const FilterIconEntry = (props, context) => {
|
||||
const { value, filterName } = props;
|
||||
const { act } = useBackend(context);
|
||||
return (
|
||||
<Fragment>
|
||||
<Button
|
||||
icon="pencil-alt"
|
||||
onClick={() => act('modify_icon_value', {
|
||||
name: filterName,
|
||||
})} />
|
||||
<Box inline ml={1}>
|
||||
{value}
|
||||
</Box>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const FilterFlagsEntry = (props, context) => {
|
||||
const { name, value, filterName, filterType } = props;
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const filterInfo = data.filter_info;
|
||||
const flags = filterInfo[filterType]['flags'];
|
||||
return (
|
||||
map((bitField, flagName) => (
|
||||
<Button.Checkbox
|
||||
checked={value & bitField}
|
||||
content={flagName}
|
||||
onClick={() => act('modify_filter_value', {
|
||||
name: filterName,
|
||||
new_data: {
|
||||
[name]: value ^ bitField,
|
||||
},
|
||||
})} />
|
||||
))(flags)
|
||||
);
|
||||
};
|
||||
|
||||
const FilterDataEntry = (props, context) => {
|
||||
const { name, value, hasValue, filterName } = props;
|
||||
|
||||
const filterEntryTypes = {
|
||||
int: <FilterIntegerEntry {...props} />,
|
||||
float: <FilterFloatEntry {...props} />,
|
||||
string: <FilterTextEntry {...props} />,
|
||||
color: <FilterColorEntry {...props} />,
|
||||
icon: <FilterIconEntry {...props} />,
|
||||
flags: <FilterFlagsEntry {...props} />,
|
||||
};
|
||||
|
||||
const filterEntryMap = {
|
||||
x: 'float',
|
||||
y: 'float',
|
||||
icon: 'icon',
|
||||
render_source: 'string',
|
||||
flags: 'flags',
|
||||
size: 'float',
|
||||
color: 'color',
|
||||
offset: 'float',
|
||||
radius: 'float',
|
||||
falloff: 'float',
|
||||
density: 'int',
|
||||
threshold: 'float',
|
||||
factor: 'float',
|
||||
repeat: 'int',
|
||||
};
|
||||
|
||||
return (
|
||||
<LabeledList.Item label={name}>
|
||||
{filterEntryTypes[filterEntryMap[name]] || "Not Found (This is an error)"}
|
||||
{' '}
|
||||
{!hasValue && <Box inline color="average">(Default)</Box>}
|
||||
</LabeledList.Item>
|
||||
);
|
||||
};
|
||||
|
||||
const FilterEntry = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const { name, filterDataEntry } = props;
|
||||
const { type, priority, ...restOfProps } = filterDataEntry;
|
||||
|
||||
const filterDefaults = data["filter_info"];
|
||||
|
||||
const targetFilterPossibleKeys = Object.keys(filterDefaults[type]['defaults']);
|
||||
|
||||
return (
|
||||
<Collapsible
|
||||
title={name + " (" + type + ")"}
|
||||
buttons={(
|
||||
<Fragment>
|
||||
<NumberInput
|
||||
value={priority}
|
||||
stepPixelSize={10}
|
||||
width="60px"
|
||||
onChange={(e, value) => act('change_priority', {
|
||||
name: name,
|
||||
new_priority: value,
|
||||
})}
|
||||
/>
|
||||
<Button.Input
|
||||
content="Rename"
|
||||
placeholder={name}
|
||||
onCommit={(e, new_name) => act('rename_filter', {
|
||||
name: name,
|
||||
new_name: new_name,
|
||||
})}
|
||||
width="90px" />
|
||||
<Button.Confirm
|
||||
icon="minus"
|
||||
onClick={() => act("remove_filter", { name: name })} />
|
||||
</Fragment>
|
||||
)}>
|
||||
<Section level={2}>
|
||||
<LabeledList>
|
||||
{targetFilterPossibleKeys.map(entryName => {
|
||||
const defaults = filterDefaults[type]['defaults'];
|
||||
const value = restOfProps[entryName] || defaults[entryName];
|
||||
const hasValue = value !== defaults[entryName];
|
||||
return (
|
||||
<FilterDataEntry
|
||||
key={entryName}
|
||||
filterName={name}
|
||||
filterType={type}
|
||||
name={entryName}
|
||||
value={value}
|
||||
hasValue={hasValue} />
|
||||
);
|
||||
})}
|
||||
</LabeledList>
|
||||
</Section>
|
||||
</Collapsible>
|
||||
);
|
||||
};
|
||||
|
||||
export const Filteriffic = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const name = data.target_name || "Unknown Object";
|
||||
const filters = data.target_filter_data || {};
|
||||
const hasFilters = filters !== {};
|
||||
const filterDefaults = data["filter_info"];
|
||||
const [massApplyPath, setMassApplyPath] = useLocalState(context, 'massApplyPath', '');
|
||||
const [hiddenSecret, setHiddenSecret] = useLocalState(context, 'hidden', false);
|
||||
return (
|
||||
<Window
|
||||
width={500}
|
||||
height={500}
|
||||
title="Filteriffic"
|
||||
resizable>
|
||||
<Window.Content scrollable>
|
||||
<NoticeBox danger>
|
||||
DO NOT MESS WITH EXISTING FILTERS IF YOU DO NOT KNOW THE CONSEQUENCES.
|
||||
YOU HAVE BEEN WARNED.
|
||||
</NoticeBox>
|
||||
<Section
|
||||
title={hiddenSecret ? (
|
||||
<Fragment>
|
||||
<Box mr={0.5} inline>
|
||||
MASS EDIT:
|
||||
</Box>
|
||||
<Input
|
||||
value={massApplyPath}
|
||||
width="100px"
|
||||
onInput={(e, value) => setMassApplyPath(value)} />
|
||||
<Button.Confirm
|
||||
content="Apply"
|
||||
confirmContent="ARE YOU SURE?"
|
||||
onClick={() => act('mass_apply', { path: massApplyPath })} />
|
||||
</Fragment>
|
||||
) : (
|
||||
<Box
|
||||
inline
|
||||
onDblClick={() => setHiddenSecret(true)}>
|
||||
{name}
|
||||
</Box>
|
||||
)}
|
||||
buttons={(
|
||||
<Dropdown
|
||||
icon="plus"
|
||||
displayText="Add Filter"
|
||||
nochevron
|
||||
options={Object.keys(filterDefaults)}
|
||||
onSelected={value => act('add_filter', {
|
||||
name: 'default',
|
||||
priority: 10,
|
||||
type: value,
|
||||
})} />
|
||||
)} >
|
||||
{!hasFilters ? (
|
||||
<Box>
|
||||
No filters
|
||||
</Box>
|
||||
) : (
|
||||
map((entry, key) => (
|
||||
<FilterEntry filterDataEntry={entry} name={key} key={key} />
|
||||
))(filters)
|
||||
)}
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user