mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-29 08:08:49 +01:00
[MIRROR] GAGS fix + debug improvements I needed to find it (#8219)
* GAGS fix + debug improvements I needed to find it * Feex Co-authored-by: Emmett Gaines <ninjanomnom@protonmail.com> Co-authored-by: GoldenAlpharex <jerego1234@hotmail.com>
This commit is contained in:
co-authored by
Emmett Gaines
GoldenAlpharex
parent
6caab7f61c
commit
95ac28a6b0
@@ -1477,3 +1477,4 @@
|
||||
///Called when the ticker sets up the game for start
|
||||
#define COMSIG_TICKER_ENTER_SETTING_UP "comsig_ticker_enter_setting_up"
|
||||
|
||||
#define COMSIG_GREYSCALE_CONFIG_REFRESHED "greyscale_config_refreshed"
|
||||
|
||||
+7
-6
@@ -1,12 +1,13 @@
|
||||
SUBSYSTEM_DEF(greyscale)
|
||||
PROCESSING_SUBSYSTEM_DEF(greyscale)
|
||||
name = "Greyscale"
|
||||
flags = SS_NO_FIRE
|
||||
flags = SS_BACKGROUND
|
||||
init_order = INIT_ORDER_GREYSCALE
|
||||
wait = 3 SECONDS
|
||||
|
||||
var/list/datum/greyscale_config/configurations = list()
|
||||
var/list/datum/greyscale_layer/layer_types = list()
|
||||
|
||||
/datum/controller/subsystem/greyscale/Initialize(start_timeofday)
|
||||
/datum/controller/subsystem/processing/greyscale/Initialize(start_timeofday)
|
||||
for(var/datum/greyscale_layer/fake_type as anything in subtypesof(/datum/greyscale_layer))
|
||||
layer_types[initial(fake_type.layer_type)] = fake_type
|
||||
|
||||
@@ -28,11 +29,11 @@ SUBSYSTEM_DEF(greyscale)
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/greyscale/proc/RefreshConfigsFromFile()
|
||||
/datum/controller/subsystem/processing/greyscale/proc/RefreshConfigsFromFile()
|
||||
for(var/i in configurations)
|
||||
configurations[i].Refresh(TRUE)
|
||||
|
||||
/datum/controller/subsystem/greyscale/proc/GetColoredIconByType(type, list/colors)
|
||||
/datum/controller/subsystem/processing/greyscale/proc/GetColoredIconByType(type, list/colors)
|
||||
if(!ispath(type, /datum/greyscale_config))
|
||||
CRASH("An invalid greyscale configuration was given to `GetColoredIconByType()`: [type]")
|
||||
type = "[type]"
|
||||
@@ -42,7 +43,7 @@ SUBSYSTEM_DEF(greyscale)
|
||||
CRASH("Invalid colors were given to `GetColoredIconByType()`: [colors]")
|
||||
return configurations[type].Generate(colors)
|
||||
|
||||
/datum/controller/subsystem/greyscale/proc/ParseColorString(color_string)
|
||||
/datum/controller/subsystem/processing/greyscale/proc/ParseColorString(color_string)
|
||||
. = list()
|
||||
var/list/split_colors = splittext(color_string, "#")
|
||||
for(var/color in 2 to length(split_colors))
|
||||
@@ -27,12 +27,24 @@
|
||||
/// String path to the json file, used for reloading
|
||||
var/string_json_config
|
||||
|
||||
/// The md5 file hash for the json configuration. Used to check if the file has changed
|
||||
var/json_config_hash
|
||||
|
||||
/// String path to the icon file, used for reloading
|
||||
var/string_icon_file
|
||||
|
||||
/// The md5 file hash for the icon file. Used to check if the file has changed
|
||||
var/icon_file_hash
|
||||
|
||||
/// A list of icon states and their layers
|
||||
var/list/icon_states
|
||||
|
||||
/// A list of all layers irrespective of nesting
|
||||
var/list/flat_all_layers
|
||||
|
||||
/// A list of types to update in the world whenever a config changes
|
||||
var/list/live_edit_types
|
||||
|
||||
/// How many colors are expected to be given when building the sprite
|
||||
var/expected_colors = 0
|
||||
|
||||
@@ -51,11 +63,63 @@
|
||||
if(!name)
|
||||
stack_trace("Greyscale config object [DebugName()] is missing a name, make sure `name` has been assigned a value.")
|
||||
|
||||
/datum/greyscale_config/Destroy(force, ...)
|
||||
if(!force)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
return ..()
|
||||
|
||||
/datum/greyscale_config/process(delta_time)
|
||||
if(!Refresh(loadFromDisk=TRUE))
|
||||
return
|
||||
if(!live_edit_types)
|
||||
return
|
||||
for(var/atom/thing in world)
|
||||
if(live_edit_types[thing.type])
|
||||
thing.update_greyscale()
|
||||
|
||||
/datum/greyscale_config/proc/EnableAutoRefresh(live_type)
|
||||
message_admins("Config auto refresh has been enabled for '[live_type]' with configuration [DebugName()]. Expect heavy lag.")
|
||||
if(live_type)
|
||||
if(!live_edit_types)
|
||||
live_edit_types = list()
|
||||
live_edit_types += typecacheof(live_type)
|
||||
START_PROCESSING(SSgreyscale, src)
|
||||
|
||||
/datum/greyscale_config/proc/DisableAutoRefresh(live_type, remove_all=FALSE)
|
||||
if(!remove_all && !(live_type in live_edit_types))
|
||||
return
|
||||
message_admins("Config auto refresh has been disabled for '[live_type]' with configuration [DebugName()]")
|
||||
if(remove_all)
|
||||
live_edit_types = null
|
||||
else if(live_type && live_edit_types)
|
||||
live_edit_types -= typecacheof(live_type)
|
||||
if(!length(live_edit_types))
|
||||
live_edit_types = null
|
||||
STOP_PROCESSING(SSgreyscale, src)
|
||||
|
||||
/// Call this proc to handle all the data extraction from the json configuration. Can be forced to load values from disk instead of memory.
|
||||
/datum/greyscale_config/proc/Refresh(loadFromDisk=FALSE)
|
||||
if(loadFromDisk)
|
||||
var/changed = FALSE
|
||||
|
||||
json_config = file(string_json_config)
|
||||
var/json_hash = md5asfile(json_config)
|
||||
if(json_config_hash != json_hash)
|
||||
json_config_hash = json_hash
|
||||
changed = TRUE
|
||||
|
||||
icon_file = file(string_icon_file)
|
||||
var/icon_hash = md5asfile(icon_file)
|
||||
if(icon_file_hash != icon_hash)
|
||||
icon_file_hash = icon_hash
|
||||
changed = TRUE
|
||||
|
||||
for(var/datum/greyscale_layer/layer as anything in flat_all_layers)
|
||||
if(layer.DiskRefresh())
|
||||
changed = TRUE
|
||||
|
||||
if(!changed)
|
||||
return FALSE
|
||||
|
||||
var/list/raw = json_decode(file2text(json_config))
|
||||
ReadIconStateConfiguration(raw)
|
||||
@@ -67,6 +131,10 @@
|
||||
|
||||
ReadMetadata()
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_GREYSCALE_CONFIG_REFRESHED)
|
||||
|
||||
return TRUE
|
||||
|
||||
/// Called after every config has refreshed, this proc handles data verification that depends on multiple entwined configurations.
|
||||
/datum/greyscale_config/proc/CrossVerify()
|
||||
for(var/icon_state in icon_states)
|
||||
@@ -139,9 +207,11 @@
|
||||
if(length(state_layers) > MAX_SANE_LAYERS)
|
||||
stack_trace("[DebugName()] icon state '[state]' has [length(state_layers)] layers which is larger than the max of [MAX_SANE_LAYERS].")
|
||||
|
||||
flat_all_layers = list()
|
||||
var/list/color_groups = list()
|
||||
var/largest_id = 0
|
||||
for(var/datum/greyscale_layer/layer as anything in all_layers)
|
||||
flat_all_layers += layer
|
||||
for(var/id in layer.color_ids)
|
||||
if(!isnum(id))
|
||||
continue
|
||||
@@ -155,6 +225,11 @@
|
||||
|
||||
expected_colors = length(color_groups)
|
||||
|
||||
/// For saving a dmi to disk, useful for debug mainly
|
||||
/datum/greyscale_config/proc/SaveOutput(color_string)
|
||||
var/icon/icon_output = GenerateBundle(color_string)
|
||||
fcopy(icon_output, "tmp/gags_debug_output.dmi")
|
||||
|
||||
/// Actually create the icon and color it in, handles caching
|
||||
/datum/greyscale_config/proc/Generate(color_string)
|
||||
var/key = color_string
|
||||
@@ -163,13 +238,7 @@
|
||||
return icon(new_icon)
|
||||
|
||||
var/icon/icon_bundle = GenerateBundle(color_string)
|
||||
|
||||
// This block is done like this because generated icons are unable to be scaled before getting added to the rsc
|
||||
icon_bundle = fcopy_rsc(icon_bundle)
|
||||
icon_bundle = icon(icon_bundle)
|
||||
icon_bundle.Scale(width, height)
|
||||
icon_bundle = fcopy_rsc(icon_bundle)
|
||||
|
||||
icon_cache[key] = icon_bundle
|
||||
var/icon/output = icon(icon_bundle)
|
||||
return output
|
||||
@@ -183,13 +252,19 @@
|
||||
|
||||
var/list/generated_icons = list()
|
||||
for(var/icon_state in icon_states)
|
||||
var/icon/generated_icon = GenerateLayerGroup(colors, icon_states[icon_state], render_steps)
|
||||
var/list/icon_state_steps
|
||||
if(render_steps)
|
||||
icon_state_steps = render_steps[icon_state] = list()
|
||||
var/icon/generated_icon = GenerateLayerGroup(colors, icon_states[icon_state], icon_state_steps)
|
||||
// We read a pixel to force the icon to be fully generated before we let it loose into the world
|
||||
// I hate this
|
||||
generated_icon.GetPixel(1, 1)
|
||||
generated_icons[icon_state] = generated_icon
|
||||
|
||||
var/icon/icon_bundle = icon('icons/testing/greyscale_error.dmi')
|
||||
var/icon/icon_bundle = generated_icons[""] || icon('icons/testing/greyscale_error.dmi')
|
||||
icon_bundle.Scale(width, height)
|
||||
generated_icons -= ""
|
||||
|
||||
for(var/icon_state in generated_icons)
|
||||
icon_bundle.Insert(generated_icons[icon_state], icon_state)
|
||||
|
||||
@@ -214,8 +289,9 @@
|
||||
// These are so we can see the result of every step of the process in the preview ui
|
||||
if(render_steps)
|
||||
var/list/icon_data = list()
|
||||
render_steps[icon(layer_icon)] = icon_data
|
||||
render_steps += list(icon_data)
|
||||
icon_data["config_name"] = name
|
||||
icon_data["step"] = icon(layer_icon)
|
||||
icon_data["result"] = icon(new_icon)
|
||||
return new_icon
|
||||
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
/datum/greyscale_layer/proc/Initialize(icon_file)
|
||||
return
|
||||
|
||||
/// Override this if you need to do something during a full config refresh from disk, return TRUE if something was changed
|
||||
/datum/greyscale_layer/proc/DiskRefresh()
|
||||
return FALSE
|
||||
|
||||
/// Handles the processing of the json data and conversion to correct value types.
|
||||
/// Will error on incorrect, missing, or unexpected values.
|
||||
/datum/greyscale_layer/proc/ReadJsonData(list/json_data)
|
||||
@@ -117,13 +121,21 @@
|
||||
optional_values[NAMEOF(src, icon_state)] = /datum/json_reader/text
|
||||
required_values[NAMEOF(src, reference_type)] = /datum/json_reader/greyscale_config
|
||||
|
||||
/datum/greyscale_layer/reference/DiskRefresh()
|
||||
. = ..()
|
||||
return reference_type.Refresh(loadFromDisk=TRUE)
|
||||
|
||||
/datum/greyscale_layer/reference/CrossVerify()
|
||||
. = ..()
|
||||
if(!reference_type.icon_states[icon_state])
|
||||
CRASH("[src] expects icon_state '[icon_state]' but referenced configuration '[reference_type]' does not have it.")
|
||||
|
||||
/datum/greyscale_layer/reference/InternalGenerate(list/colors, list/render_steps)
|
||||
var/icon/generated_icon
|
||||
if(render_steps)
|
||||
return reference_type.GenerateBundle(colors, render_steps)
|
||||
var/list/reference_data = list()
|
||||
generated_icon = reference_type.GenerateBundle(colors, reference_data)
|
||||
render_steps += reference_data[icon_state]
|
||||
else
|
||||
return reference_type.Generate(colors.Join())
|
||||
generated_icon = reference_type.Generate(colors.Join())
|
||||
return icon(generated_icon, icon_state)
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
/// A list of colors currently selected
|
||||
var/list/split_colors
|
||||
|
||||
/// The type that the configuration file was assigned at
|
||||
var/config_owner_type
|
||||
|
||||
/// Collection of data for tgui to use in displaying everything
|
||||
var/list/sprite_data
|
||||
/// The sprite dir currently being shown
|
||||
@@ -38,15 +41,18 @@
|
||||
src.apply_callback = apply_callback || CALLBACK(src, .proc/DefaultApply)
|
||||
icon_state = starting_icon_state
|
||||
|
||||
SetupConfigOwner()
|
||||
|
||||
var/current_config = "[starting_config]" || "[target?.greyscale_config]"
|
||||
config = SSgreyscale.configurations[current_config]
|
||||
var/datum/greyscale_config/new_config = SSgreyscale.configurations[current_config]
|
||||
if(!(current_config in allowed_configs))
|
||||
config = SSgreyscale.configurations["[allowed_configs[pick(allowed_configs)]]"]
|
||||
new_config = SSgreyscale.configurations["[allowed_configs[pick(allowed_configs)]]"]
|
||||
change_config(new_config)
|
||||
|
||||
var/list/config_choices = list()
|
||||
for(var/config_string in allowed_configs)
|
||||
var/datum/greyscale_config/config = text2path("[config_string]")
|
||||
config_choices[initial(config.name)] = config_string
|
||||
var/datum/greyscale_config/allowed_config = text2path("[config_string]")
|
||||
config_choices[initial(allowed_config.name)] = config_string
|
||||
src.allowed_configs = config_choices
|
||||
|
||||
ReadColorsFromString(starting_colors || target?.greyscale_colors)
|
||||
@@ -88,6 +94,7 @@
|
||||
data["generate_full_preview"] = generate_full_preview
|
||||
data["unlocked"] = unlocked
|
||||
data["refreshing"] = refreshing
|
||||
data["monitoring_files"] = !!(config.datum_flags & DF_ISPROCESSING)
|
||||
data["sprites_dir"] = dir2text(sprite_dir)
|
||||
data["icon_state"] = icon_state
|
||||
data["sprites"] = sprite_data
|
||||
@@ -108,7 +115,7 @@
|
||||
new_config = allowed_configs[new_config]
|
||||
new_config = SSgreyscale.configurations[new_config] || new_config
|
||||
if(!isnull(new_config) && config != new_config)
|
||||
config = new_config
|
||||
change_config(new_config)
|
||||
queue_refresh()
|
||||
|
||||
if("load_config_from_string")
|
||||
@@ -116,7 +123,7 @@
|
||||
return
|
||||
var/datum/greyscale_config/new_config = SSgreyscale.configurations[params["config_string"]]
|
||||
if(!isnull(new_config) && config != new_config)
|
||||
config = new_config
|
||||
change_config(new_config)
|
||||
queue_refresh()
|
||||
|
||||
if("toggle_full_preview")
|
||||
@@ -171,7 +178,7 @@
|
||||
apply_callback.Invoke(src)
|
||||
|
||||
if("refresh_file")
|
||||
if(!unlocked)
|
||||
if(!unlocked || !check_rights(R_DEBUG))
|
||||
return
|
||||
if(length(GLOB.player_list) > 1)
|
||||
var/check = alert(
|
||||
@@ -184,13 +191,36 @@ This is highly likely to cause a lag spike for a few seconds."},
|
||||
)
|
||||
if(check != "Yes")
|
||||
return
|
||||
SSgreyscale.RefreshConfigsFromFile()
|
||||
queue_refresh()
|
||||
config.Refresh(loadFromDisk=TRUE)
|
||||
|
||||
if("save_dmi")
|
||||
if(!unlocked)
|
||||
return
|
||||
config.SaveOutput(split_colors.Copy(1, config.expected_colors+1))
|
||||
|
||||
if("change_dir")
|
||||
sprite_dir = text2dir(params["new_sprite_dir"])
|
||||
queue_refresh()
|
||||
|
||||
if("toggle_mass_refresh")
|
||||
if(!unlocked || !check_rights(R_DEBUG))
|
||||
return
|
||||
if(config.datum_flags & DF_ISPROCESSING)
|
||||
config.DisableAutoRefresh(remove_all=TRUE)
|
||||
return
|
||||
if(length(GLOB.player_list) > 1)
|
||||
var/check = alert(
|
||||
user,
|
||||
{"Other players are connected to the server, are you sure you want to automatically refresh all greyscale configurations?\n
|
||||
This is highly likely to cause massive amounts of lag as every object in the game will be iterated over every few seconds."},
|
||||
"Auto-Refresh Greyscale Configurations",
|
||||
"Yes",
|
||||
"Cancel"
|
||||
)
|
||||
if(check != "Yes")
|
||||
return
|
||||
config.EnableAutoRefresh(config_owner_type)
|
||||
|
||||
/datum/greyscale_modify_menu/proc/ReadColorsFromString(colorString)
|
||||
var/list/raw_colors = splittext(colorString, "#")
|
||||
split_colors = list()
|
||||
@@ -203,7 +233,14 @@ This is highly likely to cause a lag spike for a few seconds."},
|
||||
new_color += num2hex(rand(0, 255), 2)
|
||||
split_colors[color_index] = new_color
|
||||
|
||||
/datum/greyscale_modify_menu/proc/change_config(datum/greyscale_config/new_config)
|
||||
if(config)
|
||||
UnregisterSignal(config, COMSIG_GREYSCALE_CONFIG_REFRESHED)
|
||||
config = new_config
|
||||
RegisterSignal(config, COMSIG_GREYSCALE_CONFIG_REFRESHED, .proc/queue_refresh)
|
||||
|
||||
/datum/greyscale_modify_menu/proc/queue_refresh()
|
||||
SIGNAL_HANDLER
|
||||
refreshing = TRUE
|
||||
addtimer(CALLBACK(src, .proc/refresh_preview), 1 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
|
||||
|
||||
@@ -235,25 +272,17 @@ This is highly likely to cause a lag spike for a few seconds."},
|
||||
finished = image(data["icon"], icon_state=icon_state)
|
||||
var/list/steps = list()
|
||||
sprite_data["steps"] = steps
|
||||
for(var/step in data["steps"])
|
||||
var/list/icon_state_data = data["steps"][icon_state]
|
||||
for(var/list/step as anything in icon_state_data)
|
||||
CHECK_TICK
|
||||
var/list/step_data = data["steps"][step]
|
||||
var/image/layer = image(step)
|
||||
var/image/result = step_data["result"]
|
||||
// SKYRAT EDIT BEGIN - Bringing back the GAGS coloring menu - ORIGINAL:
|
||||
/*
|
||||
var/image/layer = image(step["step"])
|
||||
var/image/result = image(step["result"])
|
||||
// SKYRAT EDIT BEGIN - Bringing back the GAGS coloring menu
|
||||
steps += list(
|
||||
list(
|
||||
"layer"=icon2html(layer, user, dir=sprite_dir, sourceonly=TRUE, override_skyrat = TRUE),
|
||||
"result"=icon2html(result, user, dir=sprite_dir, sourceonly=TRUE, override_skyrat = TRUE),
|
||||
"config_name"=step_data["config_name"]
|
||||
)
|
||||
)*/
|
||||
steps += list(
|
||||
list(
|
||||
"layer"=icon2html(layer, user, dir=sprite_dir, sourceonly=TRUE, override_skyrat = TRUE),
|
||||
"result"=icon2html(result, user, dir=sprite_dir, sourceonly=TRUE, override_skyrat = TRUE),
|
||||
"config_name"=step_data["config_name"]
|
||||
"config_name"=step["config_name"]
|
||||
)
|
||||
)
|
||||
// SKYRAT EDIT END
|
||||
@@ -268,3 +297,14 @@ This is highly likely to cause a lag spike for a few seconds."},
|
||||
|
||||
/datum/greyscale_modify_menu/proc/DefaultApply()
|
||||
target.set_greyscale(split_colors, config.type)
|
||||
|
||||
/// Gets the top level type that first uses the configuration in this type path
|
||||
/datum/greyscale_modify_menu/proc/SetupConfigOwner()
|
||||
var/atom/current = target.type
|
||||
var/atom/parent = target.parent_type
|
||||
if(!initial(current.greyscale_config))
|
||||
return
|
||||
while(initial(current.greyscale_config) == initial(parent.greyscale_config))
|
||||
current = parent
|
||||
parent = type2parent(current)
|
||||
config_owner_type = current
|
||||
|
||||
+1
-1
@@ -374,7 +374,6 @@
|
||||
#include "code\controllers\subsystem\explosions.dm"
|
||||
#include "code\controllers\subsystem\fire_burning.dm"
|
||||
#include "code\controllers\subsystem\garbage.dm"
|
||||
#include "code\controllers\subsystem\greyscale.dm"
|
||||
#include "code\controllers\subsystem\icon_smooth.dm"
|
||||
#include "code\controllers\subsystem\id_access.dm"
|
||||
#include "code\controllers\subsystem\idlenpcpool.dm"
|
||||
@@ -432,6 +431,7 @@
|
||||
#include "code\controllers\subsystem\processing\fastprocess.dm"
|
||||
#include "code\controllers\subsystem\processing\fields.dm"
|
||||
#include "code\controllers\subsystem\processing\fluids.dm"
|
||||
#include "code\controllers\subsystem\processing\greyscale.dm"
|
||||
#include "code\controllers\subsystem\processing\instruments.dm"
|
||||
#include "code\controllers\subsystem\processing\networks.dm"
|
||||
#include "code\controllers\subsystem\processing\obj.dm"
|
||||
|
||||
@@ -26,6 +26,7 @@ type GreyscaleMenuData = {
|
||||
sprites: SpriteData;
|
||||
generate_full_preview: boolean;
|
||||
unlocked: boolean;
|
||||
monitoring_files: boolean;
|
||||
sprites_dir: string;
|
||||
icon_state: string;
|
||||
refreshing: boolean;
|
||||
@@ -292,21 +293,48 @@ export const GreyscaleModifyMenu = (props, context) => {
|
||||
<ConfigDisplay />
|
||||
<ColorDisplay />
|
||||
<IconStatesDisplay />
|
||||
{
|
||||
!!data.unlocked
|
||||
&& <Button content="Refresh Icon File" onClick={() => act("refresh_file")} />
|
||||
}
|
||||
<Button
|
||||
content="Apply"
|
||||
onClick={() => act("apply")}
|
||||
mx={1}
|
||||
/>
|
||||
<Button.Checkbox
|
||||
content="Full Preview"
|
||||
disabled={!data.generate_full_preview && !data.unlocked}
|
||||
checked={data.generate_full_preview}
|
||||
onClick={() => act("toggle_full_preview")}
|
||||
/>
|
||||
<Flex direction="column">
|
||||
{
|
||||
!!data.unlocked
|
||||
&& (
|
||||
<Flex.Item justify="flex-start">
|
||||
<Button
|
||||
content={<Icon name="file-image-o" spin={data.monitoring_files} />}
|
||||
tooltip="Continuously checks files for changes and reloads when necessary. WARNING: Very expensive"
|
||||
selected={data.monitoring_files}
|
||||
onClick={() => act("toggle_mass_refresh")}
|
||||
width={1.9}
|
||||
mr={-0.2}
|
||||
/>
|
||||
<Button
|
||||
content="Refresh Icon File"
|
||||
tooltip="Loads the json configuration and icon file fresh from disk. This is useful to avoid restarting the server to see changes. WARNING: Expensive"
|
||||
onClick={() => act("refresh_file")}
|
||||
/>
|
||||
<Button
|
||||
content="Save Icon File"
|
||||
tooltip="Saves the icon to a temp file in tmp/. This is useful if you want to use a generated icon elsewhere or just view a more accurate representation"
|
||||
onClick={() => act("save_dmi")}
|
||||
/>
|
||||
</Flex.Item>
|
||||
)
|
||||
}
|
||||
<Flex.Item>
|
||||
<Button
|
||||
content="Apply"
|
||||
tooltip="Applies changes made to the object this menu was created from."
|
||||
color="red"
|
||||
onClick={() => act("apply")}
|
||||
/>
|
||||
<Button.Checkbox
|
||||
content="Full Preview"
|
||||
tooltip="Generates and displays the full sprite generation process instead of just the final output."
|
||||
disabled={!data.generate_full_preview && !data.unlocked}
|
||||
checked={data.generate_full_preview}
|
||||
onClick={() => act("toggle_full_preview")}
|
||||
/>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
<PreviewDisplay />
|
||||
{
|
||||
!!data.refreshing && <LoadingAnimation />
|
||||
|
||||
Reference in New Issue
Block a user