Artur
2020-04-23 09:55:28 +03:00
parent 055606b81b
commit 80b47ec1c0
368 changed files with 29034 additions and 6568 deletions
+113 -104
View File
@@ -1,133 +1,142 @@
/**
* tgui external
*
* Contains all external tgui declarations.
**/
/**
* tgui external
*
* Contains all external tgui declarations.
*/
/**
* public
*
* Used to open and update UIs.
* If this proc is not implemented properly, the UI will not update correctly.
*
* required user mob The mob who opened/is using the UI.
* optional ui_key string The ui_key of the UI.
* optional ui datum/tgui The UI to be updated, if it exists.
* optional force_open bool If the UI should be re-opened instead of updated.
* optional master_ui datum/tgui The parent UI.
* optional state datum/ui_state The state used to determine status.
**/
/**
* public
*
* Used to open and update UIs.
* If this proc is not implemented properly, the UI will not update correctly.
*
* required user mob The mob who opened/is using the UI.
* optional ui_key string The ui_key of the UI.
* optional ui datum/tgui The UI to be updated, if it exists.
* optional force_open bool If the UI should be re-opened instead of updated.
* optional master_ui datum/tgui The parent UI.
* optional state datum/ui_state The state used to determine status.
*/
/datum/proc/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
return FALSE // Not implemented.
/**
* public
*
* Data to be sent to the UI.
* This must be implemented for a UI to work.
*
* required user mob The mob interacting with the UI.
*
* return list Data to be sent to the UI.
**/
/**
* public
*
* Data to be sent to the UI.
* This must be implemented for a UI to work.
*
* required user mob The mob interacting with the UI.
*
* return list Data to be sent to the UI.
*/
/datum/proc/ui_data(mob/user)
return list() // Not implemented.
/**
* 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.
*
* required user mob The mob interacting with the UI.
*
* return list Statuic Data to be sent to the UI.
**/
/**
* 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.
*
* required user mob The mob interacting with the UI.
*
* return list Statuic Data to be sent to the UI.
*/
/datum/proc/ui_static_data(mob/user)
return list()
/**
* public
*
* Forces an update on static data. Should be done manually whenever something happens to change static data.
*
* required user the mob currently interacting with the ui
* optional ui ui to be updated
* optional ui_key ui key of ui to be updated
*
**/
* public
*
* Forces an update on static data. Should be done manually whenever something happens to change static data.
*
* required user the mob currently interacting with the ui
* optional ui ui to be updated
* optional ui_key ui key of ui to be updated
*/
/datum/proc/update_static_data(mob/user, datum/tgui/ui, ui_key = "main")
ui = SStgui.try_update_ui(user, src, ui_key, ui)
// If there was no ui to update, there's no static data to update either.
if(!ui)
return //If there was no ui to update, there's no static data to update either.
return
ui.push_data(null, ui_static_data(), TRUE)
/**
* public
*
* Called on a UI when the UI receieves a href.
* Think of this as Topic().
*
* required action string The action/button that has been invoked by the user.
* required params list A list of parameters attached to the button.
*
* return bool If the UI should be updated or not.
**/
/**
* public
*
* Called on a UI when the UI receieves a href.
* Think of this as Topic().
*
* required action string The action/button that has been invoked by the user.
* required params list A list of parameters attached to the button.
*
* return bool If the UI should be updated or not.
*/
/datum/proc/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
// If UI is not interactive or usr calling Topic is not the UI user, bail.
if(!ui || ui.status != UI_INTERACTIVE)
return 1 // If UI is not interactive or usr calling Topic is not the UI user, bail.
return 1
/**
* public
*
* Called on an object when a tgui object is being created, allowing you to customise the html
* For example: inserting a custom stylesheet that you need in the head
*
* For this purpose, some tags are available in the html, to be parsed out with replacetext
* (customheadhtml) - Additions to the head tag
*
* required html the html base text
*
**/
/**
* public
*
* Called on an object when a tgui object is being created, allowing you to
* customise the html
* For example: inserting a custom stylesheet that you need in the head
*
* For this purpose, some tags are available in the html, to be parsed out
^ with replacetext
* (customheadhtml) - Additions to the head tag
*
* required html the html base text
*/
/datum/proc/ui_base_html(html)
return html
/**
* 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.
**/
/**
* 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.
/**
* global
*
* Used to track UIs for a mob.
**/
/mob/var/list/open_uis = list()
/**
* public
*
* Called on a UI's object when the UI is closed, not to be confused with client/verb/uiclose(), which closes the ui window
*
*
**/
/datum/proc/ui_close()
/**
* global
*
* Associative list of JSON-encoded shared states that were set by
* tgui clients.
*/
/datum/var/list/tgui_shared_states
/**
* verb
*
* Called by UIs when they are closed.
* Must be a verb so winset() can call it.
*
* required uiref ref The UI that was closed.
**/
/**
* global
*
* Used to track UIs for a mob.
*/
/mob/var/list/open_uis = list()
/**
* public
*
* Called on a UI's object when the UI is closed, not to be confused with
* client/verb/uiclose(), which closes the ui window
*/
/datum/proc/ui_close(mob/user)
/**
* verb
*
* Called by UIs when they are closed.
* Must be a verb so winset() can call it.
*
* required uiref ref The UI that was closed.
*/
/client/verb/uiclose(ref as text)
// Name the verb, and hide it from the user panel.
set name = "uiclose"
+55 -55
View File
@@ -1,19 +1,19 @@
/**
* tgui states
*
* Base state and helpers for states. Just does some sanity checks, implement a state for in-depth checks.
**/
/**
* tgui states
*
* Base state and helpers for states. Just does some sanity checks, implement a state for in-depth checks.
*/
/**
* public
*
* Checks the UI state for a mob.
*
* required user mob The mob who opened/is using the UI.
* required state datum/ui_state The state to check.
*
* return UI_state The state of the UI.
**/
/**
* public
*
* Checks the UI state for a mob.
*
* required user mob The mob who opened/is using the UI.
* required state datum/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
@@ -34,27 +34,27 @@
var/result = state.can_use_topic(src_object, user)
. = max(., result)
/**
* private
*
* Checks if a user can use src_object's UI, and returns the state.
* Can call a mob proc, which allows overrides for each mob.
*
* required src_object datum The object/datum which owns the UI.
* required user mob The mob who opened/is using the UI.
*
* return UI_state The state of the UI.
**/
/**
* private
*
* Checks if a user can use src_object's UI, and returns the state.
* Can call a mob proc, which allows overrides for each mob.
*
* required src_object datum The object/datum which owns the UI.
* required user mob The mob who opened/is using the UI.
*
* return UI_state The state of the UI.
*/
/datum/ui_state/proc/can_use_topic(src_object, mob/user)
return UI_CLOSE // Don't allow interaction by default.
/**
* public
*
* Standard interaction/sanity checks. Different mob types may have overrides.
*
* return UI_state The state of the UI.
**/
/**
* public
*
* Standard interaction/sanity checks. Different mob types may have overrides.
*
* return UI_state The state of the UI.
*/
/mob/proc/shared_ui_interaction(src_object)
if(!client) // Close UIs if mindless.
return UI_CLOSE
@@ -75,31 +75,31 @@
return ..()
/**
* public
*
* Check the distance for a living mob.
* Really only used for checks outside the context of a mob.
* Otherwise, use shared_living_ui_distance().
*
* required src_object The object which owns the UI.
* required user mob The mob who opened/is using the UI.
*
* return UI_state The state of the UI.
**/
* public
*
* Check the distance for a living mob.
* Really only used for checks outside the context of a mob.
* Otherwise, use shared_living_ui_distance().
*
* required src_object The object which owns the UI.
* required user mob The mob who opened/is using the UI.
*
* return UI_state The state of the UI.
*/
/atom/proc/contents_ui_distance(src_object, mob/living/user)
return user.shared_living_ui_distance(src_object) // Just call this mob's check.
/**
* public
*
* Distance versus interaction check.
*
* required src_object atom/movable The object which owns the UI.
*
* return UI_state The state of the UI.
**/
/mob/living/proc/shared_living_ui_distance(atom/movable/src_object)
if(!(src_object in view(src))) // If the object is obscured, close it.
/**
* public
*
* Distance versus interaction check.
*
* required src_object atom/movable The object which owns the UI.
*
* return UI_state The state of the UI.
*/
/mob/living/proc/shared_living_ui_distance(atom/movable/src_object, viewcheck = TRUE)
if(viewcheck && !(src_object in view(src))) // If the object is obscured, close it.
return UI_CLOSE
var/dist = get_dist(src_object, src)
+5 -5
View File
@@ -1,8 +1,8 @@
/**
* tgui state: admin_state
*
* Checks that the user is an admin, end-of-story.
**/
/**
* tgui state: admin_state
*
* Checks that the user is an admin, end-of-story.
*/
GLOBAL_DATUM_INIT(admin_state, /datum/ui_state/admin_state, new)
+5 -6
View File
@@ -1,9 +1,8 @@
/**
* tgui state: always_state
*
* Always grants the user UI_INTERACTIVE. Period.
**/
/**
* tgui state: always_state
*
* Always grants the user UI_INTERACTIVE. Period.
*/
GLOBAL_DATUM_INIT(always_state, /datum/ui_state/always_state, new)
+5 -5
View File
@@ -1,8 +1,8 @@
/**
* tgui state: conscious_state
*
* Only checks if the user is conscious.
**/
/**
* tgui state: conscious_state
*
* Only checks if the user is conscious.
*/
GLOBAL_DATUM_INIT(conscious_state, /datum/ui_state/conscious_state, new)
+5 -5
View File
@@ -1,8 +1,8 @@
/**
* tgui state: contained_state
*
* Checks that the user is inside the src_object.
**/
/**
* tgui state: contained_state
*
* Checks that the user is inside the src_object.
*/
GLOBAL_DATUM_INIT(contained_state, /datum/ui_state/contained_state, new)
+5 -5
View File
@@ -1,8 +1,8 @@
/**
* tgui state: deep_inventory_state
*
* Checks that the src_object is in the user's deep (backpack, box, toolbox, etc) inventory.
**/
/**
* tgui state: deep_inventory_state
*
* Checks that the src_object is in the user's deep (backpack, box, toolbox, etc) inventory.
*/
GLOBAL_DATUM_INIT(deep_inventory_state, /datum/ui_state/deep_inventory_state, new)
+5 -5
View File
@@ -1,8 +1,8 @@
/**
* tgui state: default_state
*
* Checks a number of things -- mostly physical distance for humans and view for robots.
**/
/**
* tgui state: default_state
*
* Checks a number of things -- mostly physical distance for humans and view for robots.
*/
GLOBAL_DATUM_INIT(default_state, /datum/ui_state/default, new)
+5 -5
View File
@@ -1,8 +1,8 @@
/**
* tgui state: hands_state
*
* Checks that the src_object is in the user's hands.
**/
/**
* tgui state: hands_state
*
* Checks that the src_object is in the user's hands.
*/
GLOBAL_DATUM_INIT(hands_state, /datum/ui_state/hands_state, new)
+6 -7
View File
@@ -1,10 +1,9 @@
/**
* tgui state: human_adjacent_state
*
* In addition to default checks, only allows interaction for a
* human adjacent user.
**/
/**
* tgui state: human_adjacent_state
*
* In addition to default checks, only allows interaction for a
* human adjacent user.
*/
GLOBAL_DATUM_INIT(human_adjacent_state, /datum/ui_state/human_adjacent_state, new)
+5 -5
View File
@@ -1,8 +1,8 @@
/**
* tgui state: inventory_state
*
* Checks that the src_object is in the user's top-level (hand, ear, pocket, belt, etc) inventory.
**/
/**
* tgui state: inventory_state
*
* Checks that the src_object is in the user's top-level (hand, ear, pocket, belt, etc) inventory.
*/
GLOBAL_DATUM_INIT(inventory_state, /datum/ui_state/inventory_state, new)
+3 -3
View File
@@ -1,6 +1,6 @@
/**
* tgui state: language_menu_state
*/
/**
* tgui state: language_menu_state
*/
GLOBAL_DATUM_INIT(language_menu_state, /datum/ui_state/language_menu, new)
+10 -10
View File
@@ -1,16 +1,16 @@
/**
* tgui state: not_incapacitated_state
*
* Checks that the user isn't incapacitated
**/
/**
* tgui state: not_incapacitated_state
*
* Checks that the user isn't incapacitated
*/
GLOBAL_DATUM_INIT(not_incapacitated_state, /datum/ui_state/not_incapacitated_state, new)
/**
* tgui state: not_incapacitated_turf_state
*
* Checks that the user isn't incapacitated and that their loc is a turf
**/
/**
* tgui state: not_incapacitated_turf_state
*
* Checks that the user isn't incapacitated and that their loc is a turf
*/
GLOBAL_DATUM_INIT(not_incapacitated_turf_state, /datum/ui_state/not_incapacitated_state, new(no_turfs = TRUE))
+5 -5
View File
@@ -1,8 +1,8 @@
/**
* tgui state: notcontained_state
*
* Checks that the user is not inside src_object, and then makes the default checks.
**/
/**
* tgui state: notcontained_state
*
* Checks that the user is not inside src_object, and then makes the default checks.
*/
GLOBAL_DATUM_INIT(notcontained_state, /datum/ui_state/notcontained_state, new)
+5 -5
View File
@@ -1,8 +1,8 @@
/**
* tgui state: observer_state
*
* Checks that the user is an observer/ghost.
**/
/**
* tgui state: observer_state
*
* Checks that the user is an observer/ghost.
*/
GLOBAL_DATUM_INIT(observer_state, /datum/ui_state/observer_state, new)
+31 -5
View File
@@ -1,8 +1,8 @@
/**
* tgui state: physical_state
*
* Short-circuits the default state to only check physical distance.
**/
/**
* tgui state: physical_state
*
* Short-circuits the default state to only check physical distance.
*/
GLOBAL_DATUM_INIT(physical_state, /datum/ui_state/physical, new)
@@ -22,3 +22,29 @@ GLOBAL_DATUM_INIT(physical_state, /datum/ui_state/physical, new)
/mob/living/silicon/ai/physical_can_use_topic(src_object)
return UI_UPDATE // AIs are not physical.
/**
* tgui state: physical_obscured_state
*
* Short-circuits the default state to only check physical distance, being in view doesn't matter
*/
GLOBAL_DATUM_INIT(physical_obscured_state, /datum/ui_state/physical_obscured_state, new)
/datum/ui_state/physical_obscured_state/can_use_topic(src_object, mob/user)
. = user.shared_ui_interaction(src_object)
if(. > UI_CLOSE)
return min(., user.physical_obscured_can_use_topic(src_object))
/mob/proc/physical_obscured_can_use_topic(src_object)
return UI_CLOSE
/mob/living/physical_obscured_can_use_topic(src_object)
return shared_living_ui_distance(src_object, viewcheck = FALSE)
/mob/living/silicon/physical_obscured_can_use_topic(src_object)
return max(UI_UPDATE, shared_living_ui_distance(src_object, viewcheck = FALSE)) // Silicons can always see.
/mob/living/silicon/ai/physical_obscured_can_use_topic(src_object)
return UI_UPDATE // AIs are not physical.
+5 -5
View File
@@ -1,8 +1,8 @@
/**
* tgui state: self_state
*
* Only checks that the user and src_object are the same.
**/
/**
* tgui state: self_state
*
* Only checks that the user and src_object are the same.
*/
GLOBAL_DATUM_INIT(self_state, /datum/ui_state/self_state, new)
+5 -5
View File
@@ -1,8 +1,8 @@
/**
* tgui state: z_state
*
* Only checks that the Z-level of the user and src_object are the same.
**/
/**
* tgui state: z_state
*
* Only checks that the Z-level of the user and src_object are the same.
*/
GLOBAL_DATUM_INIT(z_state, /datum/ui_state/z_state, new)
+111 -111
View File
@@ -1,22 +1,22 @@
/**
* tgui subsystem
*
* Contains all tgui state and subsystem code.
**/
/**
* tgui subsystem
*
* Contains all tgui state and subsystem code.
*/
/**
* public
*
* Get a open UI given a user, src_object, and ui_key and try to update it with data.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object/datum which owns the UI.
* required ui_key string The ui_key of the UI.
* optional ui datum/tgui The UI to be updated, if it exists.
* optional force_open bool If the UI should be re-opened instead of updated.
*
* return datum/tgui The found UI.
**/
/**
* public
*
* Get a open UI given a user, src_object, and ui_key and try to update it with data.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object/datum which owns the UI.
* required ui_key string The ui_key of the UI.
* optional ui datum/tgui The UI to be updated, if it exists.
* optional force_open bool If the UI should be re-opened instead of updated.
*
* return datum/tgui The found UI.
*/
/datum/controller/subsystem/tgui/proc/try_update_ui(mob/user, datum/src_object, ui_key, datum/tgui/ui, force_open = FALSE)
if(isnull(ui)) // No UI was passed, so look for one.
ui = get_open_ui(user, src_object, ui_key)
@@ -31,17 +31,17 @@
else
return null // We couldn't find a UI.
/**
* private
*
* Get a open UI given a user, src_object, and ui_key.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object/datum which owns the UI.
* required ui_key string The ui_key of the UI.
*
* return datum/tgui The found UI.
**/
/**
* private
*
* Get a open UI given a user, src_object, and ui_key.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object/datum which owns the UI.
* required ui_key string The ui_key of the UI.
*
* return datum/tgui The found UI.
*/
/datum/controller/subsystem/tgui/proc/get_open_ui(mob/user, datum/src_object, ui_key)
var/src_object_key = "[REF(src_object)]"
if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
@@ -55,15 +55,15 @@
return null // Couldn't find a UI!
/**
* private
*
* Update all UIs attached to src_object.
*
* required src_object datum The object/datum which owns the UIs.
*
* return int The number of UIs updated.
**/
/**
* private
*
* Update all UIs attached to src_object.
*
* required src_object datum The object/datum which owns the UIs.
*
* return int The number of UIs updated.
*/
/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object)
var/src_object_key = "[REF(src_object)]"
if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
@@ -77,15 +77,15 @@
update_count++ // Count each UI we update.
return update_count
/**
* private
*
* Close all UIs attached to src_object.
*
* required src_object datum The object/datum which owns the UIs.
*
* return int The number of UIs closed.
**/
/**
* private
*
* Close all UIs attached to src_object.
*
* required src_object datum The object/datum which owns the UIs.
*
* return int The number of UIs closed.
*/
/datum/controller/subsystem/tgui/proc/close_uis(datum/src_object)
var/src_object_key = "[REF(src_object)]"
if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
@@ -99,13 +99,13 @@
close_count++ // Count each UI we close.
return close_count
/**
* private
*
* Close *ALL* UIs
*
* return int The number of UIs closed.
**/
/**
* private
*
* Close *ALL* UIs
*
* return int The number of UIs closed.
*/
/datum/controller/subsystem/tgui/proc/close_all_uis()
var/close_count = 0
for(var/src_object_key in open_uis)
@@ -116,17 +116,17 @@
close_count++ // Count each UI we close.
return close_count
/**
* private
*
* Update all UIs belonging to a user.
*
* required user mob The mob who opened/is using the UI.
* optional src_object datum If provided, only update UIs belonging this src_object.
* optional ui_key string If provided, only update UIs with this UI key.
*
* return int The number of UIs updated.
**/
/**
* private
*
* Update all UIs belonging to a user.
*
* required user mob The mob who opened/is using the UI.
* optional src_object datum If provided, only update UIs belonging this src_object.
* optional ui_key string If provided, only update UIs with this UI key.
*
* return int The number of UIs updated.
*/
/datum/controller/subsystem/tgui/proc/update_user_uis(mob/user, datum/src_object = null, ui_key = null)
if(isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
return 0 // Couldn't find any UIs for this user.
@@ -138,17 +138,17 @@
update_count++ // Count each UI we upadte.
return update_count
/**
* private
*
* Close all UIs belonging to a user.
*
* required user mob The mob who opened/is using the UI.
* optional src_object datum If provided, only close UIs belonging this src_object.
* optional ui_key string If provided, only close UIs with this UI key.
*
* return int The number of UIs closed.
**/
/**
* private
*
* Close all UIs belonging to a user.
*
* required user mob The mob who opened/is using the UI.
* optional src_object datum If provided, only close UIs belonging this src_object.
* optional ui_key string If provided, only close UIs with this UI key.
*
* return int The number of UIs closed.
*/
/datum/controller/subsystem/tgui/proc/close_user_uis(mob/user, datum/src_object = null, ui_key = null)
if(isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
return 0 // Couldn't find any UIs for this user.
@@ -160,13 +160,13 @@
close_count++ // Count each UI we close.
return close_count
/**
* private
*
* Add a UI to the list of open UIs.
*
* required ui datum/tgui The UI to be added.
**/
/**
* private
*
* Add a UI to the list of open UIs.
*
* required ui datum/tgui The UI to be added.
*/
/datum/controller/subsystem/tgui/proc/on_open(datum/tgui/ui)
var/src_object_key = "[REF(ui.src_object)]"
if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
@@ -180,15 +180,15 @@
uis |= ui
processing_uis |= ui
/**
* private
*
* Remove a UI from the list of open UIs.
*
* required ui datum/tgui The UI to be removed.
*
* return bool If the UI was removed or not.
**/
/**
* private
*
* Remove a UI from the list of open UIs.
*
* required ui datum/tgui The UI to be removed.
*
* return bool If the UI was removed or not.
*/
/datum/controller/subsystem/tgui/proc/on_close(datum/tgui/ui)
var/src_object_key = "[REF(ui.src_object)]"
if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
@@ -210,28 +210,28 @@
return 1 // Let the caller know we did it.
/**
* private
*
* Handle client logout, by closing all their UIs.
*
* required user mob The mob which logged out.
*
* return int The number of UIs closed.
**/
/**
* private
*
* Handle client logout, by closing all their UIs.
*
* required user mob The mob which logged out.
*
* return int The number of UIs closed.
*/
/datum/controller/subsystem/tgui/proc/on_logout(mob/user)
return close_user_uis(user)
/**
* private
*
* Handle clients switching mobs, by transferring their UIs.
*
* required user source The client's original mob.
* required user target The client's new mob.
*
* return bool If the UIs were transferred.
**/
/**
* private
*
* Handle clients switching mobs, by transferring their UIs.
*
* required user source The client's original mob.
* required user target The client's new mob.
*
* return bool If the UIs were transferred.
*/
/datum/controller/subsystem/tgui/proc/on_transfer(mob/source, mob/target)
if(!source || isnull(source.open_uis) || !istype(source.open_uis, /list) || open_uis.len == 0)
return 0 // The old mob had no open UIs.
+176 -178
View File
@@ -1,12 +1,12 @@
/**
* tgui
*
* /tg/station user interface library
**/
/**
* tgui
*
* /tg/station user interface library
*/
/**
* tgui datum (represents a UI).
**/
/**
* tgui datum (represents a UI).
*/
/datum/tgui
/// The mob who opened/is using the UI.
var/mob/user
@@ -22,8 +22,6 @@
var/width = 0
/// The window height
var/height = 0
/// The style to be used for this UI.
var/style = "nanotrasen"
/// The interface (template) to be used for this UI.
var/interface
/// Update the UI every MC tick.
@@ -34,6 +32,8 @@
var/list/initial_data
/// The static data used to initialize the UI.
var/list/initial_static_data
/// Holder for the json string, that is sent during the initial update
var/_initial_update
/// The status/visibility of the UI.
var/status = UI_INTERACTIVE
/// Topic state used to determine status/interactability.
@@ -42,34 +42,31 @@
var/datum/tgui/master_ui
/// Children of this UI.
var/list/datum/tgui/children = list()
var/custom_browser_id = FALSE
var/ui_screen = "home"
/**
* public
*
* Create a new UI.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object or datum which owns the UI.
* required ui_key string The ui_key of the UI.
* required interface string The interface used to render the UI.
* optional title string The title of the UI.
* optional width int The window width.
* optional height int The window height.
* optional master_ui datum/tgui The parent UI.
* optional state datum/ui_state The state used to determine status.
*
* return datum/tgui The requested UI.
**/
/datum/tgui/New(mob/user, datum/src_object, ui_key, interface, title, width = 0, height = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state, browser_id = null)
/**
* public
*
* Create a new UI.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object or datum which owns the UI.
* required ui_key string The ui_key of the UI.
* required interface string The interface used to render the UI.
* optional title string The title of the UI.
* optional width int The window width.
* optional height int The window height.
* optional master_ui datum/tgui The parent UI.
* optional state datum/ui_state The state used to determine status.
*
* return datum/tgui The requested UI.
*/
/datum/tgui/New(mob/user, datum/src_object, ui_key, interface, title, width = 0, height = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
src.user = user
src.src_object = src_object
src.ui_key = ui_key
src.window_id = browser_id ? browser_id : "[REF(src_object)]-[ui_key]" // DO NOT replace with \ref here. src_object could potentially be tagged
src.custom_browser_id = browser_id ? TRUE : FALSE
set_interface(interface)
// DO NOT replace with \ref here. src_object could potentially be tagged
src.window_id = "[REF(src_object)]-[ui_key]"
src.interface = interface
if(title)
src.title = sanitize(title)
@@ -86,11 +83,11 @@
var/datum/asset/assets = get_asset_datum(/datum/asset/group/tgui)
assets.send(user)
/**
* public
*
* Open this UI (and initialize it with data).
**/
/**
* public
*
* Open this UI (and initialize it with data).
*/
/datum/tgui/proc/open()
if(!user.client)
return // Bail if there is no client.
@@ -99,18 +96,16 @@
if(status < UI_UPDATE)
return // Bail if we're not supposed to open.
var/window_size
if(width && height) // If we have a width and height, use them.
window_size = "size=[width]x[height];"
else
window_size = ""
// Build window options
var/window_options = "can_minimize=0;auto_format=0;"
// If we have a width and height, use them.
if(width && height)
window_options += "size=[width]x[height];"
// Remove titlebar and resize handles for a fancy window
var/have_title_bar
if(user.client.prefs.tgui_fancy)
have_title_bar = "titlebar=0;can_resize=0;"
window_options += "titlebar=0;can_resize=0;"
else
have_title_bar = "titlebar=1;can_resize=1;"
window_options += "titlebar=1;can_resize=1;"
// Generate page html
var/html
@@ -120,50 +115,54 @@
// Replace template tokens with important UI data
// NOTE: Intentional \ref usage; tgui datums can't/shouldn't
// be tagged, so this is an effective unwrap
html = replacetextEx(html, "\[ref]", "\ref[src]")
html = replacetextEx(html, "\[style]", style)
html = replacetextEx(html, "\[tgui:ref]", "\ref[src]")
// Open the window.
user << browse(html, "window=[window_id];can_minimize=0;auto_format=0;[window_size][have_title_bar]")
if (!custom_browser_id)
// Instruct the client to signal UI when the window is closed.
// NOTE: Intentional \ref usage; tgui datums can't/shouldn't
// be tagged, so this is an effective unwrap
winset(user, window_id, "on-close=\"uiclose \ref[src]\"")
user << browse(html, "window=[window_id];[window_options]")
if(!initial_data)
// Instruct the client to signal UI when the window is closed.
// NOTE: Intentional \ref usage; tgui datums can't/shouldn't
// be tagged, so this is an effective unwrap
winset(user, window_id, "on-close=\"uiclose \ref[src]\"")
// Pre-fetch initial state while browser is still loading in
// another thread
if(!initial_data) {
initial_data = src_object.ui_data(user)
if(!initial_static_data)
}
if(!initial_static_data) {
initial_static_data = src_object.ui_static_data(user)
}
_initial_update = url_encode(get_json(initial_data, initial_static_data))
SStgui.on_open(src)
/**
* public
*
* Reinitialize the UI.
* (Possibly with a new interface and/or data).
*
* optional template string The name of the new interface.
* optional data list The new initial data.
**/
/**
* public
*
* Reinitialize the UI.
* (Possibly with a new interface and/or data).
*
* optional template string The name of the new interface.
* optional data list The new initial data.
*/
/datum/tgui/proc/reinitialize(interface, list/data, list/static_data)
if(interface)
set_interface(interface) // Set a new interface.
src.interface = interface
if(data)
initial_data = data
if(static_data)
initial_static_data = static_data
open()
/**
* public
*
* Close the UI, and all its children.
**/
/**
* public
*
* Close the UI, and all its children.
*/
/datum/tgui/proc/close()
user << browse(null, "window=[window_id]") // Close the window.
src_object.ui_close()
src_object.ui_close(user)
SStgui.on_close(src)
for(var/datum/tgui/child in children) // Loop through and close all children.
child.close()
@@ -172,67 +171,49 @@
master_ui = null
qdel(src)
/**
* public
*
* Set the style for this UI.
*
* required style string The new UI style.
**/
/datum/tgui/proc/set_style(style)
src.style = lowertext(style)
/**
* public
*
* Set the interface (template) for this UI.
*
* required interface string The new UI interface.
**/
/datum/tgui/proc/set_interface(interface)
src.interface = lowertext(interface)
/**
* public
*
* Enable/disable auto-updating of the UI.
*
* required state bool Enable/disable auto-updating.
**/
/**
* public
*
* Enable/disable auto-updating of the UI.
*
* required state bool Enable/disable auto-updating.
*/
/datum/tgui/proc/set_autoupdate(state = TRUE)
autoupdate = state
/**
* private
*
* Package the data to send to the UI, as JSON.
* This includes the UI data and config_data.
*
* return string The packaged JSON.
**/
/**
* private
*
* Package the data to send to the UI, as JSON.
* This includes the UI data and config_data.
*
* return string The packaged JSON.
*/
/datum/tgui/proc/get_json(list/data, list/static_data)
var/list/json_data = list()
json_data["config"] = list(
"title" = title,
"status" = status,
"screen" = ui_screen,
"style" = style,
"interface" = interface,
"fancy" = user.client.prefs.tgui_fancy,
"locked" = user.client.prefs.tgui_lock && !custom_browser_id,
"locked" = user.client.prefs.tgui_lock,
"observer" = isobserver(user),
"window" = window_id,
// NOTE: Intentional \ref usage; tgui datums can't/shouldn't
// be tagged, so this is an effective unwrap
"ref" = "\ref[src]"
)
if(!isnull(data))
json_data["data"] = data
if(!isnull(static_data))
json_data["static_data"] = static_data
// Send shared states
if(src_object.tgui_shared_states)
json_data["shared"] = src_object.tgui_shared_states
// Generate the JSON.
var/json = json_encode(json_data)
// Strip #255/improper.
@@ -240,13 +221,13 @@
json = replacetext(json, "\improper", "")
return json
/**
* private
*
* Handle clicks from the UI.
* Call the src_object's ui_act() if status is UI_INTERACTIVE.
* If the src_object's ui_act() returns 1, update all UIs attacked to it.
**/
/**
* private
*
* Handle clicks from the UI.
* Call the src_object's ui_act() if status is UI_INTERACTIVE.
* If the src_object's ui_act() returns 1, update all UIs attacked to it.
*/
/datum/tgui/Topic(href, href_list)
if(user != usr)
return // Something is not right here.
@@ -256,35 +237,47 @@
switch(action)
if("tgui:initialize")
user << output(url_encode(get_json(initial_data, initial_static_data)), "[custom_browser_id ? window_id : "[window_id].browser"]:initialize")
user << output(_initial_update, "[window_id].browser:update")
initialized = TRUE
if("tgui:view")
if(params["screen"])
ui_screen = params["screen"]
if("tgui:setSharedState")
// Update the window state.
update_status(push = FALSE)
// Bail if UI is not interactive or usr calling Topic
// is not the UI user.
if(status != UI_INTERACTIVE)
return
var/key = params["key"]
var/value = params["value"]
if(!src_object.tgui_shared_states)
src_object.tgui_shared_states = list()
src_object.tgui_shared_states[key] = value
SStgui.update_uis(src_object)
if("tgui:setFancy")
var/value = text2num(params["value"])
user.client.prefs.tgui_fancy = value
if("tgui:log")
// Force window to show frills on fatal errors
if(params["fatal"])
winset(user, window_id, "titlebar=1;can-resize=1;size=600x600")
log_message(params["log"])
if("tgui:link")
user << link(params["url"])
if("tgui:fancy")
user.client.prefs.tgui_fancy = TRUE
if("tgui:nofrills")
user.client.prefs.tgui_fancy = FALSE
else
update_status(push = FALSE) // Update the window state.
if(src_object.ui_act(action, params, src, state)) // Call ui_act() on the src_object.
SStgui.update_uis(src_object) // Update if the object requested it.
// Update the window state.
update_status(push = FALSE)
// Call ui_act() on the src_object.
if(src_object.ui_act(action, params, src, state))
// Update if the object requested it.
SStgui.update_uis(src_object)
/**
* private
*
* Update the UI.
* Only updates the data if update is true, otherwise only updates the status.
*
* optional force bool If the UI should be forced to update.
**/
/**
* private
*
* Update the UI.
* Only updates the data if update is true, otherwise only updates the status.
*
* optional force bool If the UI should be forced to update.
*/
/datum/tgui/process(force = FALSE)
var/datum/host = src_object.ui_host(user)
if(!src_object || !host || !user) // If the object or user died (or something else), abort.
@@ -296,42 +289,46 @@
else
update_status(push = TRUE) // Otherwise only update status.
/**
* private
*
* Push data to an already open UI.
*
* required data list The data to send.
* optional force bool If the update should be sent regardless of state.
**/
/**
* private
*
* Push data to an already open UI.
*
* required data list The data to send.
* optional force bool If the update should be sent regardless of state.
*/
/datum/tgui/proc/push_data(data, static_data, force = FALSE)
update_status(push = FALSE) // Update the window state.
// Update the window state.
update_status(push = FALSE)
// Cannot update UI if it is not set up yet.
if(!initialized)
return // Cannot update UI if it is not set up yet.
return
// Cannot update UI, we have no visibility.
if(status <= UI_DISABLED && !force)
return // Cannot update UI, we have no visibility.
return
// Send the new JSON to the update() Javascript function.
user << output(url_encode(get_json(data, static_data)), "[custom_browser_id ? window_id : "[window_id].browser"]:update")
user << output(
url_encode(get_json(data, static_data)),
"[window_id].browser:update")
/**
* private
*
* Updates the UI by interacting with the src_object again, which will hopefully
* call try_ui_update on it.
*
* optional force_open bool If force_open should be passed to ui_interact.
**/
/**
* private
*
* Updates the UI by interacting with the src_object again, which will hopefully
* call try_ui_update on it.
*
* optional force_open bool If force_open should be passed to ui_interact.
*/
/datum/tgui/proc/update(force_open = FALSE)
src_object.ui_interact(user, ui_key, src, force_open, master_ui, state)
/**
* private
*
* Update the status/visibility of the UI for its user.
*
* optional push bool Push an update to the UI (an update is always sent for UI_DISABLED).
**/
/**
* private
*
* Update the status/visibility of the UI for its user.
*
* optional push bool Push an update to the UI (an update is always sent for UI_DISABLED).
*/
/datum/tgui/proc/update_status(push = FALSE)
var/status = src_object.ui_status(user, state)
if(master_ui)
@@ -340,25 +337,26 @@
if(status == UI_CLOSE)
close()
/**
* private
*
* Set the status/visibility of the UI.
*
* required status int The status to set (UI_CLOSE/UI_DISABLED/UI_UPDATE/UI_INTERACTIVE).
* optional push bool Push an update to the UI (an update is always sent for UI_DISABLED).
**/
/**
* private
*
* Set the status/visibility of the UI.
*
* required status int The status to set (UI_CLOSE/UI_DISABLED/UI_UPDATE/UI_INTERACTIVE).
* optional push bool Push an update to the UI (an update is always sent for UI_DISABLED).
*/
/datum/tgui/proc/set_status(status, push = FALSE)
if(src.status != status) // Only update if status has changed.
// Only update if status has changed.
if(src.status != status)
if(src.status == UI_DISABLED)
src.status = status
if(push)
update()
else
src.status = status
if(status == UI_DISABLED || push) // Update if the UI just because disabled, or a push is requested.
// Update if the UI just because disabled, or a push is requested.
if(status == UI_DISABLED || push)
push_data(null, force = TRUE)
/datum/tgui/proc/log_message(message)
log_tgui("[user] ([user.ckey]) using \"[title]\":\n[message]")