Files

221 lines
6.7 KiB
Plaintext

//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2023 Citadel Station developers. *//
// TODO: generalize this to a tgui helper / whatever, this shouldn't just be for dynamic input modal.
// this will be very useful for rigs & more.
/**
* Helper datum used to build a query for tgui_dynamic_input
* High overhead, technically not necessary, but, this is easy to use as an API.
*/
/datum/tgui_dynamic_query
/// options list
var/list/options = list()
/datum/tgui_dynamic_query/proc/string(key, name, desc, max_length = 512, multi_line = FALSE, default)
RETURN_TYPE(/datum/tgui_dynamic_query)
options[key] = list(
"name" = name,
"desc" = desc,
"default" = default,
"type" = TGUI_INPUT_DATATYPE_TEXT,
"constraints" = list(max_length),
)
return src
/datum/tgui_dynamic_query/proc/number(key, name, desc, min_value = -INFINITY, max_value = INFINITY, round_to, default)
RETURN_TYPE(/datum/tgui_dynamic_query)
options[key] = list(
"name" = name,
"desc" = desc,
"default" = default,
"type" = TGUI_INPUT_DATATYPE_NUM,
"constraints" = list(min_value, max_value, round_to),
)
return src
/datum/tgui_dynamic_query/proc/toggle(key, name, desc, default)
RETURN_TYPE(/datum/tgui_dynamic_query)
options[key] = list(
"name" = name,
"desc" = desc,
"default" = default,
"type" = TGUI_INPUT_DATATYPE_TOGGLE,
"constraints" = list(),
)
return src
/datum/tgui_dynamic_query/proc/pick_one(key, name, desc, list/choices = list(), default)
RETURN_TYPE(/datum/tgui_dynamic_query)
options[key] = list(
"name" = name,
"desc" = desc,
"default" = default,
"type" = TGUI_INPUT_DATATYPE_LIST_PICK,
"constraints" = choices,
)
return src
/**
* builds return list of results
*/
/datum/tgui_dynamic_query/proc/get_results(list/choices)
. = list()
var/got
for(var/key in options)
var/list/params = options[key]
var/val = choices[key]
switch(params[TGUI_INPUT_DATA_TYPE])
if(TGUI_INPUT_DATATYPE_TEXT)
got = isnull(val) ? params[TGUI_INPUT_DATA_DEFAULT] : val
if(!isnull(got))
if(length(got) > params[TGUI_INPUT_DATA_CONSTRAINTS][1])
got = copytext_char(got, 1, params[TGUI_INPUT_DATA_CONSTRAINTS][1] + 1)
.[key] = got
if(TGUI_INPUT_DATATYPE_NUM)
got = isnull(val) ? params[TGUI_INPUT_DATA_DEFAULT] : text2num(val)
if(!isnull(got))
got = clamp(got, params[TGUI_INPUT_DATA_CONSTRAINTS][1], params[TGUI_INPUT_DATA_CONSTRAINTS][2])
if(!isnull(params[TGUI_INPUT_DATA_CONSTRAINTS][3]))
got = round(got, params[TGUI_INPUT_DATA_CONSTRAINTS][3])
.[key] = got
if(TGUI_INPUT_DATATYPE_LIST_PICK)
got = isnull(val) ? params[TGUI_INPUT_DATA_DEFAULT] : val
if(!isnull(got))
if(!(got in params[TGUI_INPUT_DATA_CONSTRAINTS]))
if(length(params[TGUI_INPUT_DATA_CONSTRAINTS]))
got = params[TGUI_INPUT_DATA_CONSTRAINTS][1]
else
got = null
.[key] = got
if(TGUI_INPUT_DATATYPE_TOGGLE)
got = isnull(val) ? params[TGUI_INPUT_DATA_DEFAULT] : val
if(!isnull(got))
got = !!got
.[key] = got
/**
* returns list to be sent to UI
*/
/datum/tgui_dynamic_query/proc/get_query()
return options
/**
* Creates a TGUI input window and returns the user's response
*
* This is used to grab a set of responses to various datatypes.
* This proc blocks until finished.
*
* @params
* * user - who to send this to
* * message - description in interface
* * title - self explanatory
* * query - built query
* * timeout - timeout before menu closes. if it times out, choices will be null.
*
* @return list of key-value pairs (the TGUI_INPUT_DATA_KEY's you put in) associated to values
*/
/proc/tgui_dynamic_input(mob/user, message, title = "Input", datum/tgui_dynamic_query/query, timeout = 0)
var/datum/tgui_dynamic_input/modal = new(user, message, title, query, timeout)
modal.block_on_finished()
return modal.query.get_results(modal.choices)
/**
* Creates a TGUI input window and returns the user's response
*
* This is used to grab a set of responses to various datatypes.
* This proc immediately returns.
*
* @params
* * user - who to send this to
* * message - description in interface
* * title - self explanatory
* * query - built query
* * timeout - timeout before menu closes. if it times out, choices will be null.
* * callback - callback called with first arg being the picked list when we're done.
*
* @return the /datum/tgui_dynamic_input instance created. you should probably not touch this unless you know what you're doing.
*/
/proc/tgui_dynamic_input_async(mob/user, message, title = "Input", datum/tgui_dynamic_query/query, timeout = 0, datum/callback/callback)
return new /datum/tgui_dynamic_input(user, message, title, query, timeout, callback)
/datum/tgui_dynamic_input
/// title of the windo
var/title
/// message that appears inside the window
var/message
/// query datum
var/datum/tgui_dynamic_query/query
/// list of user's choices; null if they haven't picked yet
var/list/choices
/// when we were opened
var/opened_time
/// how long our timeout is; null for infinite
var/timeout
/// did user close us yet? also set to true if we're qdeleted
var/closed
/// callback to invoke on finish
var/datum/callback/callback
/// are we finished? set to true on close, here to prevent double close.
var/finished = FALSE
/datum/tgui_dynamic_input/New(mob/user, message, title, datum/tgui_dynamic_query/query, timeout, datum/callback/callback)
src.title = title
src.message = message
src.query = query
src.timeout = timeout
if(timeout)
QDEL_IN(src, timeout)
src.callback = callback
ui_interact(user)
/datum/tgui_dynamic_input/Destroy()
// 'choices' and 'query' intentionally kept
if(!finished)
finish(null)
closed = TRUE
return ..()
/datum/tgui_dynamic_input/ui_static_data(mob/user, datum/tgui/ui)
. = ..()
.["query"] = query.get_query()
.["title"] = title
.["message"] = message
.["timeout"] = timeout
/datum/tgui_dynamic_input/ui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "UIDynamicInputModal")
ui.set_autoupdate(FALSE)
ui.open()
/datum/tgui_dynamic_input/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state, datum/event_args/actor/actor)
. = ..()
if(.)
return
switch(action)
if("submit")
finish(params["choices"])
return TRUE
if("cancel")
closed = TRUE
SStgui.close_uis(src)
if(!finished)
finish(null)
return TRUE
/datum/tgui_dynamic_input/ui_state()
return GLOB.always_state
/datum/tgui_dynamic_input/proc/block_on_finished()
UNTIL(closed)
return choices
/datum/tgui_dynamic_input/proc/finish(list/choices)
finished = TRUE
choices = query.get_results(choices)
callback?.InvokeAsync(choices)
if(!QDESTROYING(src))
qdel(src)