diff --git a/code/datums/colormate.dm b/code/datums/colormate.dm index c82f09a11c..cfa5a118b2 100644 --- a/code/datums/colormate.dm +++ b/code/datums/colormate.dm @@ -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 diff --git a/code/game/machinery/painter_vr.dm b/code/game/machinery/painter_vr.dm index aaf4d632cf..9c8377e248 100644 --- a/code/game/machinery/painter_vr.dm +++ b/code/game/machinery/painter_vr.dm @@ -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 diff --git a/code/game/machinery/petrification.dm b/code/game/machinery/petrification.dm index 5b061e8006..e7d8a9d51e 100644 --- a/code/game/machinery/petrification.dm +++ b/code/game/machinery/petrification.dm @@ -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") diff --git a/code/game/mecha/combat/fighter.dm b/code/game/mecha/combat/fighter.dm index bdb1c7c96a..8fb6196656 100644 --- a/code/game/mecha/combat/fighter.dm +++ b/code/game/mecha/combat/fighter.dm @@ -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") diff --git a/code/game/mecha/space/shuttle.dm b/code/game/mecha/space/shuttle.dm index b7dd4f35f3..a337d337dd 100644 --- a/code/game/mecha/space/shuttle.dm +++ b/code/game/mecha/space/shuttle.dm @@ -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") diff --git a/code/game/objects/items/devices/floor_painter.dm b/code/game/objects/items/devices/floor_painter.dm index ae9b0a5ed5..644523f8cf 100644 --- a/code/game/objects/items/devices/floor_painter.dm +++ b/code/game/objects/items/devices/floor_painter.dm @@ -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 a new colour.")) diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm index 578279ae0a..4f1b136df4 100644 --- a/code/game/objects/items/devices/gps.dm +++ b/code/game/objects/items/devices/gps.dm @@ -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) diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm index 9a3329b636..266c0c5d89 100644 --- a/code/game/objects/items/devices/lightreplacer.dm +++ b/code/game/objects/items/devices/lightreplacer.dm @@ -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.") diff --git a/code/game/objects/items/devices/personal_shield_generator_vr.dm b/code/game/objects/items/devices/personal_shield_generator_vr.dm index 76cd026389..714ada7d3a 100644 --- a/code/game/objects/items/devices/personal_shield_generator_vr.dm +++ b/code/game/objects/items/devices/personal_shield_generator_vr.dm @@ -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 diff --git a/code/game/objects/items/toys/toys.dm b/code/game/objects/items/toys/toys.dm index 71c96d7b1c..3b19932f3e 100644 --- a/code/game/objects/items/toys/toys.dm +++ b/code/game/objects/items/toys/toys.dm @@ -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() diff --git a/code/game/objects/items/weapons/grenades/smokebomb.dm b/code/game/objects/items/weapons/grenades/smokebomb.dm index 62ebd2ddcb..66c9bb03d9 100644 --- a/code/game/objects/items/weapons/grenades/smokebomb.dm +++ b/code/game/objects/items/weapons/grenades/smokebomb.dm @@ -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 diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm index 7997c6870c..d2e501036b 100644 --- a/code/game/objects/items/weapons/melee/energy.dm +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -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) . = ..() diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm index 1055edef2c..a24869731c 100644 --- a/code/game/objects/items/weapons/shields.dm +++ b/code/game/objects/items/weapons/shields.dm @@ -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() diff --git a/code/game/objects/items/weapons/storage/wallets.dm b/code/game/objects/items/weapons/storage/wallets.dm index f0ddba449d..8fe4e29d6f 100644 --- a/code/game/objects/items/weapons/storage/wallets.dm +++ b/code/game/objects/items/weapons/storage/wallets.dm @@ -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 diff --git a/code/modules/client/preference_setup/general/02_language.dm b/code/modules/client/preference_setup/general/02_language.dm index d796ba9ca2..2b1af1b02e 100644 --- a/code/modules/client/preference_setup/general/02_language.dm +++ b/code/modules/client/preference_setup/general/02_language.dm @@ -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 diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index 18ad76141e..66482747c8 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -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 diff --git a/code/modules/client/preference_setup/loadout/gear_tweaks.dm b/code/modules/client/preference_setup/loadout/gear_tweaks.dm index 5948152129..38c0397f41 100644 --- a/code/modules/client/preference_setup/loadout/gear_tweaks.dm +++ b/code/modules/client/preference_setup/loadout/gear_tweaks.dm @@ -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 \ No newline at end of file +#undef LOADOUT_BAN_STRING diff --git a/code/modules/client/preference_setup/vore/07_traits.dm b/code/modules/client/preference_setup/vore/07_traits.dm index 92909532de..6b803a896c 100644 --- a/code/modules/client/preference_setup/vore/07_traits.dm +++ b/code/modules/client/preference_setup/vore/07_traits.dm @@ -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 diff --git a/code/modules/client/preferences/types/game/ui.dm b/code/modules/client/preferences/types/game/ui.dm index 1d770dc3e7..3f110e0680 100644 --- a/code/modules/client/preferences/types/game/ui.dm +++ b/code/modules/client/preferences/types/game/ui.dm @@ -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 diff --git a/code/modules/client/preferences_tgui.dm b/code/modules/client/preferences_tgui.dm index 068580432c..62c5cb7b03 100644 --- a/code/modules/client/preferences_tgui.dm +++ b/code/modules/client/preferences_tgui.dm @@ -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 diff --git a/code/modules/client/ui_style.dm b/code/modules/client/ui_style.dm index 479d59d181..3baa865c5e 100644 --- a/code/modules/client/ui_style.dm +++ b/code/modules/client/ui_style.dm @@ -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 diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 410b3606a7..909fd1a452 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -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 diff --git a/code/modules/integrated_electronics/core/detailer.dm b/code/modules/integrated_electronics/core/detailer.dm index 7d0a079979..d385387396 100644 --- a/code/modules/integrated_electronics/core/detailer.dm +++ b/code/modules/integrated_electronics/core/detailer.dm @@ -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() \ No newline at end of file + // update_icon() diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm index b7c73a5482..019db4a31a 100644 --- a/code/modules/integrated_electronics/subtypes/input.dm +++ b/code/modules/integrated_electronics/subtypes/input.dm @@ -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() diff --git a/code/modules/mob/living/carbon/human/species/species_shapeshift_vr.dm b/code/modules/mob/living/carbon/human/species/species_shapeshift_vr.dm index 35548d6288..def65e1ffd 100644 --- a/code/modules/mob/living/carbon/human/species/species_shapeshift_vr.dm +++ b/code/modules/mob/living/carbon/human/species/species_shapeshift_vr.dm @@ -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() diff --git a/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm b/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm index 45ca875563..485b16b95c 100644 --- a/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm +++ b/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm @@ -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. diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index ba600401aa..491876c859 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -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 diff --git a/code/modules/mob/living/silicon/pai/pai_vr.dm b/code/modules/mob/living/silicon/pai/pai_vr.dm index 67c4716218..69f5839a15 100644 --- a/code/modules/mob/living/silicon/pai/pai_vr.dm +++ b/code/modules/mob/living/silicon/pai/pai_vr.dm @@ -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() diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm b/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm index 091e655324..1cafcf860f 100644 --- a/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm +++ b/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm @@ -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.")) diff --git a/code/modules/mob/living/silicon/robot/subtypes/thinktank/thinktank_module.dm b/code/modules/mob/living/silicon/robot/subtypes/thinktank/thinktank_module.dm index ebe112a4e8..fca4a2d3f1 100644 --- a/code/modules/mob/living/silicon/robot/subtypes/thinktank/thinktank_module.dm +++ b/code/modules/mob/living/silicon/robot/subtypes/thinktank/thinktank_module.dm @@ -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 diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/catslug.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/catslug.dm index f88ff654a8..4de0146444 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/catslug.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/catslug.dm @@ -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 diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/squirrel.dm b/code/modules/mob/living/simple_mob/subtypes/animal/squirrel.dm index 4ba69741eb..97d79e4290 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/squirrel.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/squirrel.dm @@ -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 diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm b/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm index ec0508f787..3db9acc2cb 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm @@ -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 diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/sect_drone.dm b/code/modules/mob/living/simple_mob/subtypes/vore/sect_drone.dm index 27e6d0e92a..e5b0b92f3b 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/sect_drone.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/sect_drone.dm @@ -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() diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/sect_queen.dm b/code/modules/mob/living/simple_mob/subtypes/vore/sect_queen.dm index 76ab3b915f..2279b31f66 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/sect_queen.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/sect_queen.dm @@ -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() diff --git a/code/modules/overmap/ships/computers/helm.dm b/code/modules/overmap/ships/computers/helm.dm index 0473457bdc..e030e0d7bb 100644 --- a/code/modules/overmap/ships/computers/helm.dm +++ b/code/modules/overmap/ships/computers/helm.dm @@ -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() diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index fc66eb453c..8b4b1266b7 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -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 diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator_vr.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator_vr.dm index e963004064..52203deb1c 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator_vr.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator_vr.dm @@ -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 diff --git a/code/modules/tgui/modules/appearance_changer.dm b/code/modules/tgui/modules/appearance_changer.dm index 3ffd787f42..fad47cc4a8 100644 --- a/code/modules/tgui/modules/appearance_changer.dm +++ b/code/modules/tgui/modules/appearance_changer.dm @@ -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)) diff --git a/code/modules/tgui/modules/overmap.dm b/code/modules/tgui/modules/overmap.dm index 6b7e31a5ab..f26eef3ab5 100644 --- a/code/modules/tgui/modules/overmap.dm +++ b/code/modules/tgui/modules/overmap.dm @@ -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) diff --git a/code/modules/tgui_input/color.dm b/code/modules/tgui_input/color.dm new file mode 100644 index 0000000000..30865c412c --- /dev/null +++ b/code/modules/tgui_input/color.dm @@ -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 diff --git a/code/modules/vehicles/bike.dm b/code/modules/vehicles/bike.dm index 0ced8dc838..e61dd1a065 100644 --- a/code/modules/vehicles/bike.dm +++ b/code/modules/vehicles/bike.dm @@ -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() diff --git a/code/modules/vehicles/quad.dm b/code/modules/vehicles/quad.dm index 4090cca797..2ba4bfca53 100644 --- a/code/modules/vehicles/quad.dm +++ b/code/modules/vehicles/quad.dm @@ -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() diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm index 04ea19e846..46af90ad28 100644 --- a/code/modules/vore/eating/vorepanel_vr.dm +++ b/code/modules/vore/eating/vorepanel_vr.dm @@ -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 diff --git a/code/modules/vore/smoleworld/smoleworld_vr.dm b/code/modules/vore/smoleworld/smoleworld_vr.dm index 7e43c79a21..06aa6b2267 100644 --- a/code/modules/vore/smoleworld/smoleworld_vr.dm +++ b/code/modules/vore/smoleworld/smoleworld_vr.dm @@ -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 diff --git a/tgui/packages/common/colorpicker.tsx b/tgui/packages/common/colorpicker.tsx new file mode 100644 index 0000000000..494ab3ea7f --- /dev/null +++ b/tgui/packages/common/colorpicker.tsx @@ -0,0 +1,415 @@ +/* + * MIT License + * https://github.com/omgovich/react-colorful/ + * + * Copyright (c) 2020 Vlad Shilov + * 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 units. + * https://developer.mozilla.org/en-US/docs/Web/CSS/angle + */ +const angleUnits: Record = { + 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', + ], +]; diff --git a/tgui/packages/tgui/components/Interactive.tsx b/tgui/packages/tgui/components/Interactive.tsx new file mode 100644 index 0000000000..9281ab0dbe --- /dev/null +++ b/tgui/packages/tgui/components/Interactive.tsx @@ -0,0 +1,143 @@ +/** + * MIT License + * https://github.com/omgovich/react-colorful/ + * + * Copyright (c) 2020 Vlad Shilov + * 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 { + containerRef: RefObject; + + constructor(props: InteractiveProps) { + super(props); + this.containerRef = createRef(); + } + + handleMoveStart = (event: React.MouseEvent) => { + 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) => { + 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 ( +
+ {children} +
+ ); + } +} diff --git a/tgui/packages/tgui/components/Pointer.tsx b/tgui/packages/tgui/components/Pointer.tsx new file mode 100644 index 0000000000..1e52cec455 --- /dev/null +++ b/tgui/packages/tgui/components/Pointer.tsx @@ -0,0 +1,46 @@ +/** + * MIT License + * https://github.com/omgovich/react-colorful/ + * + * Copyright (c) 2020 Vlad Shilov + * 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 = ({ + className, + color, + left, + top = 0.5, +}) => { + const nodeClassName = classes(['react-colorful__pointer', className]); + + const style = { + top: `${top * 100}%`, + left: `${left * 100}%`, + }; + + return ( +
+
+
+ ); +}; diff --git a/tgui/packages/tgui/components/index.ts b/tgui/packages/tgui/components/index.ts index 6c17662086..aeb0fc8aa2 100644 --- a/tgui/packages/tgui/components/index.ts +++ b/tgui/packages/tgui/components/index.ts @@ -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'; diff --git a/tgui/packages/tgui/interfaces/ColorPickerModal.tsx b/tgui/packages/tgui/interfaces/ColorPickerModal.tsx new file mode 100644 index 0000000000..89d9883826 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ColorPickerModal.tsx @@ -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 = () => { + const { act, data } = useBackend(); + const { + timeout, + message, + autofocus, + default_color = '#000000', + presets = '', + } = data; + let { title } = data; + + const [selectedColor, setSelectedColor] = useState( + hexToHsva(default_color), + ); + + const [lastSelectedColor, setLastSelectedColor] = useState(''); + const [allowEditing, setAllowEditing] = useState(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( + 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 ( + + {!!timeout && } + + + {!!autofocus && } + {message && ( + +
+ + {message} + +
+
+ )} + +
+ +
+
+ + + +
+
+
+ ); +}; + +interface ColorPresetsProps { + setColor: (color: HsvaColor) => void; + setShowPresets: (show: boolean) => void; + presetList: string[][]; + selectedPreset: number | undefined; + onSelectedPreset: React.Dispatch>; + allowEditing: boolean; + onAllowEditing: React.Dispatch>; +} + +const ColorPresets: React.FC = React.memo( + ({ + setColor, + setShowPresets, + presetList, + selectedPreset, + onSelectedPreset, + allowEditing, + onAllowEditing, + }) => { + return ( + <> +