mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2026-08-22 14:37:49 +01:00
349 lines
11 KiB
Plaintext
349 lines
11 KiB
Plaintext
/*!
|
|
* External tgui definitions, such as src_object APIs.
|
|
*
|
|
* Copyright (c) 2020 Aleksej Komarov
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
/**
|
|
* global
|
|
*
|
|
* Associative list of JSON-encoded shared states that were set by
|
|
* tgui clients.
|
|
*/
|
|
/datum/var/list/tgui_shared_states
|
|
|
|
/**
|
|
* public
|
|
*
|
|
* Used to open and update UIs.
|
|
* If this proc is not implemented properly, the UI will not update correctly.
|
|
*
|
|
* todo: how should i ruin this proc? i don't really like update being twined with opening, but it makes sense..? ~silicons
|
|
*
|
|
* required user mob The mob who opened/is using the UI.
|
|
* optional ui datum/tgui The UI to be updated, if it exists.
|
|
* optional parent_ui datum/tgui A parent UI that, when closed, closes this UI as well.
|
|
*/
|
|
/datum/proc/ui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
|
|
return FALSE // Not implemented.
|
|
|
|
/**
|
|
* public
|
|
*
|
|
* Data to be sent to the UI.
|
|
* This must be implemented for a UI to work.
|
|
*
|
|
* @params
|
|
* * user - (optional) the mob using the UI
|
|
* * ui - (optional) the host tgui
|
|
*
|
|
* return list Data to be sent to the UI.
|
|
*/
|
|
/datum/proc/ui_data(mob/user, datum/tgui/ui)
|
|
return list()
|
|
|
|
/**
|
|
* Gets nested data to be sent to the UI on first launch.
|
|
* * Nested data is 2-deep, instead of the usual data deep. The reducer operates on
|
|
* lists of the given key, allowing you to replace data in nested lists
|
|
* without updating the whole list at once.
|
|
* * Nested data is an advanced concept that the majority of UIs will never need.
|
|
* As such, it is not updated automatically. Use `push_ui_nested_data()` to manually push updates.
|
|
* * This will only be called on initial opens and when static data is being updated.
|
|
*
|
|
* @params
|
|
* * user - (optional) the mob using the UI
|
|
* * ui - (optional) the host tgui
|
|
* @return list of data to send; "key" = list(data), as this is nested data.
|
|
*/
|
|
/datum/proc/ui_nested_data(mob/user, datum/tgui/ui)
|
|
return list()
|
|
|
|
/**
|
|
* public
|
|
*
|
|
* Static Data to be sent to the UI.
|
|
*
|
|
* Static data differs from normal data in that it's large data that should be
|
|
* sent infrequently. This is implemented optionally for heavy uis that would
|
|
* be sending a lot of redundant data frequently. Gets squished into one
|
|
* object on the frontend side, but the static part is cached.
|
|
*
|
|
* @params
|
|
* * user - (optional) the mob using the UI
|
|
* * ui - (optional) the host tgui
|
|
*
|
|
* return list Static Data to be sent to the UI.
|
|
*/
|
|
/datum/proc/ui_static_data(mob/user, datum/tgui/ui)
|
|
return list()
|
|
|
|
/**
|
|
* public
|
|
*
|
|
* Called on an object when a tgui object is being created, allowing you to
|
|
* push various assets to tgui, for examples spritesheets.
|
|
*
|
|
* todo: support file paths
|
|
* todo: this should be sent to embedding interfaces
|
|
*
|
|
* assets may be:
|
|
* * a /datum/asset_pack
|
|
* * typepath of a /datum/asset_pack
|
|
*
|
|
* @params
|
|
* * ui - the UI instance that's being opened
|
|
* * immediate - what assets to load before the window is opened
|
|
* * deferred - what assets to load after the window is opened
|
|
*/
|
|
/datum/proc/ui_asset_injection(datum/tgui/ui, list/immediate, list/deferred)
|
|
return
|
|
|
|
/**
|
|
* public
|
|
*
|
|
* Called on a UI when the UI receieves a href.
|
|
* Think of this as Topic().
|
|
*
|
|
* @params
|
|
* * action - the string of the TGUI-side act() that was invoked by the user
|
|
* * params - the list of key-value parameters of the act() invocation. This is always strings for both key and value!
|
|
* * ui - the TGUI instance invoking this (host window)
|
|
*
|
|
* return bool If the user's input has been handled and the UI should update.
|
|
*/
|
|
/datum/proc/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state, datum/event_args/actor/actor)
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
// If UI is not interactive or usr calling Topic is not the UI user, bail.
|
|
if(!ui || ui.status != UI_INTERACTIVE)
|
|
return TRUE
|
|
|
|
/**
|
|
* private
|
|
*
|
|
* The UI's host object (usually src_object).
|
|
* This allows modules/datums to have the UI attached to them,
|
|
* and be a part of another object.
|
|
*/
|
|
/datum/proc/ui_host(mob/user)
|
|
return src // Default src.
|
|
|
|
/**
|
|
* private
|
|
*
|
|
* The UI's state controller to be used for created uis
|
|
* This is a proc over a var for memory reasons
|
|
*/
|
|
/datum/proc/ui_state(mob/user)
|
|
return GLOB.default_state
|
|
|
|
/**
|
|
* TODO: replace module system with something else
|
|
*
|
|
* Called to route UI act calls to modules.
|
|
*
|
|
* This is a proc so you can override yourself - very useful if you're doing your own module system
|
|
* rather than copy-pasting module code.
|
|
*
|
|
* TODO: get rid of this, we should use parent ui, not the weird modules system we have going on.
|
|
*
|
|
* @params
|
|
* * action - the action string of the ui_act
|
|
* * params - list of string key-values; this is always strings, text2num your number args if needed!
|
|
* * ui - the host window ui datum
|
|
* * id - the module ID of the route request
|
|
*
|
|
* @return TRUE if it was handled by modules.
|
|
*/
|
|
/datum/proc/ui_route(action, list/params, datum/tgui/ui, id)
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
// todo: the fact this is here is probably a bad thing, as it's very poorly documented.
|
|
// this basically matches the useModule<>() hook used on the UI side, because id is null if
|
|
// we're a host window, and not an act call from an embedded component.
|
|
if(!id)
|
|
return ui_act(action, params, ui, ui.state, new /datum/event_args/actor(usr))
|
|
return FALSE
|
|
|
|
/**
|
|
* immediately shunts this data to either an user, an ui, or all users.
|
|
*
|
|
* prefer to use this instead of update_static_data or update_ui_data, because this supports embedding
|
|
* and is generally faster.
|
|
*
|
|
* @params
|
|
* * user - when specified, only pushes this user. else, pushes to all windows.
|
|
* * ui - when specified, only pushes this ui for a given user.
|
|
* * data - list(...) for data. the reducer on tgui-side will only overwrite provided data keys.
|
|
* * nested_data - list(id = list(data...), ...) for nested data. the reducer on tgui-side will only overwrite provided data keys.
|
|
*/
|
|
/datum/proc/push_ui_data(mob/user, datum/tgui/ui, list/data, list/nested_data)
|
|
// todo: the way this works is so jank; this should be COMSIG_DATUM_HOOK_UI_PUSH instead?
|
|
// todo: this is because user, ui, data needs to go to the signal before being auto-resolved, as modules
|
|
// todo: won't necessarily match the values!
|
|
// FUCK
|
|
// ~silicons
|
|
SEND_SIGNAL(src, COMSIG_DATUM_PUSH_UI_DATA, user, ui, data)
|
|
if(!user)
|
|
for (var/datum/tgui/window as anything in open_uis)
|
|
window.push_data(data, nested_data)
|
|
return
|
|
if(!ui)
|
|
ui = SStgui.get_open_ui(user, src)
|
|
if(ui)
|
|
// todo: this is force because otherwise static data can be desynced. should static data be on another proc instead?
|
|
ui.push_data(data, nested_data, TRUE)
|
|
|
|
/**
|
|
* immediately pushes module updates to user, an ui, or all users
|
|
*
|
|
* @params
|
|
* * user - when specified, only pushes this user. else, pushes to all windows.
|
|
* * ui - when specified, only pushes this ui for a given user.
|
|
* * updates - list(id = list(data...), ...) for modules. the reducer on tgui-side will only overwrite provided data keys.
|
|
*/
|
|
/datum/proc/push_ui_nested_data(mob/user, datum/tgui/ui, list/updates)
|
|
if(!user)
|
|
for (var/datum/tgui/window as anything in open_uis)
|
|
window.push_nested_data(updates)
|
|
return
|
|
if(!ui)
|
|
ui = SStgui.get_open_ui(user, src)
|
|
if(ui)
|
|
ui.push_nested_data(updates)
|
|
|
|
/**
|
|
* public
|
|
*
|
|
* Checks the overall UI state for a mob.
|
|
*
|
|
* todo: this is just completely ignored for modules/embedding. is this a good thing? ~silicons
|
|
*
|
|
* @params
|
|
* * user - The mob who opened/is using the UI.
|
|
* * state - The state to check.
|
|
*
|
|
* return UI_state The state of the UI.
|
|
*/
|
|
/datum/proc/ui_status(mob/user, datum/ui_state/state)
|
|
var/src_object = ui_host(user)
|
|
. = UI_CLOSE
|
|
if(!state)
|
|
return
|
|
|
|
if(isobserver(user))
|
|
// If they turn on ghost AI control, admins can always interact.
|
|
// TODO: Can we move this check somewhere else? This can potentially grant access to admin UIs that an admin shouldn't have.
|
|
if(IsAdminGhost(user))
|
|
. = max(., UI_INTERACTIVE)
|
|
|
|
// Regular ghosts can always at least view if in range.
|
|
if(user.client)
|
|
// todo: in view range for zooming
|
|
if(get_dist(src_object, user) < max(CEILING(user.client.current_viewport_width / 2, 1), CEILING(user.client.current_viewport_height / 2, 1)))
|
|
. = max(., UI_UPDATE)
|
|
|
|
// Check if the state allows interaction
|
|
var/result = state.can_use_topic(src_object, user)
|
|
. = max(., result)
|
|
|
|
//* API - Update - Optimizers, look here! *//
|
|
|
|
/**
|
|
* public
|
|
*
|
|
* Forces an update to regular UI data.
|
|
*
|
|
* * If no user is provided, every user will be updated.
|
|
* * Ignores static and nested data.
|
|
*
|
|
* @params
|
|
* * user - (optional) the mob to update
|
|
* * ui - (optional) the /datum/tgui to update
|
|
*/
|
|
/datum/proc/update_ui_data(mob/user, datum/tgui/ui)
|
|
if(isnull(user))
|
|
SStgui.update_uis(src)
|
|
else
|
|
SStgui.try_update_ui(user, src, ui)
|
|
|
|
/**
|
|
* public
|
|
*
|
|
* Forces an update on static data. Should be done manually whenever something
|
|
* happens to change static data.
|
|
*
|
|
* If no user is provided, every user will be updated.
|
|
*
|
|
* optional user the mob currently interacting with the ui
|
|
* optional ui tgui to be updated
|
|
* optional hard_refresh use if you need to block the ui from showing if the refresh queues
|
|
*/
|
|
/datum/proc/update_static_data(mob/user, datum/tgui/ui, hard_refresh)
|
|
if(!user)
|
|
for(var/datum/tgui/window as anything in open_uis)
|
|
window.send_full_update()
|
|
return
|
|
if(!ui)
|
|
ui = SStgui.get_open_ui(user, src)
|
|
if(ui)
|
|
ui.send_full_update()
|
|
|
|
//* Checks *//
|
|
|
|
/**
|
|
* public
|
|
*
|
|
* checks if UIs are open
|
|
*/
|
|
/datum/proc/has_open_ui()
|
|
return length(open_uis)
|
|
|
|
//* Hooks *//
|
|
|
|
/**
|
|
* Called when a new UI is opened with this datum as the host, or when this datum is embedded into another UI.
|
|
*
|
|
* Called once per embed, if multiple windows embedding this datum is transferred. Handle this accordingly!
|
|
*
|
|
* When overriding this, be sure to cast embed_context to the right type for your datum.
|
|
*
|
|
* @params
|
|
* * user - opening mob
|
|
* * ui - the tgui instance
|
|
* * embedded - this was an embedded ui / the datum is being embedded
|
|
*/
|
|
/datum/proc/on_ui_open(mob/user, datum/tgui/ui, embedded)
|
|
SIGNAL_HANDLER
|
|
|
|
/**
|
|
* Called when an UI with this datum as the host is closed, or when an UI is no longer embedding this datum.
|
|
*
|
|
* Called once per embed, if multiple windows embedding this datum is transferred. Handle this accordingly!
|
|
*
|
|
* When overriding this, be sure to cast embed_context to the right type for your datum.
|
|
*
|
|
* @params
|
|
* * user - opening mob
|
|
* * ui - the tgui instance
|
|
* * embedded - this was an embedded ui / the datum is being un-embedded
|
|
*/
|
|
/datum/proc/on_ui_close(mob/user, datum/tgui/ui, embedded)
|
|
SIGNAL_HANDLER
|
|
|
|
/**
|
|
* Called on a UI's object when the UI is transferred from one mob to another.
|
|
*
|
|
* Called once per embed, if multiple windows embedding this datum is transferred. Handle this accordingly!
|
|
*
|
|
* When overriding this, be sure to cast embed_context to the right type for your datum.
|
|
*
|
|
* @params
|
|
* * old_mob - the old mob
|
|
* * new_mob - the new mob
|
|
* * ui - the tgui instance
|
|
* * embedded - this was an embedded transfer
|
|
*/
|
|
/datum/proc/on_ui_transfer(mob/old_mob, mob/new_mob, datum/tgui/ui, embedded)
|
|
return
|