ports tgui color input from bubbers (#16934)

* ports tgui color input from monkeystation

* .

* push that real quick

* .

* .

* cleanup

* fix for 516

* port bubbers pre set selection

* also this

* allow 20 saved states

* oups

* regex replace

* urg

* use the update by type

* .

* .

* highlight?

* larger?

* fix those

* keep anyone below 516 on old style
This commit is contained in:
Kashargul
2025-01-21 18:27:45 -05:00
committed by GitHub
parent 7266c4c5dc
commit c0e339b1ea
56 changed files with 1913 additions and 108 deletions
+1 -1
View File
@@ -83,7 +83,7 @@
active_mode = text2num(params["mode"])
return TRUE
if("choose_color")
var/chosen_color = input(inserted, "Choose a color: ", "ColorMate colour picking", activecolor) as color|null
var/chosen_color = tgui_color_picker(inserted, "Choose a color: ", "ColorMate colour picking", activecolor)
if(chosen_color)
activecolor = chosen_color
return TRUE
+1 -1
View File
@@ -168,7 +168,7 @@
active_mode = text2num(params["mode"])
return TRUE
if("choose_color")
var/chosen_color = input(ui.user, "Choose a color: ", "ColorMate colour picking", activecolor) as color|null
var/chosen_color = tgui_color_picker(ui.user, "Choose a color: ", "ColorMate colour picking", activecolor)
if(chosen_color)
activecolor = chosen_color
return TRUE
+1 -1
View File
@@ -171,7 +171,7 @@
return
switch(option)
if("tint")
var/new_color = input(user, "Choose the color for the [identifier] to be:", "Statue color", tint) as color|null
var/new_color = tgui_color_picker(user, "Choose the color for the [identifier] to be:", "Statue color", tint)
if (new_color)
tint = new_color
if("material","identifier","adjective")
+1 -1
View File
@@ -294,7 +294,7 @@
if(istype(W,/obj/item/multitool) && state == 1)
var/new_paint_location = tgui_input_list(user, "Please select a target zone.", "Paint Zone", list("Fore Stripe", "Aft Stripe", "CANCEL"))
if(new_paint_location && new_paint_location != "CANCEL")
var/new_paint_color = input(user, "Please select a paint color.", "Paint Color", null) as color|null
var/new_paint_color = tgui_color_picker(user, "Please select a paint color.", "Paint Color", null)
if(new_paint_color)
switch(new_paint_location)
if("Fore Stripe")
+1 -1
View File
@@ -70,7 +70,7 @@
if(istype(W,/obj/item/multitool) && state == 1)
var/new_paint_location = tgui_input_list(user, "Please select a target zone.", "Paint Zone", list("Central", "Engine", "Base", "Front", "CANCEL"))
if(new_paint_location && new_paint_location != "CANCEL")
var/new_paint_color = input(user, "Please select a paint color.", "Paint Color", null) as color|null
var/new_paint_color = tgui_color_picker(user, "Please select a paint color.", "Paint Color", null)
if(new_paint_color)
switch(new_paint_location)
if("Central")
@@ -129,7 +129,7 @@
if(usr.incapacitated())
return
var/new_colour = input(usr, "Choose a colour.", name, paint_colour) as color|null
var/new_colour = tgui_color_picker(usr, "Choose a colour.", name, paint_colour)
if(new_colour && new_colour != paint_colour)
paint_colour = new_colour
to_chat(usr, span_notice("You set \the [src] to paint with <font color='[paint_colour]'>a new colour</font>."))
+1 -1
View File
@@ -318,7 +318,7 @@ GLOBAL_LIST_EMPTY(GPS_list)
if(href_list["track_color"])
var/obj/item/gps/gps = locate(href_list["track_color"])
if(istype(gps) && !QDELETED(gps))
var/new_colour = input(usr, "Enter a new tracking color.", "GPS Waypoint Color") as color|null
var/new_colour = tgui_color_picker(usr, "Enter a new tracking color.", "GPS Waypoint Color")
if(new_colour && istype(gps) && !QDELETED(gps) && holder == usr && !usr.incapacitated())
to_chat(usr, span_notice("You adjust the colour \the [src] is using to highlight [gps.gps_tag]."))
LAZYSET(tracking_devices, href_list["track_color"], new_colour)
@@ -138,7 +138,7 @@
return
*/
to_chat(user, "It has [uses] lights remaining.")
var/new_color = input(user, "Choose a color to set the light to! (Default is [LIGHT_COLOR_INCANDESCENT_TUBE])", "", selected_color) as color|null
var/new_color = tgui_color_picker(user, "Choose a color to set the light to! (Default is [LIGHT_COLOR_INCANDESCENT_TUBE])", "", selected_color)
if(new_color)
selected_color = new_color
to_chat(user, "The light color has been changed.")
@@ -208,7 +208,7 @@
to_chat(user, span_notice("You remove the cell from \the [src]."))
update_icon()
else if(istype(W,/obj/item/multitool))
var/new_color = input(usr, "Choose a color to set the shield to!", "", effect_color) as color|null
var/new_color = tgui_color_picker(usr, "Choose a color to set the shield to!", "", effect_color)
if(new_color)
effect_color = new_color
else
+1 -1
View File
@@ -198,7 +198,7 @@
return
if(tgui_alert(user, "Are you sure you want to recolor your blade?", "Confirm Recolor", list("Yes", "No")) == "Yes")
var/energy_color_input = input(user,"","Choose Energy Color",lcolor) as color|null
var/energy_color_input = tgui_color_picker(user,"","Choose Energy Color",lcolor)
if(energy_color_input)
lcolor = sanitize_hexcolor(energy_color_input)
update_icon()
@@ -34,6 +34,6 @@
/obj/item/grenade/smokebomb/attackby(obj/item/I as obj, mob/user as mob)
if(istype(I,/obj/item/multitool))
var/new_smoke_color = input(user, "Choose a color for the smoke:", "Smoke Color", smoke_color) as color|null
var/new_smoke_color = tgui_color_picker(user, "Choose a color for the smoke:", "Smoke Color", smoke_color)
if(new_smoke_color)
smoke_color = new_smoke_color
@@ -188,10 +188,12 @@
return
if(tgui_alert(user, "Are you sure you want to recolor your blade?", "Confirm Recolor", list("Yes", "No")) == "Yes")
var/energy_color_input = input(user,"","Choose Energy Color",lcolor) as color|null
var/energy_color_input = tgui_color_picker(user,"","Choose Energy Color",lcolor)
if(energy_color_input)
lcolor = sanitize_hexcolor(energy_color_input)
update_icon()
if(active)
set_light(lrange, lpower, lcolor)
/obj/item/melee/energy/examine(mob/user)
. = ..()
+1 -1
View File
@@ -209,7 +209,7 @@
to_chat(user, span_warning("You can't do that right now!"))
return
if(tgui_alert(user, "Are you sure you want to recolor your shield?", "Confirm Recolor", list("Yes", "No")) == "Yes")
var/energy_color_input = input(user,"","Choose Energy Color",lcolor) as color|null
var/energy_color_input = tgui_color_picker(user,"","Choose Energy Color",lcolor)
if(energy_color_input)
lcolor = sanitize_hexcolor(energy_color_input)
update_icon()
@@ -120,7 +120,7 @@
if(usr.stat || usr.restrained() || usr.incapacitated())
return
var/new_color = input(usr, "Pick a new color", "Wallet Color", color) as color|null
var/new_color = tgui_color_picker(usr, "Pick a new color", "Wallet Color", color)
if(new_color && (new_color != color))
color = new_color
@@ -199,7 +199,7 @@
// VOREStation Add End
else if(href_list["pref_runechat_color"])
var/new_runechat_color = input(user, "Choose your character's runechat colour (#000000 for random):", "Character Preference", pref.runechat_color) as color|null
var/new_runechat_color = tgui_color_picker(user, "Choose your character's runechat colour (#000000 for random):", "Character Preference", pref.runechat_color)
if(new_runechat_color && CanUseTopic(user))
pref.runechat_color = new_runechat_color
// whenever we change this, we update our mob
@@ -593,7 +593,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
else if(href_list["hair_color"])
if(!has_flag(mob_species, HAS_HAIR_COLOR))
return TOPIC_NOACTION
var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference", pref.read_preference(/datum/preference/color/human/hair_color)) as color|null
var/new_hair = tgui_color_picker(user, "Choose your character's hair colour:", "Character Preference", pref.read_preference(/datum/preference/color/human/hair_color))
if(new_hair && has_flag(mob_species, HAS_HAIR_COLOR) && CanUseTopic(user))
pref.update_preference_by_type(/datum/preference/color/human/hair_color, new_hair)
return TOPIC_REFRESH_UPDATE_PREVIEW
@@ -601,7 +601,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
else if(href_list["grad_color"])
if(!has_flag(mob_species, HAS_HAIR_COLOR))
return TOPIC_NOACTION
var/new_grad = input(user, "Choose your character's secondary hair color:", "Character Preference", pref.read_preference(/datum/preference/color/human/grad_color)) as color|null
var/new_grad = tgui_color_picker(user, "Choose your character's secondary hair color:", "Character Preference", pref.read_preference(/datum/preference/color/human/grad_color))
if(new_grad && has_flag(mob_species, HAS_HAIR_COLOR) && CanUseTopic(user))
pref.update_preference_by_type(/datum/preference/color/human/grad_color, new_grad)
return TOPIC_REFRESH_UPDATE_PREVIEW
@@ -647,7 +647,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
else if(href_list["facial_color"])
if(!has_flag(mob_species, HAS_HAIR_COLOR))
return TOPIC_NOACTION
var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference", pref.read_preference(/datum/preference/color/human/facial_color)) as color|null
var/new_facial = tgui_color_picker(user, "Choose your character's facial-hair colour:", "Character Preference", pref.read_preference(/datum/preference/color/human/facial_color))
if(new_facial && has_flag(mob_species, HAS_HAIR_COLOR) && CanUseTopic(user))
pref.update_preference_by_type(/datum/preference/color/human/facial_color, new_facial)
return TOPIC_REFRESH_UPDATE_PREVIEW
@@ -660,7 +660,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
else if(href_list["eye_color"])
if(!has_flag(mob_species, HAS_EYE_COLOR))
return TOPIC_NOACTION
var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference", pref.read_preference(/datum/preference/color/human/eyes_color)) as color|null
var/new_eyes = tgui_color_picker(user, "Choose your character's eye colour:", "Character Preference", pref.read_preference(/datum/preference/color/human/eyes_color))
if(new_eyes && has_flag(mob_species, HAS_EYE_COLOR) && CanUseTopic(user))
pref.update_preference_by_type(/datum/preference/color/human/eyes_color, new_eyes)
return TOPIC_REFRESH_UPDATE_PREVIEW
@@ -676,7 +676,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
else if(href_list["skin_color"])
if(!has_flag(mob_species, HAS_SKIN_COLOR))
return TOPIC_NOACTION
var/new_skin = input(user, "Choose your character's skin colour: ", "Character Preference", pref.read_preference(/datum/preference/color/human/skin_color)) as color|null
var/new_skin = tgui_color_picker(user, "Choose your character's skin colour: ", "Character Preference", pref.read_preference(/datum/preference/color/human/skin_color))
if(new_skin && has_flag(mob_species, HAS_SKIN_COLOR) && CanUseTopic(user))
pref.update_preference_by_type(/datum/preference/color/human/skin_color, new_skin)
return TOPIC_REFRESH_UPDATE_PREVIEW
@@ -769,7 +769,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
if (isnull(pref.body_markings[M]["color"]))
if (tgui_alert(user, "You currently have customized marking colors. This will reset each bodypart's color. Are you sure you want to continue?","Reset Bodypart Colors",list("Yes","No")) != "Yes")
return TOPIC_NOACTION
var/mark_color = input(user, "Choose the [M] color: ", "Character Preference", pref.body_markings[M]["color"]) as color|null
var/mark_color = tgui_color_picker(user, "Choose the [M] color: ", "Character Preference", pref.body_markings[M]["color"])
if(mark_color && CanUseTopic(user))
pref.body_markings[M] = pref.mass_edit_marking_list(M,FALSE,TRUE,pref.body_markings[M],color="[mark_color]")
return TOPIC_REFRESH_UPDATE_PREVIEW
@@ -794,7 +794,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
if (pref.body_markings.Find(marking) == 0)
winshow(user, "prefs_markings_subwindow", FALSE)
return TOPIC_NOACTION
var/mark_color = input(user, "Choose the [marking] color: ", "Character Preference", pref.body_markings[marking]["color"]) as color|null
var/mark_color = tgui_color_picker(user, "Choose the [marking] color: ", "Character Preference", pref.body_markings[marking]["color"])
if(mark_color && CanUseTopic(user))
pref.body_markings[marking] = pref.mass_edit_marking_list(marking,FALSE,TRUE,pref.body_markings[marking],color="[mark_color]")
markings_subwindow(user, marking)
@@ -807,7 +807,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
return TOPIC_NOACTION
var/zone = href_list["zone"]
pref.body_markings[marking]["color"] = null //turn off the color button outside the submenu
var/mark_color = input(user, "Choose the [marking] color: ", "Character Preference", pref.body_markings[marking][zone]["color"]) as color|null
var/mark_color = tgui_color_picker(user, "Choose the [marking] color: ", "Character Preference", pref.body_markings[marking][zone]["color"])
if(mark_color && CanUseTopic(user))
pref.body_markings[marking][zone]["color"] = "[mark_color]"
markings_subwindow(user, marking)
@@ -1036,7 +1036,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["synth2_color"])
var/new_color = input(user, "Choose your character's synth colour: ", "Character Preference", pref.read_preference(/datum/preference/color/human/synth_color)) as color|null
var/new_color = tgui_color_picker(user, "Choose your character's synth colour: ", "Character Preference", pref.read_preference(/datum/preference/color/human/synth_color))
if(new_color && CanUseTopic(user))
pref.update_preference_by_type(/datum/preference/color/human/synth_color, new_color)
return TOPIC_REFRESH_UPDATE_PREVIEW
@@ -1057,22 +1057,22 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["ear_color"])
var/new_earc = input(user, "Choose your character's ear colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/ears_color1)) as color|null
var/new_earc = tgui_color_picker(user, "Choose your character's ear colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/ears_color1))
if(new_earc)
pref.update_preference_by_type(/datum/preference/color/human/ears_color1, new_earc)
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["ear_color2"])
var/new_earc2 = input(user, "Choose your character's ear colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/ears_color2)) as color|null
var/new_earc2 = tgui_color_picker(user, "Choose your character's ear colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/ears_color2))
if(new_earc2)
pref.update_preference_by_type(/datum/preference/color/human/ears_color2, new_earc2)
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["ear_color3"])
var/new_earc3 = input(user, "Choose your character's tertiary ear colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/ears_color3)) as color|null
var/new_earc3 = tgui_color_picker(user, "Choose your character's tertiary ear colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/ears_color3))
if(new_earc3)
pref.update_preference_by_type(/datum/preference/color/human/ears_color3, new_earc3)
return TOPIC_REFRESH_UPDATE_PREVIEW
@@ -1089,12 +1089,12 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
if(channel > GLOB.fancy_sprite_accessory_color_channel_names.len)
return TOPIC_NOACTION
// this would say 'secondary ears' but you'd get 'choose your character's primary secondary ear colour' which sounds silly
var/new_color = input(
var/new_color = tgui_color_picker(
user,
"Choose your character's [lowertext(GLOB.fancy_sprite_accessory_color_channel_names[channel])] ear colour:",
"Secondary Ear Coloration",
LAZYACCESS(pref.ear_secondary_colors, channel) || "#ffffff",
) as color | null
)
if(!new_color)
return TOPIC_NOACTION
// ensures color channel list is at least that long
@@ -1110,22 +1110,22 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["tail_color"])
var/new_tailc = input(user, "Choose your character's tail/taur colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/tail_color1)) as color|null
var/new_tailc = tgui_color_picker(user, "Choose your character's tail/taur colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/tail_color1))
if(new_tailc)
pref.update_preference_by_type(/datum/preference/color/human/tail_color1, new_tailc)
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["tail_color2"])
var/new_tailc2 = input(user, "Choose your character's secondary tail/taur colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/tail_color2)) as color|null
var/new_tailc2 = tgui_color_picker(user, "Choose your character's secondary tail/taur colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/tail_color2))
if(new_tailc2)
pref.update_preference_by_type(/datum/preference/color/human/tail_color2, new_tailc2)
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["tail_color3"])
var/new_tailc3 = input(user, "Choose your character's tertiary tail/taur colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/tail_color3)) as color|null
var/new_tailc3 = tgui_color_picker(user, "Choose your character's tertiary tail/taur colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/tail_color3))
if(new_tailc3)
pref.update_preference_by_type(/datum/preference/color/human/tail_color3, new_tailc3)
return TOPIC_REFRESH_UPDATE_PREVIEW
@@ -1138,22 +1138,22 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["wing_color"])
var/new_wingc = input(user, "Choose your character's wing colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/wing_color1)) as color|null
var/new_wingc = tgui_color_picker(user, "Choose your character's wing colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/wing_color1))
if(new_wingc)
pref.update_preference_by_type(/datum/preference/color/human/wing_color1, new_wingc)
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["wing_color2"])
var/new_wingc = input(user, "Choose your character's secondary wing colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/wing_color2)) as color|null
var/new_wingc = tgui_color_picker(user, "Choose your character's secondary wing colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/wing_color2))
if(new_wingc)
pref.update_preference_by_type(/datum/preference/color/human/wing_color2, new_wingc)
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["wing_color3"])
var/new_wingc = input(user, "Choose your character's tertiary wing colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/wing_color3)) as color|null
var/new_wingc = tgui_color_picker(user, "Choose your character's tertiary wing colour:", "Character Preference",
pref.read_preference(/datum/preference/color/human/wing_color3))
if(new_wingc)
pref.update_preference_by_type(/datum/preference/color/human/wing_color3, new_wingc)
return TOPIC_REFRESH_UPDATE_PREVIEW
@@ -35,7 +35,7 @@
/datum/gear_tweak/color/get_metadata(var/user, var/metadata, var/title = "Character Preference")
if(valid_colors)
return tgui_input_list(user, "Choose a color.", title, valid_colors, metadata)
return input(user, "Choose a color.", title, metadata) as color|null
return tgui_color_picker(user, "Choose a color.", title, metadata)
/datum/gear_tweak/color/tweak_item(var/obj/item/I, var/metadata)
if(valid_colors && !(metadata in valid_colors))
@@ -614,4 +614,4 @@ var/datum/gear_tweak/custom_desc/gear_tweak_free_desc = new()
else
C.initialize_tag(metadata)
#undef LOADOUT_BAN_STRING
#undef LOADOUT_BAN_STRING
@@ -101,7 +101,7 @@ var/global/list/valid_bloodreagents = list("default",REAGENT_ID_IRON,REAGENT_ID_
if (1) //TRAIT_PREF_TYPE_BOOLEAN
trait_prefs[preference] = !trait_prefs[preference]
if (2) //TRAIT_PREF_TYPE_COLOR
var/new_color = input(user, "Choose the color for this trait preference:", "Trait Preference", trait_prefs[preference]) as color|null
var/new_color = tgui_color_picker(user, "Choose the color for this trait preference:", "Trait Preference", trait_prefs[preference])
if (new_color)
trait_prefs[preference] = new_color
if (3) //TRAIT_PREF_TYPE_STRING
@@ -89,3 +89,12 @@
/datum/preference/numeric/tgui_say_height/apply_to_client(client/client, value)
client.tgui_say?.load()
/datum/preference/text/preset_colors
category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
savefile_identifier = PREFERENCE_PLAYER
savefile_key = "preset_colors"
maximum_value_length = 160
/datum/preference/text/preset_colors/apply_to_client(client/client, value)
return
+2 -2
View File
@@ -92,12 +92,12 @@
var/default_value = read_preference(requested_preference.type)
// Yielding
var/new_color = input(
var/new_color = tgui_color_picker(
usr,
"Select new color",
null,
default_value || COLOR_WHITE,
) as color | null
)
if(!new_color)
return FALSE
+1 -1
View File
@@ -51,7 +51,7 @@ var/global/list/all_tooltip_styles = list(
var/UI_style_alpha_new = tgui_input_number(usr, "Select a new alpha (transparency) parameter for your UI, between 50 and 255", null, null, 255, 50)
if(!UI_style_alpha_new || !(UI_style_alpha_new <= 255 && UI_style_alpha_new >= 50)) return
var/UI_style_color_new = input(usr, "Choose your UI color. Dark colors are not recommended!") as color|null
var/UI_style_color_new = tgui_color_picker(usr, "Choose your UI color. Dark colors are not recommended!")
if(!UI_style_color_new) return
//update UI
+1 -1
View File
@@ -177,7 +177,7 @@
if(usr.stat || usr.restrained() || usr.incapacitated())
return
var/new_color = input(usr, "Pick a new color", "Color", color) as color|null
var/new_color = tgui_color_picker(usr, "Pick a new color", "Color", color)
if(new_color && (new_color != color))
color = new_color
@@ -69,8 +69,8 @@
// Just uncomment this and get rid of all of the TGUI bullshit lol
// if(!in_range(user, src))
// return
// var/new_color = input(user, "Pick a color", "Color Selection", detail_color) as color|null
// var/new_color = tgui_color_picker(user, "Pick a color", "Color Selection", detail_color)
// if(!new_color)
// return
// detail_color = new_color
// update_icon()
// update_icon()
@@ -92,7 +92,7 @@
power_draw_per_use = 4
/obj/item/integrated_circuit/input/colorpad/ask_for_input(mob/user)
var/new_color = input(user, "Enter a color, please.", "Color pad", get_pin_data(IC_OUTPUT, 1)) as color|null
var/new_color = tgui_color_picker(user, "Enter a color, please.", "Color pad", get_pin_data(IC_OUTPUT, 1))
if(new_color && CanInteract(user, GLOB.tgui_physical_state))
set_pin_data(IC_OUTPUT, 1, new_color)
push_data()
@@ -83,7 +83,7 @@
for(var/channel in 1 to ear_secondary_style.get_color_channel_count())
var/channel_name = GLOB.fancy_sprite_accessory_color_channel_names[channel]
var/default = LAZYACCESS(ear_secondary_colors, channel) || "#ffffff"
var/new_color = input(usr, "Pick [channel_name]", "Ear Color ([channel_name])", default) as color | null
var/new_color = tgui_color_picker(usr, "Pick [channel_name]", "Ear Color ([channel_name])", default)
new_colors += new_color || default
update_hair()
@@ -1274,7 +1274,7 @@
return
if(choice == "Color") //Easy way to set color so we don't bloat up the menu with even more buttons.
var/new_color = input(src, "Choose a color to set your appendage to!", "", appendage_color) as color|null
var/new_color = tgui_color_picker(src, "Choose a color to set your appendage to!", "", appendage_color)
if(new_color)
appendage_color = new_color
if(choice == "Functionality") //Easy way to set color so we don't bloat up the menu with even more buttons.
+1 -1
View File
@@ -607,7 +607,7 @@ var/list/ai_verbs_default = list(
switch(choice)
if("Color")
input = input("Choose a color:", "Hologram Color", holo_color) as color|null
input = tgui_color_picker("Choose a color:", "Hologram Color", holo_color)
if(input)
holo_color = input
@@ -236,7 +236,7 @@
else
to_chat(src, span_warning("Your selected chassis eye color can not be modified. The color you pick will only apply to supporting chassis and your card screen."))
var/new_eye_color = input(src, "Choose your character's eye color:", "Eye Color") as color|null
var/new_eye_color = tgui_color_picker(src, "Choose your character's eye color:", "Eye Color")
if(new_eye_color)
eye_color = new_eye_color
update_icon()
@@ -254,7 +254,7 @@
if(!choice)
return
if(choice == "Color")
var/new_color = input(usr, "Choose a color to set the light to! (Default is [LIGHT_COLOR_INCANDESCENT_TUBE])", "", selected_color) as color|null
var/new_color = tgui_color_picker(usr, "Choose a color to set the light to! (Default is [LIGHT_COLOR_INCANDESCENT_TUBE])", "", selected_color)
if(new_color)
selected_color = new_color
to_chat(user, span_filter_notice("The light color has been changed."))
@@ -28,7 +28,7 @@
set category = "Abilities.Silicon"
set src in usr
var/new_pupil_color = input(usr, "Select a pupil colour.", "Pupil Colour Selection") as color|null
var/new_pupil_color = tgui_color_picker(usr, "Select a pupil colour.", "Pupil Colour Selection")
if(usr.incapacitated() || QDELETED(usr) || QDELETED(src) || loc != usr)
return
@@ -291,7 +291,7 @@
if(picked_color)
to_chat(src, span_notice("You have already picked a color! If you picked the wrong color, ask an admin to change your picked_color variable to 0."))
return
var/newcolor = input(usr, "Choose a color.", "", color) as color|null
var/newcolor = tgui_color_picker(usr, "Choose a color.", "", color)
if(newcolor)
color = newcolor
picked_color = TRUE
@@ -215,7 +215,7 @@
if(picked_color)
to_chat(src, span_notice("You have already picked a color! If you picked the wrong color, ask an admin to change your picked_color variable to 0."))
return
var/newcolor = input(usr, "Choose a color.", "", color) as color|null
var/newcolor = tgui_color_picker(usr, "Choose a color.", "", color)
if(newcolor)
color = newcolor
picked_color = TRUE
@@ -249,7 +249,7 @@
set name = "Pick Color"
set category = "Abilities.Settings"
set desc = "You can set your color!"
var/newcolor = input(usr, "Choose a color.", "", color) as color|null
var/newcolor = tgui_color_picker(usr, "Choose a color.", "", color)
if(newcolor)
color = newcolor
chosen_color = newcolor
@@ -95,7 +95,7 @@
set desc = "Customize your eyes and abdomen glow color."
set category = "Abilities.Sect Drone"
var/new_color = input(src, "Please select color.", "Glow Color", custom_eye_color) as color|null
var/new_color = tgui_color_picker(src, "Please select color.", "Glow Color", custom_eye_color)
if(new_color)
custom_eye_color = new_color
remove_eyes()
@@ -96,7 +96,7 @@
set desc = "Customize your eyes and abdomen glow color."
set category = "Abilities.Sect Queen"
var/new_color = input(src, "Please select color.", "Glow Color", custom_eye_color) as color|null
var/new_color = tgui_color_picker(src, "Please select color.", "Glow Color", custom_eye_color)
if(new_color)
custom_eye_color = new_color
remove_eyes()
+2 -2
View File
@@ -113,8 +113,8 @@ GLOBAL_LIST_EMPTY(all_waypoints)
var/turf/T = get_turf(linked)
var/obj/effect/overmap/visitable/sector/current_sector = locate() in T
data["mapRef"] = linked?.map_name
if(linked)
data["mapRef"] = linked.map_name
data["sector"] = current_sector ? current_sector.name : "Deep Space"
data["sector_info"] = current_sector ? current_sector.desc : "Not Available"
data["landed"] = linked.get_landed_info()
+2 -2
View File
@@ -1114,7 +1114,7 @@ var/global/list/light_type_cache = list()
brightness_power = new_power
if("Normal Color")
var/new_color = input(usr, "Choose a color to set the light to!", "", brightness_color) as color|null
var/new_color = tgui_color_picker(usr, "Choose a color to set the light to!", "", brightness_color)
if(new_color)
brightness_color = new_color
@@ -1129,7 +1129,7 @@ var/global/list/light_type_cache = list()
nightshift_power = new_power
if("Nightshift Color")
var/new_color = input(usr, "Choose a color to set the light to!", "", nightshift_color) as color|null
var/new_color = tgui_color_picker(usr, "Choose a color to set the light to!", "", nightshift_color)
if(new_color)
nightshift_color = new_color
@@ -734,7 +734,7 @@
desc = "Causes kinetic accelerator bolts to have an adjustable-colored tracer trail and explosion. Use in-hand to change color."
/obj/item/borg/upgrade/modkit/tracer/adjustable/attack_self(mob/user)
bolt_color = input(user,"","Choose Color",bolt_color) as color|null
bolt_color = tgui_color_picker(user,"","Choose Color",bolt_color)
#undef KA_ENVIRO_TYPE_COLD
#undef KA_ENVIRO_TYPE_HOT
+14 -14
View File
@@ -116,7 +116,7 @@
return owner.change_skin_tone(new_s_tone)
if("skin_color")
if(can_change_skin_color(owner))
var/new_skin = input(ui.user, "Choose your character's skin colour: ", "Skin Color", rgb(owner.r_skin, owner.g_skin, owner.b_skin)) as color|null
var/new_skin = tgui_color_picker(ui.user, "Choose your character's skin colour: ", "Skin Color", rgb(owner.r_skin, owner.g_skin, owner.b_skin))
if(new_skin && can_still_topic(owner, state))
var/r_skin = hex2num(copytext(new_skin, 2, 4))
var/g_skin = hex2num(copytext(new_skin, 4, 6))
@@ -133,7 +133,7 @@
return 1
if("hair_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = input(ui.user, "Please select hair color.", "Hair Color", rgb(owner.r_hair, owner.g_hair, owner.b_hair)) as color|null
var/new_hair = tgui_color_picker(ui.user, "Please select hair color.", "Hair Color", rgb(owner.r_hair, owner.g_hair, owner.b_hair))
if(new_hair && can_still_topic(owner, state))
var/r_hair = hex2num(copytext(new_hair, 2, 4))
var/g_hair = hex2num(copytext(new_hair, 4, 6))
@@ -150,7 +150,7 @@
return 1
if("facial_hair_color")
if(can_change(owner, APPEARANCE_FACIAL_HAIR_COLOR))
var/new_facial = input(ui.user, "Please select facial hair color.", "Facial Hair Color", rgb(owner.r_facial, owner.g_facial, owner.b_facial)) as color|null
var/new_facial = tgui_color_picker(ui.user, "Please select facial hair color.", "Facial Hair Color", rgb(owner.r_facial, owner.g_facial, owner.b_facial))
if(new_facial && can_still_topic(owner, state))
var/r_facial = hex2num(copytext(new_facial, 2, 4))
var/g_facial = hex2num(copytext(new_facial, 4, 6))
@@ -161,7 +161,7 @@
return 1
if("eye_color")
if(can_change(owner, APPEARANCE_EYE_COLOR))
var/new_eyes = input(ui.user, "Please select eye color.", "Eye Color", rgb(owner.r_eyes, owner.g_eyes, owner.b_eyes)) as color|null
var/new_eyes = tgui_color_picker(ui.user, "Please select eye color.", "Eye Color", rgb(owner.r_eyes, owner.g_eyes, owner.b_eyes))
if(new_eyes && can_still_topic(owner, state))
var/r_eyes = hex2num(copytext(new_eyes, 2, 4))
var/g_eyes = hex2num(copytext(new_eyes, 4, 6))
@@ -201,7 +201,7 @@
return TRUE
if("ears_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = input(ui.user, "Please select ear color.", "Ear Color", rgb(owner.r_ears, owner.g_ears, owner.b_ears)) as color|null
var/new_hair = tgui_color_picker(ui.user, "Please select ear color.", "Ear Color", rgb(owner.r_ears, owner.g_ears, owner.b_ears))
if(new_hair && can_still_topic(owner, state))
owner.r_ears = hex2num(copytext(new_hair, 2, 4))
owner.g_ears = hex2num(copytext(new_hair, 4, 6))
@@ -212,7 +212,7 @@
return 1
if("ears2_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = input(ui.user, "Please select secondary ear color.", "2nd Ear Color", rgb(owner.r_ears2, owner.g_ears2, owner.b_ears2)) as color|null
var/new_hair = tgui_color_picker(ui.user, "Please select secondary ear color.", "2nd Ear Color", rgb(owner.r_ears2, owner.g_ears2, owner.b_ears2))
if(new_hair && can_still_topic(owner, state))
owner.r_ears2 = hex2num(copytext(new_hair, 2, 4))
owner.g_ears2 = hex2num(copytext(new_hair, 4, 6))
@@ -227,7 +227,7 @@
if(channel > length(owner.ear_secondary_colors))
return TRUE
var/existing = LAZYACCESS(owner.ear_secondary_colors, channel) || "#ffffff"
var/new_color = input(ui.user, "Please select ear color.", "2nd Ear Color", existing) as color|null
var/new_color = tgui_color_picker(ui.user, "Please select ear color.", "2nd Ear Color", existing)
if(new_color && can_still_topic(owner, state))
owner.ear_secondary_colors[channel] = new_color
update_dna(owner)
@@ -248,7 +248,7 @@
return TRUE
if("tail_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = input(ui.user, "Please select tail color.", "Tail Color", rgb(owner.r_tail, owner.g_tail, owner.b_tail)) as color|null
var/new_hair = tgui_color_picker(ui.user, "Please select tail color.", "Tail Color", rgb(owner.r_tail, owner.g_tail, owner.b_tail))
if(new_hair && can_still_topic(owner, state))
owner.r_tail = hex2num(copytext(new_hair, 2, 4))
owner.g_tail = hex2num(copytext(new_hair, 4, 6))
@@ -259,7 +259,7 @@
return 1
if("tail2_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = input(ui.user, "Please select secondary tail color.", "2nd Tail Color", rgb(owner.r_tail2, owner.g_tail2, owner.b_tail2)) as color|null
var/new_hair = tgui_color_picker(ui.user, "Please select secondary tail color.", "2nd Tail Color", rgb(owner.r_tail2, owner.g_tail2, owner.b_tail2))
if(new_hair && can_still_topic(owner, state))
owner.r_tail2 = hex2num(copytext(new_hair, 2, 4))
owner.g_tail2 = hex2num(copytext(new_hair, 4, 6))
@@ -270,7 +270,7 @@
return 1
if("tail3_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = input(ui.user, "Please select secondary tail color.", "3rd Tail Color", rgb(owner.r_tail3, owner.g_tail3, owner.b_tail3)) as color|null
var/new_hair = tgui_color_picker(ui.user, "Please select secondary tail color.", "3rd Tail Color", rgb(owner.r_tail3, owner.g_tail3, owner.b_tail3))
if(new_hair && can_still_topic(owner, state))
owner.r_tail3 = hex2num(copytext(new_hair, 2, 4))
owner.g_tail3 = hex2num(copytext(new_hair, 4, 6))
@@ -293,7 +293,7 @@
return TRUE
if("wing_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = input(ui.user, "Please select wing color.", "Wing Color", rgb(owner.r_wing, owner.g_wing, owner.b_wing)) as color|null
var/new_hair = tgui_color_picker(ui.user, "Please select wing color.", "Wing Color", rgb(owner.r_wing, owner.g_wing, owner.b_wing))
if(new_hair && can_still_topic(owner, state))
owner.r_wing = hex2num(copytext(new_hair, 2, 4))
owner.g_wing = hex2num(copytext(new_hair, 4, 6))
@@ -304,7 +304,7 @@
return 1
if("wing2_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = input(ui.user, "Please select secondary wing color.", "2nd Wing Color", rgb(owner.r_wing2, owner.g_wing2, owner.b_wing2)) as color|null
var/new_hair = tgui_color_picker(ui.user, "Please select secondary wing color.", "2nd Wing Color", rgb(owner.r_wing2, owner.g_wing2, owner.b_wing2))
if(new_hair && can_still_topic(owner, state))
owner.r_wing2 = hex2num(copytext(new_hair, 2, 4))
owner.g_wing2 = hex2num(copytext(new_hair, 4, 6))
@@ -315,7 +315,7 @@
return 1
if("wing3_color")
if(can_change(owner, APPEARANCE_HAIR_COLOR))
var/new_hair = input(ui.user, "Please select secondary wing color.", "3rd Wing Color", rgb(owner.r_wing3, owner.g_wing3, owner.b_wing3)) as color|null
var/new_hair = tgui_color_picker(ui.user, "Please select secondary wing color.", "3rd Wing Color", rgb(owner.r_wing3, owner.g_wing3, owner.b_wing3))
if(new_hair && can_still_topic(owner, state))
owner.r_wing3 = hex2num(copytext(new_hair, 2, 4))
owner.g_wing3 = hex2num(copytext(new_hair, 4, 6))
@@ -353,7 +353,7 @@
return TRUE
if (4) //color
var/current = markings[name_marking] ? markings[name_marking] : "#000000"
var/marking_color = input(ui.user, "Please select marking color", "Marking color", current) as color|null
var/marking_color = tgui_color_picker(ui.user, "Please select marking color", "Marking color", current)
if(marking_color && can_still_topic(owner, state))
var/datum/sprite_accessory/marking/mark_datum = body_marking_styles_list[name_marking]
if (owner.change_marking_color(mark_datum, marking_color))
+2 -1
View File
@@ -33,7 +33,8 @@
/datum/tgui_module/ship/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
data["mapRef"] = linked?.map_name
if(linked)
data["mapRef"] = linked.map_name
return data
/datum/tgui_module/ship/tgui_status(mob/user)
+144
View File
@@ -0,0 +1,144 @@
/**
* Creates a TGUI color picker window and returns the user's response.
*
* This proc should be used to create a color picker that the caller will wait for a response from.
* Arguments:
* * user - The user to show the picker to.
* * title - The of the picker modal, shown on the top of the TGUI window.
* * timeout - The timeout of the picker, after which the modal will close and qdel itself. Set to zero for no timeout.
* * autofocus - The bool that controls if this picker should grab window focus.
*/
/proc/tgui_color_picker(mob/user, message, title, default = "#000000", timeout = 0, autofocus = TRUE)
if (!user)
user = usr
if (!istype(user))
if (istype(user, /client))
var/client/client = user
user = client.mob
else
return
// Client does NOT have tgui_input on: Returns regular input
if(!user.client.prefs.read_preference(/datum/preference/toggle/tgui_input_mode) || user.client.byond_version < 516) // Todo, remove once virgo is on 516, but currently the TGUI interface is already programmed for edge
return input(user, message, title, default) as color|null
var/datum/tgui_color_picker/picker = new(user, message, title, default, timeout, autofocus)
picker.tgui_interact(user)
picker.wait()
if (picker)
. = picker.choice
qdel(picker)
/**
* # tgui_color_picker
*
* Datum used for instantiating and using a TGUI-controlled color picker.
*/
/datum/tgui_color_picker
/// The title of the TGUI window
var/title
/// The message to show the user
var/message
/// The default choice, used if there is an existing value
var/default
/// The color the user selected, null if no selection has been made
var/choice
/// The time at which the tgui_color_picker was created, for displaying timeout progress.
var/start_time
/// The lifespan of the tgui_color_picker, after which the window will close and delete itself.
var/timeout
/// The bool that controls if this modal should grab window focus
var/autofocus
/// Boolean field describing if the tgui_color_picker was closed by the user.
var/closed
/datum/tgui_color_picker/New(mob/user, message, title, default, timeout, autofocus)
src.autofocus = autofocus
src.title = title
src.default = default
src.message = message
if (timeout)
src.timeout = timeout
start_time = world.time
QDEL_IN(src, timeout)
/datum/tgui_color_picker/Destroy(force)
SStgui.close_uis(src)
. = ..()
/**
* Waits for a user's response to the tgui_color_picker's prompt before returning. Returns early if
* the window was closed by the user.
*/
/datum/tgui_color_picker/proc/wait()
while (!choice && !closed && !QDELETED(src))
stoplag(1)
/datum/tgui_color_picker/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ColorPickerModal")
ui.open()
ui.set_autoupdate(timeout > 0)
/datum/tgui_color_picker/tgui_close(mob/user)
. = ..()
closed = TRUE
/datum/tgui_color_picker/tgui_state(mob/user)
return GLOB.tgui_always_state
/datum/tgui_color_picker/tgui_static_data(mob/user)
. = list()
.["autofocus"] = autofocus
.["large_buttons"] = !user.client?.prefs || user.client.prefs.read_preference(/datum/preference/toggle/tgui_large_buttons)
.["swapped_buttons"] = !user.client?.prefs || user.client.prefs.read_preference(/datum/preference/toggle/tgui_swapped_buttons)
.["title"] = title
.["default_color"] = default
.["message"] = message
/datum/tgui_color_picker/tgui_data(mob/user)
. = list()
if(timeout)
.["timeout"] = CLAMP01((timeout - (world.time - start_time) - 1 SECONDS) / (timeout - 1 SECONDS))
.["presets"] = user.read_preference(/datum/preference/text/preset_colors)
/datum/tgui_color_picker/tgui_act(action, list/params, datum/tgui/ui)
. = ..()
if (.)
return
switch(action)
if("submit")
var/raw_data = lowertext(params["entry"])
var/hex = sanitize_hexcolor(raw_data)
if (!hex)
return
set_choice(hex)
closed = TRUE
SStgui.close_uis(src)
return TRUE
if("cancel")
closed = TRUE
SStgui.close_uis(src)
return TRUE
if("null")
set_choice(null)
SStgui.close_uis(src)
return TRUE
if("preset")
if(ui.user)
var/raw_data = lowertext(params["color"])
var/index = lowertext(params["index"])
var/colors = ui.user.read_preference(/datum/preference/text/preset_colors)
var/list/entries = splittext(colors, ";")
while(LAZYLEN(entries) < 20)
entries += "#FFFFFF"
if(LAZYLEN(entries) > 20)
entries.Cut(21)
var/hex = sanitize_hexcolor(raw_data)
if (!hex || !isnum(index) || entries[index] == hex)
return
entries[index] = hex
ui.user.write_preference_directly(/datum/preference/text/preset_colors, entries.Join(";"))
return TRUE
/datum/tgui_color_picker/proc/set_choice(choice)
src.choice = choice
+2 -2
View File
@@ -46,9 +46,9 @@
paint_color = rgb(rand(1,255),rand(1,255),rand(1,255))
. = ..()
/obj/vehicle/bike/attackby(obj/item/W as obj, mob/user as mob)
/obj/vehicle/bike/attackby(obj/item/W, mob/user)
if(istype(W, /obj/item/multitool) && open)
var/new_paint = input(usr, "Please select paint color.", "Paint Color", paint_color) as color|null
var/new_paint = tgui_color_picker(user, "Please select paint color.", "Paint Color", paint_color)
if(new_paint)
paint_color = new_paint
update_icon()
+4 -4
View File
@@ -88,9 +88,9 @@
if(8)
pixel_y = 0
/obj/vehicle/train/engine/quadbike/attackby(obj/item/W as obj, mob/user as mob)
/obj/vehicle/train/engine/quadbike/attackby(obj/item/W, mob/user)
if(istype(W, /obj/item/multitool) && open)
var/new_paint = input(usr, "Please select paint color.", "Paint Color", paint_color) as color|null
var/new_paint = tgui_color_picker(user, "Please select paint color.", "Paint Color", paint_color)
if(new_paint)
paint_color = new_paint
update_icon()
@@ -276,9 +276,9 @@
Bodypaint.color = paint_color
add_overlay(Bodypaint)
/obj/vehicle/train/trolley/trailer/attackby(obj/item/W as obj, mob/user as mob)
/obj/vehicle/train/trolley/trailer/attackby(obj/item/W, mob/user)
if(istype(W, /obj/item/multitool) && open)
var/new_paint = input(usr, "Please select paint color.", "Paint Color", paint_color) as color|null
var/new_paint = tgui_color_picker(user, "Please select paint color.", "Paint Color", paint_color)
if(new_paint)
paint_color = new_paint
update_icon()
+8 -8
View File
@@ -676,7 +676,7 @@ var/global/list/belly_colorable_only_fullscreens = list("a_synth_flesh_mono",
if("set_vs_color")
var/belly_choice = tgui_input_list(ui.user, "Which vore sprite are you going to edit the color of?", "Vore Sprite Color", host.vore_icon_bellies)
if(belly_choice)
var/newcolor = input(ui.user, "Choose a color.", "", host.vore_sprite_color[belly_choice]) as color|null
var/newcolor = tgui_color_picker(ui.user, "Choose a color.", "", host.vore_sprite_color[belly_choice])
if(newcolor)
host.vore_sprite_color[belly_choice] = newcolor
var/multiply = tgui_input_list(ui.user, "Set the color to be applied multiplicatively or additively? Currently in [host.vore_sprite_multiply[belly_choice] ? "Multiply" : "Add"]", "Vore Sprite Color", list("Multiply", "Add"))
@@ -1724,17 +1724,17 @@ var/global/list/belly_colorable_only_fullscreens = list("a_synth_flesh_mono",
host.vore_selected.clear_preview(host) //Clears the stomach overlay. This is a failsafe but shouldn't occur.
. = TRUE
if("b_fullscreen_color")
var/newcolor = input(user, "Choose a color.", "", host.vore_selected.belly_fullscreen_color) as color|null
var/newcolor = tgui_color_picker(user, "Choose a color.", "", host.vore_selected.belly_fullscreen_color)
if(newcolor)
host.vore_selected.belly_fullscreen_color = newcolor
. = TRUE
if("b_fullscreen_color_secondary")
var/newcolor = input(user, "Choose a color.", "", host.vore_selected.belly_fullscreen_color_secondary) as color|null
var/newcolor = tgui_color_picker(user, "Choose a color.", "", host.vore_selected.belly_fullscreen_color_secondary)
if(newcolor)
host.vore_selected.belly_fullscreen_color_secondary = newcolor
. = TRUE
if("b_fullscreen_color_trinary")
var/newcolor = input(user, "Choose a color.", "", host.vore_selected.belly_fullscreen_color_trinary) as color|null
var/newcolor = tgui_color_picker(user, "Choose a color.", "", host.vore_selected.belly_fullscreen_color_trinary)
if(newcolor)
host.vore_selected.belly_fullscreen_color_trinary = newcolor
. = TRUE
@@ -1867,7 +1867,7 @@ var/global/list/belly_colorable_only_fullscreens = list("a_synth_flesh_mono",
host.update_fullness()
host.updateVRPanel()
if("b_undergarment_color")
var/newcolor = input(user, "Choose a color.", "", host.vore_selected.undergarment_color) as color|null
var/newcolor = tgui_color_picker(user, "Choose a color.", "", host.vore_selected.undergarment_color)
if(newcolor)
host.vore_selected.undergarment_color = newcolor
host.update_fullness()
@@ -1880,17 +1880,17 @@ var/global/list/belly_colorable_only_fullscreens = list("a_synth_flesh_mono",
host.vore_selected.tail_to_change_to = tail_choice
. = TRUE
if("b_tail_color")
var/newcolor = input(user, "Choose tail color.", "", host.vore_selected.tail_colouration) as color|null
var/newcolor = tgui_color_picker(user, "Choose tail color.", "", host.vore_selected.tail_colouration)
if(newcolor)
host.vore_selected.tail_colouration = newcolor
. = TRUE
if("b_tail_color2")
var/newcolor = input(user, "Choose tail secondary color.", "", host.vore_selected.tail_extra_overlay) as color|null
var/newcolor = tgui_color_picker(user, "Choose tail secondary color.", "", host.vore_selected.tail_extra_overlay)
if(newcolor)
host.vore_selected.tail_extra_overlay = newcolor
. = TRUE
if("b_tail_color3")
var/newcolor = input(user, "Choose tail tertiary color.", "", host.vore_selected.tail_extra_overlay2) as color|null
var/newcolor = tgui_color_picker(user, "Choose tail tertiary color.", "", host.vore_selected.tail_extra_overlay2)
if(newcolor)
host.vore_selected.tail_extra_overlay2 = newcolor
. = TRUE
@@ -147,7 +147,7 @@
set src in oview(1)
if(ismouse(usr) || (isobserver(usr) && !CONFIG_GET(flag/ghost_interaction)))
return
var/new_color = input(usr, "Please select color.", "Paint Color", color) as color|null
var/new_color = tgui_color_picker(usr, "Please select color.", "Paint Color", color)
color = new_color
return
@@ -307,7 +307,7 @@
set src in oview(1)
if(ismouse(usr) || (isobserver(usr) && !CONFIG_GET(flag/ghost_interaction)))
return
var/new_color = input(usr, "Please select color.", "Paint Color", color) as color|null
var/new_color = tgui_color_picker(usr, "Please select color.", "Paint Color", color)
color = new_color
return
+415
View File
@@ -0,0 +1,415 @@
/*
* MIT License
* https://github.com/omgovich/react-colorful/
*
* Copyright (c) 2020 Vlad Shilov <omgovich@ya.ru>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
const round = (
number: number,
digits = 0,
base = Math.pow(10, digits),
): number => {
return Math.round(base * number) / base;
};
export interface RgbColor {
r: number;
g: number;
b: number;
}
export interface RgbaColor extends RgbColor {
a: number;
}
export interface HslColor {
h: number;
s: number;
l: number;
}
export interface HslaColor extends HslColor {
a: number;
}
export interface HsvColor {
h: number;
s: number;
v: number;
}
export interface HsvaColor extends HsvColor {
a: number;
}
export type ObjectColor =
| RgbColor
| HslColor
| HsvColor
| RgbaColor
| HslaColor
| HsvaColor;
export type AnyColor = string | ObjectColor;
/**
* Valid CSS <angle> units.
* https://developer.mozilla.org/en-US/docs/Web/CSS/angle
*/
const angleUnits: Record<string, number> = {
grad: 360 / 400,
turn: 360,
rad: 360 / (Math.PI * 2),
};
export const hexToHsva = (hex: string): HsvaColor => rgbaToHsva(hexToRgba(hex));
export const hexToRgba = (hex: string): RgbaColor => {
if (hex[0] === '#') hex = hex.substring(1);
if (hex.length < 6) {
return {
r: parseInt(hex[0] + hex[0], 16),
g: parseInt(hex[1] + hex[1], 16),
b: parseInt(hex[2] + hex[2], 16),
a: hex.length === 4 ? round(parseInt(hex[3] + hex[3], 16) / 255, 2) : 1,
};
}
return {
r: parseInt(hex.substring(0, 2), 16),
g: parseInt(hex.substring(2, 4), 16),
b: parseInt(hex.substring(4, 6), 16),
a: hex.length === 8 ? round(parseInt(hex.substring(6, 8), 16) / 255, 2) : 1,
};
};
export const parseHue = (value: string, unit = 'deg'): number => {
return Number(value) * (angleUnits[unit] || 1);
};
export const hslaStringToHsva = (hslString: string): HsvaColor => {
const matcher =
/hsla?\(?\s*(-?\d*\.?\d+)(deg|rad|grad|turn)?[,\s]+(-?\d*\.?\d+)%?[,\s]+(-?\d*\.?\d+)%?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i;
const match = matcher.exec(hslString);
if (!match) return { h: 0, s: 0, v: 0, a: 1 };
return hslaToHsva({
h: parseHue(match[1], match[2]),
s: Number(match[3]),
l: Number(match[4]),
a: match[5] === undefined ? 1 : Number(match[5]) / (match[6] ? 100 : 1),
});
};
export const hslStringToHsva = hslaStringToHsva;
export const hslaToHsva = ({ h, s, l, a }: HslaColor): HsvaColor => {
s *= (l < 50 ? l : 100 - l) / 100;
return {
h: h,
s: s > 0 ? ((2 * s) / (l + s)) * 100 : 0,
v: l + s,
a,
};
};
export const hsvaToHex = (hsva: HsvaColor): string =>
rgbaToHex(hsvaToRgba(hsva));
export const hsvaToHsla = ({ h, s, v, a }: HsvaColor): HslaColor => {
const hh = ((200 - s) * v) / 100;
return {
h: round(h),
s: round(
hh > 0 && hh < 200
? ((s * v) / 100 / (hh <= 100 ? hh : 200 - hh)) * 100
: 0,
),
l: round(hh / 2),
a: round(a, 2),
};
};
export const hsvaToHslString = (hsva: HsvaColor): string => {
const { h, s, l } = hsvaToHsla(hsva);
return `hsl(${h}, ${s}%, ${l}%)`;
};
export const hsvaToHsvString = (hsva: HsvaColor): string => {
const { h, s, v } = roundHsva(hsva);
return `hsv(${h}, ${s}%, ${v}%)`;
};
export const hsvaToHsvaString = (hsva: HsvaColor): string => {
const { h, s, v, a } = roundHsva(hsva);
return `hsva(${h}, ${s}%, ${v}%, ${a})`;
};
export const hsvaToHslaString = (hsva: HsvaColor): string => {
const { h, s, l, a } = hsvaToHsla(hsva);
return `hsla(${h}, ${s}%, ${l}%, ${a})`;
};
export const hsvaToRgba = ({ h, s, v, a }: HsvaColor): RgbaColor => {
h = (h / 360) * 6;
s = s / 100;
v = v / 100;
const hh = Math.floor(h),
b = v * (1 - s),
c = v * (1 - (h - hh) * s),
d = v * (1 - (1 - h + hh) * s),
module = hh % 6;
return {
r: [v, c, b, b, d, v][module] * 255,
g: [d, v, v, c, b, b][module] * 255,
b: [b, b, d, v, v, c][module] * 255,
a: round(a, 2),
};
};
export const hsvaToRgbString = (hsva: HsvaColor): string => {
const { r, g, b } = hsvaToRgba(hsva);
return `rgb(${round(r)}, ${round(g)}, ${round(b)})`;
};
export const hsvaToRgbaString = (hsva: HsvaColor): string => {
const { r, g, b, a } = hsvaToRgba(hsva);
return `rgba(${round(r)}, ${round(g)}, ${round(b)}, ${round(a, 2)})`;
};
export const hsvaStringToHsva = (hsvString: string): HsvaColor => {
const matcher =
/hsva?\(?\s*(-?\d*\.?\d+)(deg|rad|grad|turn)?[,\s]+(-?\d*\.?\d+)%?[,\s]+(-?\d*\.?\d+)%?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i;
const match = matcher.exec(hsvString);
if (!match) return { h: 0, s: 0, v: 0, a: 1 };
return roundHsva({
h: parseHue(match[1], match[2]),
s: Number(match[3]),
v: Number(match[4]),
a: match[5] === undefined ? 1 : Number(match[5]) / (match[6] ? 100 : 1),
});
};
export const hsvStringToHsva = hsvaStringToHsva;
export const rgbaStringToHsva = (rgbaString: string): HsvaColor => {
const matcher =
/rgba?\(?\s*(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i;
const match = matcher.exec(rgbaString);
if (!match) return { h: 0, s: 0, v: 0, a: 1 };
return rgbaToHsva({
r: Number(match[1]) / (match[2] ? 100 / 255 : 1),
g: Number(match[3]) / (match[4] ? 100 / 255 : 1),
b: Number(match[5]) / (match[6] ? 100 / 255 : 1),
a: match[7] === undefined ? 1 : Number(match[7]) / (match[8] ? 100 : 1),
});
};
export const rgbStringToHsva = rgbaStringToHsva;
const format = (number: number) => {
const hex = number.toString(16);
return hex.length < 2 ? '0' + hex : hex;
};
export const rgbaToHex = ({ r, g, b, a }: RgbaColor): string => {
const alphaHex = a < 1 ? format(round(a * 255)) : '';
return (
'#' + format(round(r)) + format(round(g)) + format(round(b)) + alphaHex
);
};
export const rgbaToHsva = ({ r, g, b, a }: RgbaColor): HsvaColor => {
const max = Math.max(r, g, b);
const delta = max - Math.min(r, g, b);
// prettier-ignore
const hh = delta
? max === r
? (g - b) / delta
: max === g
? 2 + (b - r) / delta
: 4 + (r - g) / delta
: 0;
return {
h: 60 * (hh < 0 ? hh + 6 : hh),
s: max ? (delta / max) * 100 : 0,
v: (max / 255) * 100,
a,
};
};
export const roundHsva = (hsva: HsvaColor): HsvaColor => ({
h: round(hsva.h),
s: round(hsva.s),
v: round(hsva.v),
a: round(hsva.a, 2),
});
export const rgbaToRgb = ({ r, g, b }: RgbaColor): RgbColor => ({ r, g, b });
export const hslaToHsl = ({ h, s, l }: HslaColor): HslColor => ({ h, s, l });
export const hsvaToHsv = (hsva: HsvaColor): HsvColor => {
const { h, s, v } = roundHsva(hsva);
return { h, s, v };
};
const hexMatcher = /^#?([0-9A-F]{3,8})$/i;
export const validHex = (value: string, alpha?: boolean): boolean => {
const match = hexMatcher.exec(value);
const length = match ? match[1].length : 0;
return (
length === 3 || // '#rgb' format
length === 6 || // '#rrggbb' format
(!!alpha && length === 4) || // '#rgba' format
(!!alpha && length === 8) // '#rrggbbaa' format
);
};
// Source for the following luminance and contrast calculation code: https://blog.cristiana.tech/calculating-color-contrast-in-typescript-using-web-content-accessibility-guidelines-wcag
export const luminance = (rgb: RgbColor): number => {
const [r, g, b] = [rgb.r, rgb.g, rgb.b].map((v) => {
v /= 255;
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
});
return r * 0.2126 + g * 0.7152 + b * 0.0722;
};
export const contrast = (
foreground: RgbColor,
background: RgbColor,
): number => {
const foreground_luminance = luminance(foreground);
const background_luminance = luminance(background);
return background_luminance < foreground_luminance
? (background_luminance + 0.05) / (foreground_luminance + 0.05)
: (foreground_luminance + 0.05) / (background_luminance + 0.05);
};
export const colorList = [
['003366', '336699', '3366CC', '003399', '000099', '0000CC', '000066'],
[
'006666',
'006699',
'0099CC',
'0066CC',
'0033CC',
'0000FF',
'3333FF',
'333399',
],
[
'008080',
'009999',
'33CCCC',
'00CCFF',
'0099FF',
'0066FF',
'3366FF',
'3333CC',
'666699',
],
[
'339966',
'00CC99',
'00FFCC',
'00FFFF',
'33CCFF',
'3399FF',
'6699FF',
'6666FF',
'6600FF',
'6600CC',
],
[
'339933',
'00CC66',
'00FF99',
'66FFCC',
'66FFFF',
'66CCFF',
'99CCFF',
'9999FF',
'9966FF',
'9933FF',
'9900FF',
],
[
'006600',
'00CC00',
'00FF00',
'66FF99',
'99FFCC',
'CCFFFF',
'CCECFF',
'CCCCFF',
'CC99FF',
'CC66FF',
'CC00FF',
'9900CC',
],
[
'003300',
'008000',
'33CC33',
'66FF66',
'99FF99',
'CCFFCC',
'FFFFFF',
'FFCCFF',
'FF99FF',
'FF66FF',
'FF00FF',
'CC00CC',
'660066',
],
[
'336600',
'009900',
'66FF33',
'99FF66',
'CCFF99',
'FFFFCC',
'FFCCCC',
'FF99CC',
'FF66CC',
'FF33CC',
'CC0099',
'800080',
],
[
'333300',
'669900',
'99FF33',
'CCFF66',
'FFFF99',
'FFCC99',
'FF9999',
'FF6699',
'FF3399',
'CC3399',
'990099',
],
[
'666633',
'99CC00',
'CCFF33',
'FFFF66',
'FFCC66',
'FF9966',
'FF7C80',
'FF0066',
'D60093',
'993366',
],
[
'808000',
'CCCC00',
'FFFF00',
'FFCC00',
'FF9933',
'FF6600',
'FF5050',
'CC0066',
'660033',
],
[
'996633',
'CC9900',
'FF9900',
'CC6600',
'FF3300',
'FF0000',
'CC0000',
'990033',
],
['663300', '996600', 'CC3300', '993300', '990000', '800000', 'A50021'],
[
'F8F8F8',
'DDDDDD',
'B2B2B2',
'808080',
'5F5F5F',
'333333',
'1C1C1C',
'080808',
],
[
'FFFFFF',
'EAEAEA',
'C0C0C0',
'969696',
'777777',
'4D4D4D',
'292929',
'111111',
'000000',
],
];
@@ -0,0 +1,143 @@
/**
* MIT License
* https://github.com/omgovich/react-colorful/
*
* Copyright (c) 2020 Vlad Shilov <omgovich@ya.ru>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import { KEY } from 'common/keys';
import { clamp } from 'common/math';
import React, { Component, createRef, ReactNode, RefObject } from 'react';
export interface Interaction {
left: number;
top: number;
}
// Finds the proper window object to fix iframe embedding issues
const getParentWindow = (node?: HTMLDivElement | null): Window => {
return (node && node.ownerDocument.defaultView) || window;
};
// Returns a relative position of the pointer inside the node's bounding box
const getRelativePosition = (
node: HTMLDivElement,
event: MouseEvent,
): Interaction => {
const rect = node.getBoundingClientRect();
const parentWindow = getParentWindow(node);
const offsetX = event.pageX - (rect.left + parentWindow.scrollX);
const offsetY = event.pageY - (rect.top + parentWindow.scrollY);
return {
left: clamp(offsetX / rect.width, 0, 1),
top: clamp(offsetY / rect.height, 0, 1),
};
};
export interface InteractiveProps {
onMove: (interaction: Interaction) => void;
onKey: (offset: Interaction) => void;
children: ReactNode;
style?: React.CSSProperties;
}
export class Interactive extends Component<InteractiveProps> {
containerRef: RefObject<HTMLDivElement>;
constructor(props: InteractiveProps) {
super(props);
this.containerRef = createRef();
}
handleMoveStart = (event: React.MouseEvent<HTMLDivElement>) => {
const el = this.containerRef?.current;
if (!el) return;
// Prevent text selection
event.preventDefault();
el.focus();
this.props.onMove(getRelativePosition(el, event.nativeEvent));
this.toggleDocumentEvents(true);
};
handleMove = (event: MouseEvent) => {
event.preventDefault();
const isDown = event.buttons > 0;
if (isDown && this.containerRef?.current) {
this.props.onMove(getRelativePosition(this.containerRef.current, event));
} else {
this.toggleDocumentEvents(false);
}
};
handleMoveEnd = () => {
this.toggleDocumentEvents(false);
};
handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
const pressedKey = event.key;
if (
pressedKey !== KEY.Left &&
pressedKey !== KEY.Right &&
pressedKey !== KEY.Up &&
pressedKey !== KEY.Down
) {
return;
}
event.preventDefault();
this.props.onKey({
left:
pressedKey === KEY.Right ? 0.05 : pressedKey === KEY.Left ? -0.05 : 0,
top: pressedKey === KEY.Down ? 0.05 : pressedKey === KEY.Up ? -0.05 : 0,
});
};
toggleDocumentEvents(state?: boolean) {
const el = this.containerRef?.current;
const parentWindow = getParentWindow(el);
const toggleEvent = state
? parentWindow.addEventListener
: parentWindow.removeEventListener;
toggleEvent('mousemove', this.handleMove);
toggleEvent('mouseup', this.handleMoveEnd);
}
componentDidMount() {
this.toggleDocumentEvents(true);
}
componentWillUnmount() {
this.toggleDocumentEvents(false);
}
render() {
const { style, children, ...rest } = this.props;
return (
<div
{...rest}
style={style}
ref={this.containerRef}
onMouseDown={this.handleMoveStart}
className="react-colorful__interactive"
onKeyDown={this.handleKeyDown}
tabIndex={0}
role="slider"
>
{children}
</div>
);
}
}
+46
View File
@@ -0,0 +1,46 @@
/**
* MIT License
* https://github.com/omgovich/react-colorful/
*
* Copyright (c) 2020 Vlad Shilov <omgovich@ya.ru>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import { classes } from 'common/react';
import React from 'react';
interface PointerProps {
className?: string;
top?: number;
left: number;
color: string;
}
export const Pointer: React.FC<PointerProps> = ({
className,
color,
left,
top = 0.5,
}) => {
const nodeClassName = classes(['react-colorful__pointer', className]);
const style = {
top: `${top * 100}%`,
left: `${left * 100}%`,
};
return (
<div className={nodeClassName} style={style}>
<div
className="react-colorful__pointer-fill"
style={{ backgroundColor: color }}
/>
</div>
);
};
+2
View File
@@ -21,6 +21,7 @@ export { Icon } from './Icon';
export { Image } from './Image';
export { InfinitePlane } from './InfinitePlane';
export { Input } from './Input';
export { Interactive } from './Interactive';
export { Knob } from './Knob';
export { LabeledControls } from './LabeledControls';
export { LabeledList } from './LabeledList';
@@ -28,6 +29,7 @@ export { Modal } from './Modal';
export { NanoMap } from './NanoMap';
export { NoticeBox } from './NoticeBox';
export { NumberInput } from './NumberInput';
export { Pointer } from './Pointer';
export { Popper } from './Popper';
export { ProgressBar } from './ProgressBar';
export { RestrictedInput } from './RestrictedInput';
@@ -0,0 +1,888 @@
/**
* @file
* @copyright 2023 itsmeow
* @license MIT
*/
import {
colorList,
hexToHsva,
HsvaColor,
hsvaToHex,
hsvaToHslString,
hsvaToRgba,
rgbaToHsva,
validHex,
} from 'common/colorpicker';
import { clamp } from 'common/math';
import { classes } from 'common/react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Pointer } from 'tgui/components';
import { Interaction, Interactive } from 'tgui/components/Interactive';
import {
Box,
Button,
Flex,
NumberInput,
Section,
Stack,
Tooltip,
} from 'tgui-core/components';
import { useBackend } from '../backend';
import { Autofocus } from '../components/Autofocus';
import { Window } from '../layouts';
import { InputButtons } from './common/InputButtons';
import { Loader } from './common/Loader';
interface ColorPickerData {
autofocus: boolean;
buttons: string[];
message: string;
large_buttons: boolean;
swapped_buttons: boolean;
timeout: number;
title: string;
default_color: string;
presets: string;
}
interface ColorPickerModalProps {}
export const ColorPickerModal: React.FC<ColorPickerModalProps> = () => {
const { act, data } = useBackend<ColorPickerData>();
const {
timeout,
message,
autofocus,
default_color = '#000000',
presets = '',
} = data;
let { title } = data;
const [selectedColor, setSelectedColor] = useState<HsvaColor>(
hexToHsva(default_color),
);
const [lastSelectedColor, setLastSelectedColor] = useState<string>('');
const [allowEditing, setAllowEditing] = useState<boolean>(false);
useEffect(() => {
setSelectedColor(hexToHsva(default_color));
}, [default_color]);
useEffect(() => {
const hexCol = hsvaToHex(selectedColor);
if (
selectedPreset !== undefined &&
lastSelectedColor !== hexCol &&
allowEditing
) {
setLastSelectedColor(hexCol);
act('preset', { color: hexCol, index: selectedPreset + 1 });
}
}, [selectedColor]);
if (!title) {
title = 'Color';
}
const [selectedPreset, setSelectedPreset] = useState<number | undefined>(
undefined,
);
const ourPresets = presets
.replaceAll('#', '')
.replace(/(^;)|(;$)/g, '')
.split(';');
while (ourPresets.length < 20) {
ourPresets.push('FFFFFF');
}
const presetList = ourPresets.reduce(
(input, entry, index) => {
if (index < 10) {
return [[...input[0], entry], input[1]];
} else {
return [input[0], [...input[1], entry]];
}
},
[[], []],
);
return (
<Window
height={message ? 460 : 420}
title={title}
width={600}
theme="generic"
>
{!!timeout && <Loader value={timeout} />}
<Window.Content>
<Stack fill vertical>
{!!autofocus && <Autofocus />}
{message && (
<Stack.Item m={1}>
<Section fill>
<Box color="label" overflow="hidden">
{message}
</Box>
</Section>
</Stack.Item>
)}
<Stack.Item grow>
<Section fill>
<ColorSelector
color={selectedColor}
setColor={setSelectedColor}
defaultColor={default_color}
presetList={presetList}
selectedPreset={selectedPreset}
onSelectedPreset={setSelectedPreset}
allowEditing={allowEditing}
onAllowEditing={setAllowEditing}
/>
</Section>
</Stack.Item>
<Stack.Item>
<InputButtons input={hsvaToHex(selectedColor)} />
</Stack.Item>
</Stack>
</Window.Content>
</Window>
);
};
interface ColorPresetsProps {
setColor: (color: HsvaColor) => void;
setShowPresets: (show: boolean) => void;
presetList: string[][];
selectedPreset: number | undefined;
onSelectedPreset: React.Dispatch<React.SetStateAction<number | undefined>>;
allowEditing: boolean;
onAllowEditing: React.Dispatch<React.SetStateAction<boolean>>;
}
const ColorPresets: React.FC<ColorPresetsProps> = React.memo(
({
setColor,
setShowPresets,
presetList,
selectedPreset,
onSelectedPreset,
allowEditing,
onAllowEditing,
}) => {
return (
<>
<Button
onClick={() => setShowPresets(false)}
position="absolute"
right="4px"
icon="arrow-left"
/>
<Stack justify="center" vertical>
<Stack.Item>
{colorList.map((row, index) => (
<Stack.Item key={index} width="100%">
<Stack justify="center">
{row.map((entry) => (
<Box key={entry} p="1px" backgroundColor="black">
<Box
p="1px"
backgroundColor="#AAAAAA"
onClick={() => {
setColor(hexToHsva(entry));
onSelectedPreset(undefined);
}}
>
<Box
backgroundColor={'#' + entry}
width="21px"
height="14px"
/>
</Box>
</Box>
))}
</Stack>
</Stack.Item>
))}
</Stack.Item>
<Stack.Item>
{presetList.map((row, index) => (
<Stack.Item key={index} grow>
<Stack justify="center">
{row.map((entry, i) => (
<Box key={i} p="1px" backgroundColor="black">
<Box
p="1px"
backgroundColor={
selectedPreset === 10 * index + i
? '#FF0000'
: '#AAAAAA'
}
onClick={() => {
setColor(hexToHsva(entry));
onSelectedPreset(10 * index + i);
}}
>
<Box
backgroundColor={'#' + entry}
width="21px"
height="14px"
/>
</Box>
</Box>
))}
</Stack>
</Stack.Item>
))}
</Stack.Item>
</Stack>
<Button
color={allowEditing ? 'green' : 'red'}
position="absolute"
right="4px"
bottom="4px"
icon="lock"
onClick={() => onAllowEditing(!allowEditing)}
/>
</>
);
},
);
interface ColorSelectorProps {
color: HsvaColor;
setColor: React.Dispatch<React.SetStateAction<HsvaColor>>;
defaultColor: string;
presetList: string[][];
selectedPreset: number | undefined;
onSelectedPreset: React.Dispatch<React.SetStateAction<number | undefined>>;
allowEditing: boolean;
onAllowEditing: React.Dispatch<React.SetStateAction<boolean>>;
}
const ColorSelector: React.FC<ColorSelectorProps> = React.memo(
({
color,
setColor,
defaultColor,
presetList,
selectedPreset,
onSelectedPreset,
allowEditing,
onAllowEditing,
}) => {
const handleChange = useCallback(
(params: Partial<HsvaColor>) => {
setColor((current) => ({ ...current, ...params }));
},
[setColor],
);
const [showPresets, setShowPresets] = useState<boolean>(false);
const rgb = hsvaToRgba(color);
const hexColor = hsvaToHex(color);
return (
<Flex direction="row">
<Flex.Item mr={2}>
<Stack vertical>
<Stack.Item>
<div className="react-colorful">
<SaturationValue hsva={color} onChange={handleChange} />
<Hue
hue={color.h}
onChange={handleChange}
className="react-colorful__last-control"
/>
</div>
</Stack.Item>
<Stack.Item>
<Box inline width="100px" height="20px" textAlign="center">
Current
</Box>
<Box inline width="100px" height="20px" textAlign="center">
Previous
</Box>
<br />
<Tooltip content={hexColor} position="bottom">
<Box
inline
width="100px"
height="30px"
backgroundColor={hexColor}
/>
</Tooltip>
<Tooltip content={defaultColor} position="bottom">
<Box
inline
width="100px"
height="30px"
backgroundColor={defaultColor}
/>
</Tooltip>
</Stack.Item>
</Stack>
</Flex.Item>
<Flex.Item grow fontSize="15px" lineHeight="24px">
{showPresets ? (
<ColorPresets
setColor={(c) => handleChange(c)}
setShowPresets={setShowPresets}
presetList={presetList}
selectedPreset={selectedPreset}
onSelectedPreset={onSelectedPreset}
allowEditing={allowEditing}
onAllowEditing={onAllowEditing}
/>
) : (
<Stack vertical>
<Stack.Item>
<Stack>
<Stack.Item>
<Box textColor="label">Hex:</Box>
</Stack.Item>
<Stack.Item grow height="24px">
<HexColorInput
fluid
color={hsvaToHex(color).substring(1)}
onChange={(value) => {
setColor(hexToHsva(value));
}}
/>
</Stack.Item>
<Stack.Item>
<Button
icon="eye-dropper"
onClick={() => setShowPresets(true)}
/>
</Stack.Item>
</Stack>
</Stack.Item>
<Stack.Divider />
<HueRow color={color} handleChange={handleChange} />
<SaturationRow color={color} handleChange={handleChange} />
<ValueRow color={color} handleChange={handleChange} />
<Stack.Divider />
<RedRow color={color} handleChange={handleChange} />
<GreenRow color={color} handleChange={handleChange} />
<BlueRow color={color} handleChange={handleChange} />
</Stack>
)}
</Flex.Item>
</Flex>
);
},
);
interface RowProps {
color: HsvaColor;
handleChange: (c: Partial<HsvaColor>) => void;
}
const HueRow: React.FC<RowProps> = React.memo(({ color, handleChange }) => (
<Stack.Item>
<Stack>
<Stack.Item width="25px">
<Box textColor="label">H:</Box>
</Stack.Item>
<Stack.Item grow>
<Hue hue={color.h} onChange={handleChange} />
</Stack.Item>
<Stack.Item>
<TextSetter
value={color.h}
callback={(v) => handleChange({ h: v })}
max={360}
unit="°"
/>
</Stack.Item>
</Stack>
</Stack.Item>
));
const SaturationRow: React.FC<RowProps> = React.memo(
({ color, handleChange }) => (
<Stack.Item>
<Stack>
<Stack.Item width="25px">
<Box textColor="label">S:</Box>
</Stack.Item>
<Stack.Item grow>
<Saturation color={color} onChange={handleChange} />
</Stack.Item>
<Stack.Item>
<TextSetter
value={color.s}
callback={(v) => handleChange({ s: v })}
unit="%"
/>
</Stack.Item>
</Stack>
</Stack.Item>
),
);
const ValueRow: React.FC<RowProps> = React.memo(({ color, handleChange }) => (
<Stack.Item>
<Stack>
<Stack.Item width="25px">
<Box textColor="label">V:</Box>
</Stack.Item>
<Stack.Item grow>
<Value color={color} onChange={handleChange} />
</Stack.Item>
<Stack.Item>
<TextSetter
value={color.v}
callback={(v) => handleChange({ v })}
unit="%"
/>
</Stack.Item>
</Stack>
</Stack.Item>
));
interface RGBRowProps {
color: HsvaColor;
handleChange: (c: HsvaColor) => void;
}
const RedRow: React.FC<RGBRowProps> = React.memo(({ color, handleChange }) => {
const rgb = hsvaToRgba(color);
return (
<Stack.Item>
<Stack>
<Stack.Item width="25px">
<Box textColor="label">R:</Box>
</Stack.Item>
<Stack.Item grow>
<RGBSlider color={color} onChange={handleChange} target="r" />
</Stack.Item>
<Stack.Item>
<TextSetter
value={rgb.r}
callback={(v) => {
handleChange(rgbaToHsva({ ...rgb, r: v }));
}}
max={255}
/>
</Stack.Item>
</Stack>
</Stack.Item>
);
});
const GreenRow: React.FC<RGBRowProps> = React.memo(
({ color, handleChange }) => {
const rgb = hsvaToRgba(color);
return (
<Stack.Item>
<Stack>
<Stack.Item width="25px">
<Box textColor="label">G:</Box>
</Stack.Item>
<Stack.Item grow>
<RGBSlider color={color} onChange={handleChange} target="g" />
</Stack.Item>
<Stack.Item>
<TextSetter
value={rgb.g}
callback={(v) => {
handleChange(rgbaToHsva({ ...rgb, g: v }));
}}
max={255}
/>
</Stack.Item>
</Stack>
</Stack.Item>
);
},
);
const BlueRow: React.FC<RGBRowProps> = React.memo(({ color, handleChange }) => {
const rgb = hsvaToRgba(color);
return (
<Stack.Item>
<Stack>
<Stack.Item width="25px">
<Box textColor="label">B:</Box>
</Stack.Item>
<Stack.Item grow>
<RGBSlider color={color} onChange={handleChange} target="b" />
</Stack.Item>
<Stack.Item>
<TextSetter
value={rgb.b}
callback={(v) => {
handleChange(rgbaToHsva({ ...rgb, b: v }));
}}
max={255}
/>
</Stack.Item>
</Stack>
</Stack.Item>
);
});
interface TextSetterProps {
value: number;
callback: (value: number) => void;
min?: number;
max?: number;
unit?: string;
}
const TextSetter: React.FC<TextSetterProps> = React.memo(
({ value, callback, min = 0, max = 100, unit }) => {
return (
<NumberInput
width="70px"
value={Math.round(value)}
step={1}
minValue={min}
maxValue={max}
onChange={callback}
unit={unit}
/>
);
},
);
interface HexColorInputProps {
prefixed?: boolean;
alpha?: boolean;
color: string;
fluid?: boolean;
onChange: (newColor: string) => void;
}
const HexColorInput: React.FC<HexColorInputProps> = React.memo(
({ alpha, color, fluid, onChange, ...rest }) => {
const initialColor = useMemo(() => {
const stripped = color
.replace(/[^0-9A-Fa-f]/g, '')
.substring(0, 6)
.toUpperCase();
return stripped;
}, [color]);
const [localValue, setLocalValue] = useState(initialColor);
useEffect(() => {
setLocalValue(initialColor);
}, [initialColor]);
const isValidFullHex = useCallback(
(val: string) => {
return validHex(val, alpha) && val.length === 6;
},
[alpha],
);
const handleChangeEvent = (e: React.ChangeEvent<HTMLInputElement>) => {
const inputValue = e.currentTarget.value;
const strippedValue = inputValue
.replace(/[^0-9A-Fa-f]/g, '')
.substring(0, 6)
.toUpperCase();
setLocalValue(strippedValue);
if (isValidFullHex(strippedValue)) {
onChange(strippedValue);
}
};
const commitOrRevert = useCallback(() => {
if (isValidFullHex(localValue)) {
onChange(localValue);
} else {
setLocalValue(initialColor);
}
}, [initialColor, isValidFullHex, localValue, onChange]);
const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
commitOrRevert();
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
commitOrRevert();
(e.currentTarget as HTMLInputElement).blur();
}
};
return (
<Box className={classes(['Input', fluid && 'Input--fluid'])}>
<div className="Input__baseline">.</div>
<input
className="Input__input"
value={localValue}
spellCheck={false}
onChange={handleChangeEvent}
onBlur={handleBlur}
onKeyDown={handleKeyDown}
{...rest}
/>
</Box>
);
},
);
interface SaturationValueProps {
hsva: HsvaColor;
onChange: (newColor: Partial<HsvaColor>) => void;
}
const SaturationValue: React.FC<SaturationValueProps> = React.memo(
({ hsva, onChange }) => {
const handleMove = (interaction: Interaction) => {
onChange({
s: interaction.left * 100,
v: 100 - interaction.top * 100,
});
};
const handleKey = (offset: Interaction) => {
onChange({
s: clamp(hsva.s + offset.left * 100, 0, 100),
v: clamp(hsva.v - offset.top * 100, 0, 100),
});
};
const containerStyle = useMemo(
() => ({
backgroundColor: hsvaToHslString({
h: hsva.h,
s: 100,
v: 100,
a: 1,
}),
}),
[hsva.h],
);
return (
<div className="react-colorful__saturation_value" style={containerStyle}>
<Interactive
onMove={handleMove}
onKey={handleKey}
aria-label="Color"
aria-valuetext={`Saturation ${Math.round(
hsva.s,
)}%, Brightness ${Math.round(hsva.v)}%`}
>
<Pointer
className="react-colorful__saturation_value-pointer"
top={1 - hsva.v / 100}
left={hsva.s / 100}
color={hsvaToHslString(hsva)}
/>
</Interactive>
</div>
);
},
);
interface HueProps {
className?: string;
hue: number;
onChange: (newHue: Partial<HsvaColor>) => void;
}
const Hue: React.FC<HueProps> = React.memo(({ className, hue, onChange }) => {
const handleMove = (interaction: Interaction) => {
onChange({ h: 360 * interaction.left });
};
const handleKey = (offset: Interaction) => {
onChange({ h: clamp(hue + offset.left * 360, 0, 360) });
};
const nodeClassName = classes(['react-colorful__hue', className]);
return (
<div className={nodeClassName}>
<Interactive
onMove={handleMove}
onKey={handleKey}
aria-label="Hue"
aria-valuenow={Math.round(hue)}
aria-valuemax={360}
aria-valuemin={0}
>
<Pointer
className="react-colorful__hue-pointer"
left={hue / 360}
color={hsvaToHslString({ h: hue, s: 100, v: 100, a: 1 })}
/>
</Interactive>
</div>
);
});
interface SaturationProps {
className?: string;
color: HsvaColor;
onChange: (newSaturation: Partial<HsvaColor>) => void;
}
const Saturation: React.FC<SaturationProps> = React.memo(
({ className, color, onChange }) => {
const handleMove = (interaction: Interaction) => {
onChange({ s: 100 * interaction.left });
};
const handleKey = (offset: Interaction) => {
onChange({ s: clamp(color.s + offset.left * 100, 0, 100) });
};
const nodeClassName = classes(['react-colorful__saturation', className]);
const background = useMemo(
() =>
`linear-gradient(to right, ${hsvaToHslString({
h: color.h,
s: 0,
v: color.v,
a: 1,
})}, ${hsvaToHslString({ h: color.h, s: 100, v: color.v, a: 1 })})`,
[color],
);
return (
<div className={nodeClassName}>
<Interactive
style={{ background }}
onMove={handleMove}
onKey={handleKey}
aria-label="Saturation"
aria-valuenow={Math.round(color.s)}
aria-valuemax={100}
aria-valuemin={0}
>
<Pointer
className="react-colorful__saturation-pointer"
left={color.s / 100}
color={hsvaToHslString({
h: color.h,
s: color.s,
v: color.v,
a: 1,
})}
/>
</Interactive>
</div>
);
},
);
interface ValueProps {
className?: string;
color: HsvaColor;
onChange: (newValue: Partial<HsvaColor>) => void;
}
const Value: React.FC<ValueProps> = React.memo(
({ className, color, onChange }) => {
const handleMove = (interaction: Interaction) => {
onChange({ v: 100 * interaction.left });
};
const handleKey = (offset: Interaction) => {
onChange({
v: clamp(color.v + offset.left * 100, 0, 100),
});
};
const nodeClassName = classes(['react-colorful__value', className]);
const background = useMemo(
() =>
`linear-gradient(to right, ${hsvaToHslString({
h: color.h,
s: color.s,
v: 0,
a: 1,
})}, ${hsvaToHslString({ h: color.h, s: color.s, v: 100, a: 1 })})`,
[color],
);
return (
<div className={nodeClassName}>
<Interactive
style={{
background,
}}
onMove={handleMove}
onKey={handleKey}
aria-label="Value"
aria-valuenow={Math.round(color.v)}
aria-valuemax={100}
aria-valuemin={0}
>
<Pointer
className="react-colorful__value-pointer"
left={color.v / 100}
color={hsvaToHslString(color)}
/>
</Interactive>
</div>
);
},
);
interface RGBSliderProps {
className?: string;
color: HsvaColor;
onChange: (newValue: HsvaColor) => void;
target: 'r' | 'g' | 'b';
}
const RGBSlider: React.FC<RGBSliderProps> = React.memo(
({ className, color, onChange, target }) => {
const rgb = hsvaToRgba(color);
const setNewTarget = (value: number) => {
const newRgb = { ...rgb, [target]: value };
onChange(rgbaToHsva(newRgb));
};
const handleMove = (interaction: Interaction) => {
setNewTarget(255 * interaction.left);
};
const handleKey = (offset: Interaction) => {
setNewTarget(clamp(rgb[target] + offset.left * 255, 0, 255));
};
const nodeClassName = classes([`react-colorful__${target}`, className]);
const channels = {
r: `rgb(${Math.round(rgb.r)},0,0)`,
g: `rgb(0,${Math.round(rgb.g)},0)`,
b: `rgb(0,0,${Math.round(rgb.b)})`,
};
const selected = channels[target];
return (
<div className={nodeClassName}>
<Interactive
onMove={handleMove}
onKey={handleKey}
aria-valuenow={rgb[target]}
aria-valuemax={255}
aria-valuemin={0}
>
<Pointer
className={`react-colorful__${target}-pointer`}
left={rgb[target] / 255}
color={selected}
/>
</Interactive>
</div>
);
},
);
@@ -7,7 +7,7 @@ import { Window } from '../layouts';
import { OvermapFlightData, OvermapPanControls } from './common/Overmap';
type Data = {
mapRef: string | null;
mapRef: string | undefined;
sector: string;
sector_info: string;
landed: string;
+1 -1
View File
@@ -16,7 +16,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-popper": "^2.3.0",
"tgui-core": "^1.2.0",
"tgui-core": "^1.7.4",
"tgui-dev-server": "workspace:*",
"tgui-polyfill": "workspace:*"
}
@@ -0,0 +1,153 @@
/**
* MIT License
* https://github.com/omgovich/react-colorful/
*
* Copyright (c) 2020 Vlad Shilov <omgovich@ya.ru>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
@use '../colors.scss';
@use '../base.scss';
.react-colorful {
position: relative;
display: flex;
flex-direction: column;
width: 200px;
height: 200px;
user-select: none;
cursor: default;
}
.react-colorful__saturation_value {
position: relative;
flex-grow: 1;
border-color: transparent; /* Fixes https://github.com/omgovich/react-colorful/issues/139 */
border-bottom: 12px solid #000;
border-radius: 8px 8px 0 0;
background-image: linear-gradient(
to top,
rgba(0, 0, 0, 255),
rgba(0, 0, 0, 0)
),
linear-gradient(to right, rgba(255, 255, 255, 255), rgba(255, 255, 255, 0));
}
.react-colorful__pointer-fill,
.react-colorful__alpha-gradient {
content: '';
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
pointer-events: none;
border-radius: inherit;
}
/* Improve elements rendering on light backgrounds */
.react-colorful__alpha-gradient,
.react-colorful__saturation_value {
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.05);
}
.react-colorful__hue,
.react-colorful__r,
.react-colorful__g,
.react-colorful__b,
.react-colorful__alpha,
.react-colorful__saturation,
.react-colorful__value {
position: relative;
height: 24px;
}
.react-colorful__hue {
background: linear-gradient(
to right,
#f00 0%,
#ff0 17%,
#0f0 33%,
#0ff 50%,
#00f 67%,
#f0f 83%,
#f00 100%
);
}
.react-colorful__r {
background: linear-gradient(to right, #000, #f00);
}
.react-colorful__g {
background: linear-gradient(to right, #000, #0f0);
}
.react-colorful__b {
background: linear-gradient(to right, #000, #00f);
}
/* Round bottom corners of the last element: `Hue` for `ColorPicker` or `Alpha` for `AlphaColorPicker` */
.react-colorful__last-control {
border-radius: 0 0 8px 8px;
}
.react-colorful__interactive {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border-radius: inherit;
outline: none;
/* Don't trigger the default scrolling behavior when the event is originating from this element */
touch-action: none;
}
.react-colorful__pointer {
position: absolute;
z-index: 1;
box-sizing: border-box;
width: 28px;
height: 28px;
transform: translate(-50%, -50%);
background-color: #cfcfcf;
border: 2px solid #cfcfcf;
border-radius: 50%;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
}
.react-colorful__interactive:focus .react-colorful__pointer {
transform: translate(-50%, -50%) scale(1.1);
background-color: #fff;
border-color: #fff;
}
/* Chessboard-like pattern for alpha related elements */
.react-colorful__alpha,
.react-colorful__alpha-pointer {
background-color: #fff;
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill-opacity=".05"><rect x="8" width="8" height="8"/><rect y="8" width="8" height="8"/></svg>');
}
.react-colorful__saturation-pointer,
.react-colorful__value-pointer,
.react-colorful__hue-pointer,
.react-colorful__r-pointer,
.react-colorful__g-pointer,
.react-colorful__b-pointer {
z-index: 1;
width: 20px;
height: 20px;
}
/* Display the saturation value pointer over the hue one */
.react-colorful__saturation_value-pointer {
z-index: 3;
}
+1
View File
@@ -52,6 +52,7 @@
@include meta.load-css('./interfaces/AlertModal.scss');
@include meta.load-css('./interfaces/CameraConsole.scss');
@include meta.load-css('./interfaces/Changelog.scss');
@include meta.load-css('./interfaces/ColorPicker.scss');
@include meta.load-css('./interfaces/CrewManifest.scss');
@include meta.load-css('./interfaces/ExperimentConfigure.scss');
@include meta.load-css('./interfaces/FishingMinigame.scss');
+5 -5
View File
@@ -8236,13 +8236,13 @@ __metadata:
languageName: unknown
linkType: soft
"tgui-core@npm:^1.2.0":
version: 1.2.0
resolution: "tgui-core@npm:1.2.0"
"tgui-core@npm:^1.7.4":
version: 1.7.4
resolution: "tgui-core@npm:1.7.4"
peerDependencies:
react: ^18.2.0
react-dom: ^18.2.0
checksum: 10c0/1eead0edbe0df5c49bfa88f0d2caa5df743057be75e9c526d0afd838b8def072c67fe60435c66cba52551c4ef70749d60d68094fa103542187008998002714f7
checksum: 10c0/06b9d8702d6ae170383b28725bf6308cd320499367ea8ea1f9dd5039ab371cfe34419a7d3d1e0e2b86884326e8d4ab116e5601208d2f85d215b7c464fd32fdbf
languageName: node
linkType: hard
@@ -8354,7 +8354,7 @@ __metadata:
react: "npm:^18.2.0"
react-dom: "npm:^18.2.0"
react-popper: "npm:^2.3.0"
tgui-core: "npm:^1.2.0"
tgui-core: "npm:^1.7.4"
tgui-dev-server: "workspace:*"
tgui-polyfill: "workspace:*"
languageName: unknown
+1
View File
@@ -4251,6 +4251,7 @@
#include "code\modules\tgui\states\zlevel.dm"
#include "code\modules\tgui_input\alert.dm"
#include "code\modules\tgui_input\checkboxes.dm"
#include "code\modules\tgui_input\color.dm"
#include "code\modules\tgui_input\list.dm"
#include "code\modules\tgui_input\number.dm"
#include "code\modules\tgui_input\text.dm"