NanoUI Goes To Brazil

This commit is contained in:
ShadowLarkens
2020-09-20 02:36:46 -07:00
parent e18fb0fd7e
commit 3f191e4204
150 changed files with 102 additions and 17465 deletions
-22
View File
@@ -1,22 +0,0 @@
SUBSYSTEM_DEF(nanoui)
name = "NanoUI"
wait = 5
flags = SS_NO_INIT
// a list of current open /nanoui UIs, grouped by src_object and ui_key
var/list/open_uis = list()
// a list of current open /nanoui UIs, not grouped, for use in processing
var/list/processing_uis = list()
/datum/controller/subsystem/nanoui/Recover()
if(SSnanoui.open_uis)
open_uis |= SSnanoui.open_uis
if(SSnanoui.processing_uis)
processing_uis |= SSnanoui.processing_uis
/datum/controller/subsystem/nanoui/stat_entry()
return ..("[processing_uis.len] UIs")
/datum/controller/subsystem/nanoui/fire(resumed)
for(var/thing in processing_uis)
var/datum/nanoui/UI = thing
UI.process()
+1 -1
View File
@@ -31,5 +31,5 @@
weakref = null // Clear this reference to ensure it's kept for as brief duration as possible.
tag = null
SSnanoui.close_uis(src)
SStgui.close_uis(src)
return QDEL_HINT_QUEUE
-1
View File
@@ -85,7 +85,6 @@
current.verbs -= /datum/changeling/proc/EvolutionMenu
current.mind = null
SSnanoui.user_transferred(current, new_character) // transfer active NanoUI instances to new user
if(new_character.mind) //remove any mind currently in our new body's mind variable
new_character.mind.current = null
+1 -1
View File
@@ -51,7 +51,7 @@ var/datum/uplink/uplink = new()
if(!can_buy(U))
return
if(U.CanUseTopic(user, inventory_state) != STATUS_INTERACTIVE)
if(U.CanUseTopic(user, GLOB.tgui_inventory_state) != STATUS_INTERACTIVE)
return
var/cost = cost(U.uses, U)
@@ -286,5 +286,5 @@ var/global/list/changeling_fabricated_clothing = list(
if(!registered_user)
registered_user = usr
usr.set_id_info(src)
ui_interact(registered_user)
tgui_interact(registered_user)
..()
+1 -1
View File
@@ -260,7 +260,7 @@ update_flag
..()
SSnanoui.update_uis(src) // Update all NanoUIs attached to src
SStgui.update_uis(src) // Update all NanoUIs attached to src
/obj/machinery/portable_atmospherics/canister/attack_ai(var/mob/user as mob)
return src.attack_hand(user)
+1 -1
View File
@@ -55,7 +55,7 @@
if(!card && user.unEquip(I))
I.forceMove(src)
card = I
SSnanoui.update_uis(src)
SStgui.update_uis(src)
update_icon()
else if(card)
to_chat(user, "<span class='warning'>There is already ID card inside.</span>")
+3 -1
View File
@@ -851,11 +851,13 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/attack_ghost(mob/user)
tgui_interact(user)
/obj/machinery/door/airlock/tgui_interact(mob/user, datum/tgui/ui)
/obj/machinery/door/airlock/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui, datum/tgui_state/custom_state)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "AiAirlock", name)
ui.open()
if(custom_state)
ui.set_state(custom_state)
return TRUE
/obj/machinery/door/airlock/tgui_data(mob/user)
@@ -7,7 +7,6 @@
layer = ABOVE_OBJ_LAYER
var/id_tag
var/datum/topic_state/remote/remote_state
var/obj/machinery/embedded_controller/radio/airlock/master_controller
/obj/machinery/dummy_airlock_controller/process()
@@ -25,15 +24,10 @@
break
if(!master_controller)
qdel(src)
else
remote_state = new /datum/topic_state/remote(src, master_controller)
/obj/machinery/dummy_airlock_controller/Destroy()
if(master_controller)
master_controller.dummy_terminals -= src
if(remote_state)
qdel(remote_state)
remote_state = null
return ..()
/obj/machinery/dummy_airlock_controller/interface_interact(var/mob/user)
-1
View File
@@ -192,7 +192,6 @@
if(inoperable())
to_chat(usr, "\The [src] doesn't appear to function.")
return
ui_interact(user)
tgui_interact(user)
/obj/machinery/media/jukebox/tgui_status(mob/user)
-1
View File
@@ -233,7 +233,6 @@
/obj/machinery/partslathe/attack_hand(mob/user)
if(..())
return
ui_interact(user)
tgui_interact(user)
/obj/machinery/partslathe/ui_assets(mob/user)
+2 -2
View File
@@ -95,7 +95,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
/obj/machinery/pointdefense_control/attackby(var/obj/item/W, var/mob/user)
if(W?.is_multitool())
var/new_ident = input(user, "Enter a new ident tag.", "[src]", id_tag) as null|text
if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, physical_state))
if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, GLOB.tgui_physical_state))
// Check for duplicate controllers with this ID
for(var/thing in pointdefense_controllers)
var/obj/machinery/pointdefense_control/PC = thing
@@ -211,7 +211,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
/obj/machinery/power/pointdefense/attackby(var/obj/item/W, var/mob/user)
if(W?.is_multitool())
var/new_ident = input(user, "Enter a new ident tag.", "[src]", id_tag) as null|text
if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, physical_state))
if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, GLOB.tgui_physical_state))
to_chat(user, "<span class='notice'>You register [src] with the [new_ident] network.</span>")
id_tag = new_ident
return
-1
View File
@@ -104,7 +104,6 @@ var/list/obj/machinery/requests_console/allConsoles = list()
/obj/machinery/requests_console/attack_hand(user as mob)
if(..(user))
return
ui_interact(user)
tgui_interact(user)
/obj/machinery/requests_console/tgui_interact(mob/user, datum/tgui/ui)
+1 -1
View File
@@ -144,6 +144,6 @@
if(!istype(user))
return
if(CanInteract(user, physical_state))
if(CanInteract(user, GLOB.tgui_physical_state))
beep = !beep
to_chat(user, "<span class='notice'>You turn the sound on \the [src] [beep ? "on" : "off"].</span>")
+3 -3
View File
@@ -559,12 +559,12 @@
target.attack_hand(src.occupant)
return 1
if(istype(target, /obj/machinery/embedded_controller))
target.ui_interact(src.occupant)
target.tgui_interact(src.occupant)
return 1
return 0
/obj/mecha/contents_nano_distance(var/src_object, var/mob/living/user)
. = user.shared_living_nano_distance(src_object) //allow them to interact with anything they can interact with normally.
/obj/mecha/contents_tgui_distance(var/src_object, var/mob/living/user)
. = user.shared_living_tgui_distance(src_object) //allow them to interact with anything they can interact with normally.
if(. != STATUS_INTERACTIVE)
//Allow interaction with the mecha or anything that is part of the mecha
if(src_object == src || (src_object in src))
@@ -233,7 +233,6 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
initialize_exonet(user)
alert_called = 0
update_icon()
ui_interact(user) // TGUITODO: Remove
tgui_interact(user)
if(video_source)
watch_video(user)
+7 -6
View File
@@ -5,7 +5,7 @@
var/in_hack_mode = 0
var/list/known_targets
var/list/supported_types
var/datum/topic_state/default/must_hack/hack_state
var/datum/tgui_state/default/must_hack/hack_state
/obj/item/device/multitool/hacktool/New()
..()
@@ -39,7 +39,8 @@
if(!attempt_hack(user, A))
return 0
A.ui_interact(user, state = hack_state)
// Note, if you ever want to expand supported_types, you must manually add the custom state argument to their tgui_interact
A.tgui_interact(user, custom_state = hack_state)
return 1
/obj/item/device/multitool/hacktool/proc/attempt_hack(var/mob/user, var/atom/target)
@@ -83,18 +84,18 @@
/obj/item/device/multitool/hacktool/proc/on_target_destroy(var/target)
known_targets -= target
/datum/topic_state/default/must_hack
/datum/tgui_state/default/must_hack
var/obj/item/device/multitool/hacktool/hacktool
/datum/topic_state/default/must_hack/New(var/hacktool)
/datum/tgui_state/default/must_hack/New(var/hacktool)
src.hacktool = hacktool
..()
/datum/topic_state/default/must_hack/Destroy()
/datum/tgui_state/default/must_hack/Destroy()
hacktool = null
return ..()
/datum/topic_state/default/must_hack/can_use_topic(var/src_object, var/mob/user)
/datum/tgui_state/default/must_hack/can_use_topic(src_object, mob/user)
if(!hacktool || !hacktool.in_hack_mode || !(src_object in hacktool.known_targets))
return STATUS_CLOSE
return ..()
@@ -151,14 +151,6 @@ var/global/list/default_medbay_channels = list(
return tgui_interact(user)
/obj/item/device/radio/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, datum/nano_ui/master_ui, datum/topic_state/state)
log_runtime(EXCEPTION("Warning: [user] attempted to call ui_interact on radio [src] [type]. This is deprecated. Please update the caller to tgui_interact."))
/obj/item/device/radio/Topic(href, href_list)
if(href_list["track"])
log_runtime(EXCEPTION("Warning: Topic() was improperly called on radio [src] [type], with the track href and \[[href] [json_encode(href_list)]]. Please update the caller to use tgui_act."))
. = ..()
/obj/item/device/radio/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
+1 -1
View File
@@ -54,7 +54,7 @@
popup.set_content(jointext(dat,null))
popup.open()
/obj/item/device/tvcamera/Topic(bred, href_list, state = physical_state)
/obj/item/device/tvcamera/Topic(bred, href_list, state = GLOB.tgui_physical_state)
if(..())
return 1
if(href_list["channel"])
+3 -4
View File
@@ -42,7 +42,7 @@
old_turf.unregister_dangerous_object(src)
new_turf.register_dangerous_object(src)
/obj/Topic(href, href_list, var/datum/topic_state/state = default_state)
/obj/Topic(href, href_list, var/datum/tgui_state/state = GLOB.tgui_default_state)
if(usr && ..())
return 1
@@ -55,7 +55,7 @@
CouldNotUseTopic(usr)
return 1
/obj/CanUseTopic(var/mob/user, var/datum/topic_state/state = default_state)
/obj/CanUseTopic(var/mob/user, var/datum/tgui_state/state = GLOB.tgui_default_state)
if(user.CanUseObjTopic(src))
return ..()
to_chat(user, "<span class='danger'>[bicon(src)]Access Denied!</span>")
@@ -69,7 +69,7 @@
return 1
/obj/proc/CouldUseTopic(var/mob/user)
var/atom/host = nano_host()
var/atom/host = tgui_host()
host.add_hiddenprint(user)
/obj/proc/CouldNotUseTopic(var/mob/user)
@@ -135,7 +135,6 @@
in_use = 0
/obj/attack_ghost(mob/user)
ui_interact(user)
tgui_interact(user)
..()
@@ -67,7 +67,7 @@
if(!UWC)
return
var/datum/category_item/underwear/selected_underwear = input(H, "Choose underwear:", "Choose underwear", H.all_underwear[UWC.name]) as null|anything in UWC.items
if(selected_underwear && CanUseTopic(H, default_state))
if(selected_underwear && CanUseTopic(H, GLOB.tgui_default_state))
H.all_underwear[UWC.name] = selected_underwear
H.hide_underwear[UWC.name] = FALSE
. = TRUE
+26 -40
View File
@@ -433,45 +433,6 @@
// Insert("polycrystal", 'icons/obj/telescience.dmi', "polycrystal")
// ..()
/datum/asset/nanoui
var/list/common = list()
var/list/common_dirs = list(
"nano/css/",
"nano/images/",
"nano/images/modular_computers/",
"nano/js/"
)
var/list/template_dirs = list(
"nano/templates/"
)
/datum/asset/nanoui/register()
// Crawl the directories to find files.
for(var/path in common_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // Ignore directories.
if(fexists(path + filename))
common[filename] = fcopy_rsc(path + filename)
register_asset(filename, common[filename])
// Combine all templates into a single bundle.
var/list/template_data = list()
for(var/path in template_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename) - 4) == ".tmpl") // Ignore directories.
template_data[filename] = file2text(path + filename)
var/template_bundle = "function nanouiTemplateBundle(){return [json_encode(template_data)];}"
var/fname = "data/nano_templates_bundle.js"
fdel(fname)
text2file(template_bundle, fname)
register_asset("nano_templates_bundle.js", fcopy_rsc(fname))
fdel(fname)
/datum/asset/nanoui/send(client)
send_asset_list(client, common)
//Pill sprites for UIs
/datum/asset/chem_master
var/assets = list()
@@ -522,4 +483,29 @@
/datum/asset/spritesheet/sheetmaterials/register()
InsertAll("", 'icons/obj/stacks.dmi')
..()
..()
// Nanomaps
/datum/asset/simple/nanomaps
// It REALLY doesnt matter too much if these arent up to date
// They are relatively big
assets = list(
"southern_cross_nanomap_z1.png" = 'icons/_nanomaps/southern_cross_nanomap_z1.png',
"southern_cross_nanomap_z10.png" = 'icons/_nanomaps/southern_cross_nanomap_z10.png',
"southern_cross_nanomap_z2.png" = 'icons/_nanomaps/southern_cross_nanomap_z2.png',
"southern_cross_nanomap_z3.png" = 'icons/_nanomaps/southern_cross_nanomap_z3.png',
"southern_cross_nanomap_z5.png" = 'icons/_nanomaps/southern_cross_nanomap_z5.png',
"southern_cross_nanomap_z6.png" = 'icons/_nanomaps/southern_cross_nanomap_z6.png',
"tether_nanomap_z1.png" = 'icons/_nanomaps/tether_nanomap_z1.png',
"tether_nanomap_z10.png" = 'icons/_nanomaps/tether_nanomap_z10.png',
"tether_nanomap_z13.png" = 'icons/_nanomaps/tether_nanomap_z13.png',
"tether_nanomap_z14.png" = 'icons/_nanomaps/tether_nanomap_z14.png',
"tether_nanomap_z2.png" = 'icons/_nanomaps/tether_nanomap_z2.png',
"tether_nanomap_z3.png" = 'icons/_nanomaps/tether_nanomap_z3.png',
"tether_nanomap_z4.png" = 'icons/_nanomaps/tether_nanomap_z4.png',
"tether_nanomap_z5.png" = 'icons/_nanomaps/tether_nanomap_z5.png',
"tether_nanomap_z6.png" = 'icons/_nanomaps/tether_nanomap_z6.png',
"tether_nanomap_z7.png" = 'icons/_nanomaps/tether_nanomap_z7.png',
"tether_nanomap_z8.png" = 'icons/_nanomaps/tether_nanomap_z8.png',
"tether_nanomap_z9.png" = 'icons/_nanomaps/tether_nanomap_z9.png',
)
-12
View File
@@ -8,8 +8,6 @@
var/obj/item/clothing/glasses/hud/omni/hud = null
var/mode = "civ"
icon_state = "glasses"
var/datum/nano_module/arscreen
var/arscreen_path
var/datum/tgui_module/tgarscreen
var/tgarscreen_path
var/flash_prot = 0 //0 for none, 1 for flash weapon protection, 2 for welder protection
@@ -18,34 +16,24 @@
/obj/item/clothing/glasses/omnihud/New()
..()
if(arscreen_path)
arscreen = new arscreen_path(src)
if(tgarscreen_path)
tgarscreen = new tgarscreen_path(src)
/obj/item/clothing/glasses/omnihud/Destroy()
QDEL_NULL(arscreen)
QDEL_NULL(tgarscreen)
. = ..()
/obj/item/clothing/glasses/omnihud/dropped()
if(arscreen)
SSnanoui.close_uis(src)
if(tgarscreen)
SStgui.close_uis(src)
..()
/obj/item/clothing/glasses/omnihud/emp_act(var/severity)
if(arscreen)
SSnanoui.close_uis(src)
if(tgarscreen)
SStgui.close_uis(src)
var/disconnect_ar = arscreen
var/disconnect_tgar = tgarscreen
arscreen = null
tgarscreen = null
spawn(20 SECONDS)
arscreen = disconnect_ar
tgarscreen = disconnect_tgar
//extra fun for non-sci variants; a small chance flip the state to the dumb 3d glasses when EMP'd
@@ -23,7 +23,7 @@
to_chat(usr, "Your module is not installed in a hardsuit.")
return
module.holder.ui_interact(usr, nano_state = contained_state)
module.holder.tgui_interact(usr, custom_state = GLOB.tgui_contained_state)
/obj/item/rig_module/ai_container
@@ -134,7 +134,7 @@
if(!target)
if(ai_card)
if(istype(ai_card,/obj/item/device/aicard))
ai_card.tgui_interact(H, custom_state = deep_inventory_state)
ai_card.tgui_interact(H, custom_state = GLOB.tgui_deep_inventory_state)
else
eject_ai(H)
update_verb_holder()
+1 -2
View File
@@ -53,13 +53,12 @@
O.loc = src
held_card = O
SSnanoui.update_uis(src)
SStgui.update_uis(src)
attack_hand(user)
/obj/machinery/account_database/attack_hand(mob/user as mob)
if(stat & (NOPOWER|BROKEN)) return
ui_interact(user)
tgui_interact(user)
/obj/machinery/account_database/tgui_interact(mob/user, datum/tgui/ui)
@@ -78,7 +78,7 @@
output.assembly = src
/obj/item/device/electronic_assembly/device/check_interactivity(mob/user)
if(!CanInteract(user, state = deep_inventory_state))
if(!CanInteract(user, state = GLOB.tgui_deep_inventory_state))
return 0
return 1
@@ -40,8 +40,8 @@ D [1]/ ||
holder = null
. = ..()
/datum/integrated_io/nano_host()
return holder.nano_host()
/datum/integrated_io/tgui_host()
return holder.tgui_host()
/datum/integrated_io/proc/data_as_type(var/as_type)
@@ -117,7 +117,7 @@
/datum/integrated_io/list/display_pin_type()
return IC_FORMAT_LIST
/datum/integrated_io/list/Topic(href, href_list, state = interactive_state)
/datum/integrated_io/list/Topic(href, href_list, state = GLOB.tgui_always_state)
if(!holder.check_interactivity(usr))
return
if(..())
@@ -115,7 +115,7 @@
/obj/item/device/integrated_electronics/debugger/attack_self(mob/user)
var/type_to_use = input("Please choose a type to use.","[src] type setting") as null|anything in list("string","number","ref", "null")
if(!CanInteract(user, physical_state))
if(!CanInteract(user, GLOB.tgui_physical_state))
return
var/new_data = null
@@ -124,13 +124,13 @@
accepting_refs = 0
new_data = input("Now type in a string.","[src] string writing") as null|text
new_data = sanitizeSafe(new_data, MAX_MESSAGE_LEN, 0, 0)
if(istext(new_data) && CanInteract(user, physical_state))
if(istext(new_data) && CanInteract(user, GLOB.tgui_physical_state))
data_to_write = new_data
to_chat(user, "<span class='notice'>You set \the [src]'s memory to \"[new_data]\".</span>")
if("number")
accepting_refs = 0
new_data = input("Now type in a number.","[src] number writing") as null|num
if(isnum(new_data) && CanInteract(user, physical_state))
if(isnum(new_data) && CanInteract(user, GLOB.tgui_physical_state))
data_to_write = new_data
to_chat(user, "<span class='notice'>You set \the [src]'s memory to [new_data].</span>")
if("ref")
@@ -54,7 +54,7 @@
/obj/item/integrated_circuit/input/numberpad/ask_for_input(mob/user)
var/new_input = input(user, "Enter a number, please.","Number pad", get_pin_data(IC_OUTPUT, 1)) as null|num
if(isnum(new_input) && CanInteract(user, physical_state))
if(isnum(new_input) && CanInteract(user, GLOB.tgui_physical_state))
set_pin_data(IC_OUTPUT, 1, new_input)
push_data()
activate_pin(1)
@@ -73,7 +73,7 @@
/obj/item/integrated_circuit/input/textpad/ask_for_input(mob/user)
var/new_input = input(user, "Enter some words, please.","Number pad", get_pin_data(IC_OUTPUT, 1)) as null|text
if(istext(new_input) && CanInteract(user, physical_state))
if(istext(new_input) && CanInteract(user, GLOB.tgui_physical_state))
set_pin_data(IC_OUTPUT, 1, new_input)
push_data()
activate_pin(1)
@@ -92,7 +92,7 @@
/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
if(new_color && CanInteract(user, physical_state))
if(new_color && CanInteract(user, GLOB.tgui_physical_state))
set_pin_data(IC_OUTPUT, 1, new_color)
push_data()
activate_pin(1)
@@ -89,7 +89,7 @@
/obj/item/integrated_circuit/memory/constant/attack_self(mob/user)
var/datum/integrated_io/O = outputs[1]
var/type_to_use = input("Please choose a type to use.","[src] type setting") as null|anything in list("string","number","ref", "null")
if(!CanInteract(user, physical_state))
if(!CanInteract(user, GLOB.tgui_physical_state))
return
var/new_data = null
@@ -97,13 +97,13 @@
if("string")
accepting_refs = 0
new_data = input("Now type in a string.","[src] string writing") as null|text
if(istext(new_data) && CanInteract(user, physical_state))
if(istext(new_data) && CanInteract(user, GLOB.tgui_physical_state))
O.data = new_data
to_chat(user, "<span class='notice'>You set \the [src]'s memory to [O.display_data(O.data)].</span>")
if("number")
accepting_refs = 0
new_data = input("Now type in a number.","[src] number writing") as null|num
if(isnum(new_data) && CanInteract(user, physical_state))
if(isnum(new_data) && CanInteract(user, GLOB.tgui_physical_state))
O.data = new_data
to_chat(user, "<span class='notice'>You set \the [src]'s memory to [O.display_data(O.data)].</span>")
if("ref")
+1 -1
View File
@@ -213,7 +213,7 @@
medicalActive1 = null
medicalActive2 = null
medical_cannotfind = 0
SSnanoui.update_uis(src)
SStgui.update_uis(src)
to_chat(usr, "<span class='notice'>You reset your record-viewing software.</span>")
/mob/living/silicon/pai/cancel_camera()
@@ -41,7 +41,6 @@ var/global/list/default_pai_software = list()
set category = "pAI Commands"
set name = "Software Interface"
ui_interact(src)
tgui_interact(src)
/mob/living/silicon/pai/tgui_state(mob/user)
-1
View File
@@ -1,5 +1,4 @@
/mob/Logout()
SSnanoui.user_logout(src) // this is used to clean up (remove) this user's Nano UIs
SStgui.on_logout(src) // Cleanup any TGUIs the user has open
player_list -= src
disconnect_time = world.realtime //VOREStation Addition: logging when we disappear.
@@ -220,12 +220,6 @@
else
return -1
/obj/item/modular_computer/initial_data()
return get_header_data()
/obj/item/modular_computer/update_layout()
return TRUE
/datum/computer_file/program/apply_visual(mob/M)
if(TM)
return TM.apply_visual(M)
-7
View File
@@ -1,7 +0,0 @@
/*
This state checks that the user is an admin, end of story
*/
/var/global/datum/topic_state/admin_state/admin_state = new()
/datum/topic_state/admin_state/can_use_topic(var/src_object, var/mob/user)
return check_rights(R_ADMIN|R_EVENT, 0, user) ? STATUS_INTERACTIVE : STATUS_CLOSE
-37
View File
@@ -1,37 +0,0 @@
/datum/proc/nano_host()
return src
/datum/proc/nano_container()
return src
/datum/proc/CanUseTopic(var/mob/user, var/datum/topic_state/state)
var/src_object = nano_host()
return state.can_use_topic(src_object, user)
/datum/topic_state/proc/href_list(var/mob/user)
return list()
/datum/topic_state/proc/can_use_topic(var/src_object, var/mob/user)
return STATUS_CLOSE
/mob/proc/shared_nano_interaction()
if (src.stat || !client)
return STATUS_CLOSE // no updates, close the interface
else if (incapacitated())
return STATUS_UPDATE // update only (orange visibility)
return STATUS_INTERACTIVE
/mob/living/silicon/ai/shared_nano_interaction()
if(lacks_power())
return STATUS_CLOSE
if (check_unable(1, 0))
return STATUS_CLOSE
return ..()
/mob/living/silicon/robot/shared_nano_interaction()
. = STATUS_INTERACTIVE
if(!has_power)
return STATUS_CLOSE
if(lockdown)
. = STATUS_DISABLED
return min(., ..())
@@ -1,7 +0,0 @@
/*
This state only checks if user is conscious.
*/
/var/global/datum/topic_state/conscious_state/conscious_state = new()
/datum/topic_state/conscious_state/can_use_topic(var/src_object, var/mob/user)
return user.stat == CONSCIOUS ? STATUS_INTERACTIVE : STATUS_CLOSE
@@ -1,18 +0,0 @@
/*
This state checks if user is somewhere within src_object, as well as the default NanoUI interaction.
*/
/var/global/datum/topic_state/contained_state/contained_state = new()
/datum/topic_state/contained_state/can_use_topic(var/atom/src_object, var/mob/user)
if(!src_object.contains(user))
return STATUS_CLOSE
return user.shared_nano_interaction()
/atom/proc/contains(var/atom/location)
if(!location)
return 0
if(location == src)
return 1
return contains(location.loc)
-91
View File
@@ -1,91 +0,0 @@
/var/global/datum/topic_state/default/default_state = new()
/datum/topic_state/default/href_list(var/mob/user)
return list()
/datum/topic_state/default/can_use_topic(var/src_object, var/mob/user)
return user.default_can_use_topic(src_object)
/mob/proc/default_can_use_topic(var/src_object)
return STATUS_CLOSE // By default no mob can do anything with NanoUI
/mob/observer/dead/default_can_use_topic(var/src_object)
if(can_admin_interact())
return STATUS_INTERACTIVE // Admins are more equal
if(!client || get_dist(src_object, src) > client.view) // Preventing ghosts from having a million windows open by limiting to objects in range
return STATUS_CLOSE
return STATUS_UPDATE // Ghosts can view updates
/mob/living/silicon/pai/default_can_use_topic(var/src_object)
if((src_object == src || src_object == radio || src_object == communicator) && !stat)
return STATUS_INTERACTIVE
else
return ..()
/mob/living/silicon/robot/default_can_use_topic(var/src_object)
. = shared_nano_interaction()
if(. <= STATUS_DISABLED)
return
// robots can interact with things they can see within their view range
if((src_object in view(src)) && get_dist(src_object, src) <= src.client.view)
return STATUS_INTERACTIVE // interactive (green visibility)
return STATUS_DISABLED // no updates, completely disabled (red visibility)
/mob/living/silicon/ai/default_can_use_topic(var/src_object)
. = shared_nano_interaction()
if(. != STATUS_INTERACTIVE)
return
// Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras)
// unless it's on the same level as the object it's interacting with.
var/turf/T = get_turf(src_object)
if(!T || !(z == T.z || (T.z in using_map.player_levels)))
return STATUS_CLOSE
// If an object is in view then we can interact with it
if(src_object in view(client.view, src))
return STATUS_INTERACTIVE
// If we're installed in a chassi, rather than transfered to an inteliCard or other container, then check if we have camera view
if(is_in_chassis())
//stop AIs from leaving windows open and using then after they lose vision
if(cameranet && !cameranet.checkTurfVis(get_turf(src_object)))
return STATUS_CLOSE
return STATUS_INTERACTIVE
else if(get_dist(src_object, src) <= client.view) // View does not return what one would expect while installed in an inteliCard
return STATUS_INTERACTIVE
return STATUS_CLOSE
//Some atoms such as vehicles might have special rules for how mobs inside them interact with NanoUI.
/atom/proc/contents_nano_distance(var/src_object, var/mob/living/user)
return user.shared_living_nano_distance(src_object)
/mob/living/proc/shared_living_nano_distance(var/atom/movable/src_object)
if (!(src_object in view(4, src))) // If the src object is not in visable, disable updates
return STATUS_CLOSE
var/dist = get_dist(src_object, src)
if (dist <= 1)
return STATUS_INTERACTIVE // interactive (green visibility)
else if (dist <= 2)
return STATUS_UPDATE // update only (orange visibility)
else if (dist <= 4)
return STATUS_DISABLED // no updates, completely disabled (red visibility)
return STATUS_CLOSE
/mob/living/default_can_use_topic(var/src_object)
. = shared_nano_interaction(src_object)
if(. != STATUS_CLOSE)
if(loc)
. = min(., loc.contents_nano_distance(src_object, src))
if(STATUS_INTERACTIVE)
return STATUS_UPDATE
/mob/living/carbon/human/default_can_use_topic(var/src_object)
. = shared_nano_interaction(src_object)
if(. != STATUS_CLOSE)
. = min(., shared_living_nano_distance(src_object))
if(. == STATUS_UPDATE && (TK in mutations)) // If we have telekinesis and remain close enough, allow interaction.
return STATUS_INTERACTIVE
@@ -1,6 +0,0 @@
/mob/living/simple_mob/default_can_use_topic(var/src_object)
. = shared_nano_interaction(src_object)
if(. != STATUS_CLOSE)
. = min(., shared_living_nano_distance(src_object))
//Allows simple mobs to interact with nanoui as long as they have "has_hands = TRUE"
@@ -1,7 +0,0 @@
/*
This state always returns STATUS_INTERACTIVE
*/
/var/global/datum/topic_state/interactive/interactive_state = new()
/datum/topic_state/interactive/can_use_topic(var/src_object, var/mob/user)
return STATUS_INTERACTIVE
@@ -1,11 +0,0 @@
/*
This state checks that the src_object is somewhere in the user's first-level inventory (in hands, on ear, etc.), but not further down (such as in bags).
*/
/var/global/datum/topic_state/inventory_state/inventory_state = new()
/datum/topic_state/inventory_state/can_use_topic(var/src_object, var/mob/user)
if(!(src_object in user))
return STATUS_CLOSE
return user.shared_nano_interaction()
@@ -1,10 +0,0 @@
/*
This state checks if src_object is contained anywhere in the user's inventory, including bags, etc.
*/
/var/global/datum/topic_state/deep_inventory_state/deep_inventory_state = new()
/datum/topic_state/deep_inventory_state/can_use_topic(var/src_object, var/mob/user)
if(!user.contains(src_object))
return STATUS_CLOSE
return user.shared_nano_interaction()
@@ -1,32 +0,0 @@
/*
This state checks that the src_object is on the user's glasses slot.
*/
/var/global/datum/topic_state/glasses_state/glasses_state = new()
/datum/topic_state/glasses_state/can_use_topic(var/src_object, var/mob/user)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.glasses == src_object)
return user.shared_nano_interaction()
return STATUS_CLOSE
/var/global/datum/topic_state/nif_state/nif_state = new()
/datum/topic_state/nif_state/can_use_topic(var/src_object, var/mob/user)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.nif && H.nif.stat == NIF_WORKING && src_object == H.nif)
return user.shared_nano_interaction()
return STATUS_CLOSE
/var/global/datum/topic_state/commlink_state/commlink_state = new()
/datum/topic_state/commlink_state/can_use_topic(var/src_object, var/mob/user)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.nif && H.nif.stat == NIF_WORKING && H.nif.comm == src_object)
return user.shared_nano_interaction()
return STATUS_CLOSE
-6
View File
@@ -1,6 +0,0 @@
/var/global/datum/topic_state/default/outside/outside_state = new()
/datum/topic_state/default/outside/can_use_topic(var/src_object, var/mob/user)
if(user in src_object)
return STATUS_CLOSE
return ..()
-18
View File
@@ -1,18 +0,0 @@
/var/global/datum/topic_state/physical/physical_state = new()
/datum/topic_state/physical/can_use_topic(var/src_object, var/mob/user)
. = user.shared_nano_interaction(src_object)
if(. > STATUS_CLOSE)
return min(., user.check_physical_distance(src_object))
/mob/proc/check_physical_distance(var/src_object)
return STATUS_CLOSE
/mob/observer/dead/check_physical_distance(var/src_object)
return default_can_use_topic(src_object)
/mob/living/check_physical_distance(var/src_object)
return shared_living_nano_distance(src_object)
/mob/living/silicon/check_physical_distance(var/src_object)
return max(STATUS_UPDATE, shared_living_nano_distance(src_object))
-39
View File
@@ -1,39 +0,0 @@
/*
This state checks that user is capable, within range of the remoter, etc. and that src_object meets the basic requirements for interaction (being powered, non-broken, etc.
Whoever initializes this state is also responsible for deleting it properly.
*/
/datum/topic_state/remote
var/datum/remoter
var/datum/remote_target
var/datum/topic_state/remoter_state
/datum/topic_state/remote/New(var/remoter, var/remote_target, var/datum/topic_state/remoter_state = default_state)
src.remoter = remoter
src.remote_target = remote_target
src.remoter_state = remoter_state
..()
/datum/topic_state/remote/Destroy()
src.remoter = null
src.remoter_state = null
// Force an UI update before we go, ensuring that any windows we may have opened for the remote target closes.
SSnanoui.update_uis(remote_target.nano_container())
remote_target = null
return ..()
/datum/topic_state/remote/can_use_topic(var/datum/src_object, var/mob/user)
if(!(remoter && remoter_state)) // The remoter is gone, let us leave
return STATUS_CLOSE
if(src_object != remote_target)
error("remote - Unexpected src_object: Expected '[remote_target]'/[remote_target.type], was '[src_object]'/[src_object.type]")
// This checks if src_object is powered, etc.
// The interactive state is otherwise simplistic and only returns STATUS_INTERACTIVE and never checks distances, etc.
. = src_object.CanUseTopic(user, interactive_state)
if(. == STATUS_CLOSE)
return
// This is the (generally) heavy checking, making sure the user is capable, within range of the remoter source, etc.
return min(., remoter.CanUseTopic(user, remoter_state))
-9
View File
@@ -1,9 +0,0 @@
/*
This state checks that the src_object is the same the as user
*/
/var/global/datum/topic_state/self_state/self_state = new()
/datum/topic_state/self_state/can_use_topic(var/src_object, var/mob/user)
if(src_object != user)
return STATUS_CLOSE
return user.shared_nano_interaction()
-13
View File
@@ -1,13 +0,0 @@
/*
This state checks that the user is on the same Z-level as src_object
*/
/var/global/datum/topic_state/z_state/z_state = new()
/datum/topic_state/z_state/can_use_topic(var/src_object, var/mob/user)
var/turf/turf_obj = get_turf(src_object)
var/turf/turf_usr = get_turf(user)
if(!turf_obj || !turf_usr)
return STATUS_CLOSE
return turf_obj.z == turf_usr.z ? STATUS_INTERACTIVE : STATUS_CLOSE
-60
View File
@@ -1,60 +0,0 @@
/datum/nano_module
var/name
var/datum/host
var/list/using_access
/datum/nano_module/New(var/datum/host)
..()
src.host = host.nano_host()
/datum/nano_module/nano_host()
return host ? host : src
/datum/nano_module/proc/can_still_topic(var/datum/topic_state/state = default_state)
return CanUseTopic(usr, state) == STATUS_INTERACTIVE
/datum/nano_module/proc/check_eye(var/mob/user)
return -1
/datum/nano_module/proc/check_access(var/mob/user, var/access)
if(!access)
return 1
if(using_access)
if(access in using_access)
return 1
else
return 0
if(!istype(user))
return 0
var/obj/item/weapon/card/id/I = user.GetIdCard()
if(!I)
return 0
if(access in I.access)
return 1
return 0
/datum/nano_module/proc/print_text(var/text, var/mob/user)
var/obj/item/modular_computer/MC = nano_host()
if(istype(MC))
if(!MC.nano_printer)
to_chat(user, "Error: No printer detected. Unable to print document.")
return
if(!MC.nano_printer.print_text(text))
to_chat(user, "Error: Printer was unable to print the document. It may be out of paper.")
else
to_chat(user, "Error: Unable to detect compatible printer interface. Are you running NTOSv2 compatible system?")
/datum/proc/initial_data()
return list()
/datum/proc/update_layout()
return FALSE
/datum/nano_module/proc/relaymove(var/mob/user, direction)
return FALSE
-44
View File
@@ -1,44 +0,0 @@
// This file contains all Nano procs/definitions for external classes/objects
/**
* Called when a Nano UI window is closed
* This is how Nano handles closed windows
* It must be a verb so that it can be called using winset
*
* @return nothing
*/
/client/verb/nanoclose(var/uiref as text)
set hidden = 1 // hide this verb from the user's panel
set name = "nanoclose"
var/datum/nanoui/ui = locate(uiref)
if (istype(ui))
ui.close()
if(ui.ref)
var/href = "close=1"
src.Topic(href, params2list(href), ui.ref) // this will direct to the atom's Topic() proc via client.Topic()
else if (ui.on_close_logic)
// no atomref specified (or not found)
// so just reset the user mob's machine var
if(src && src.mob)
src.mob.unset_machine()
/**
* The ui_interact proc is used to open and update Nano UIs
* If ui_interact is not used then the UI will not update correctly
* ui_interact is currently defined for /atom/movable
*
* @param user /mob The mob who is interacting with this ui
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
* @param force_open boolean Force the UI to (re)open, even if it's already open
*
* @return nothing
*/
/datum/proc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nano_ui/master_ui = null, var/datum/topic_state/state = default_state)
return
// Used by the Nano UI Manager (/datum/nanomanager) to track UIs opened by this mob
/mob/var/list/open_uis = list()
-224
View File
@@ -1,224 +0,0 @@
/**
* Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data
*
* @param user /mob The mob who opened/owns the ui
* @param src_object /obj|/mob The obj or mob which the ui belongs to
* @param ui_key string A string key used for the ui
* @param ui /datum/nanoui An existing instance of the ui (can be null)
* @param data list The data to be passed to the ui, if it exists
* @param force_open boolean The ui is being forced to (re)open, so close ui if it exists (instead of updating)
*
* @return /nanoui Returns the found ui, for null if none exists
*/
/datum/controller/subsystem/nanoui/proc/try_update_ui(var/mob/user, src_object, ui_key, var/datum/nanoui/ui, data, var/force_open = 0)
if (isnull(ui)) // no ui has been passed, so we'll search for one
{
ui = get_open_ui(user, src_object, ui_key)
}
if (!isnull(ui))
// The UI is already open
if (!force_open)
ui.push_data(data)
return ui
else
ui.reinitialise(new_initial_data=data)
return ui
return null
/**
* Get an open /nanoui ui for the current user, src_object and ui_key
*
* @param user /mob The mob who opened/owns the ui
* @param src_object /obj|/mob The obj or mob which the ui belongs to
* @param ui_key string A string key used for the ui
*
* @return /nanoui Returns the found ui, or null if none exists
*/
/datum/controller/subsystem/nanoui/proc/get_open_ui(var/mob/user, 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))
//testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - there are no uis open")
return null
else if (isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list))
//testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - there are no uis open for this object")
return null
for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
if (ui.user == user)
return ui
//testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - ui not found")
return null
/**
* Update all /nanoui uis attached to src_object
*
* @param src_object /obj|/mob The obj or mob which the uis are attached to
*
* @return int The number of uis updated
*/
/datum/controller/subsystem/nanoui/proc/update_uis(src_object)
var/src_object_key = "\ref[src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
return 0
var/update_count = 0
for (var/ui_key in open_uis[src_object_key])
for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
if(ui && ui.src_object && ui.user && ui.src_object.nano_host())
ui.process(1)
update_count++
return update_count
/**
* Close all /nanoui uis attached to src_object
*
* @param src_object /obj|/mob The obj or mob which the uis are attached to
*
* @return int The number of uis close
*/
/datum/controller/subsystem/nanoui/proc/close_uis(src_object)
var/src_object_key = "\ref[src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
return 0
var/close_count = 0
for (var/ui_key in open_uis[src_object_key])
for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
if(ui && ui.src_object && ui.user && ui.src_object.nano_host())
ui.close()
close_count++
return close_count
/**
* Update /nanoui uis belonging to user
*
* @param user /mob The mob who owns the uis
* @param src_object /obj|/mob If src_object is provided, only update uis which are attached to src_object (optional)
* @param ui_key string If ui_key is provided, only update uis with a matching ui_key (optional)
*
* @return int The number of uis updated
*/
/datum/controller/subsystem/nanoui/proc/update_user_uis(var/mob/user, src_object = null, ui_key = null)
if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
return 0 // has no open uis
var/update_count = 0
for (var/datum/nanoui/ui in user.open_uis)
if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
ui.process(1)
update_count++
return update_count
/**
* Close /nanoui uis belonging to user
*
* @param user /mob The mob who owns the uis
* @param src_object /obj|/mob If src_object is provided, only close uis which are attached to src_object (optional)
* @param ui_key string If ui_key is provided, only close uis with a matching ui_key (optional)
*
* @return int The number of uis closed
*/
/datum/controller/subsystem/nanoui/proc/close_user_uis(var/mob/user, src_object = null, ui_key = null)
if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
//testing("nanomanager/close_user_uis mob [user.name] has no open uis")
return 0 // has no open uis
var/close_count = 0
for (var/datum/nanoui/ui in user.open_uis)
if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
ui.close()
close_count++
//testing("nanomanager/close_user_uis mob [user.name] closed [open_uis.len] of [close_count] uis")
return close_count
/**
* Add a /nanoui ui to the list of open uis
* This is called by the /nanoui open() proc
*
* @param ui /nanoui The ui to add
*
* @return nothing
*/
/datum/controller/subsystem/nanoui/proc/ui_opened(var/datum/nanoui/ui)
var/src_object_key = "\ref[ui.src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
open_uis[src_object_key] = list(ui.ui_key = list())
else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
open_uis[src_object_key][ui.ui_key] = list();
ui.user.open_uis |= ui
var/list/uis = open_uis[src_object_key][ui.ui_key]
uis |= ui
processing_uis |= ui
//testing("nanomanager/ui_opened mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_uis [ui.user.open_uis.len] | uis [uis.len] | processing_uis [processing_uis.len]")
/**
* Remove a /nanoui ui from the list of open uis
* This is called by the /nanoui close() proc
*
* @param ui /nanoui The ui to remove
*
* @return int 0 if no ui was removed, 1 if removed successfully
*/
/datum/controller/subsystem/nanoui/proc/ui_closed(var/datum/nanoui/ui)
var/src_object_key = "\ref[ui.src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
return 0 // wasn't open
else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
return 0 // wasn't open
processing_uis.Remove(ui)
if(ui.user) // Sanity check in case a user has been deleted (say a blown up borg watching the alarm interface)
ui.user.open_uis.Remove(ui)
var/list/uis = open_uis[src_object_key][ui.ui_key]
uis.Remove(ui)
//testing("nanomanager/ui_closed mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_uis [ui.user.open_uis.len] | uis [uis.len] | processing_uis [processing_uis.len]")
return 1
/**
* This is called on user logout
* Closes/clears all uis attached to the user's /mob
*
* @param user /mob The user's mob
*
* @return nothing
*/
//
/datum/controller/subsystem/nanoui/proc/user_logout(var/mob/user)
//testing("nanomanager/user_logout user [user.name]")
return close_user_uis(user)
/**
* This is called when a player transfers from one mob to another
* Transfers all open UIs to the new mob
*
* @param oldMob /mob The user's old mob
* @param newMob /mob The user's new mob
*
* @return nothing
*/
/datum/controller/subsystem/nanoui/proc/user_transferred(var/mob/oldMob, var/mob/newMob)
//testing("nanomanager/user_transferred from mob [oldMob.name] to mob [newMob.name]")
if (!oldMob || isnull(oldMob.open_uis) || !istype(oldMob.open_uis, /list) || open_uis.len == 0)
//testing("nanomanager/user_transferred mob [oldMob.name] has no open uis")
return 0 // has no open uis
if (isnull(newMob.open_uis) || !istype(newMob.open_uis, /list))
newMob.open_uis = list()
for (var/datum/nanoui/ui in oldMob.open_uis)
ui.user = newMob
newMob.open_uis.Add(ui)
oldMob.open_uis.Cut()
return 1 // success
-529
View File
@@ -1,529 +0,0 @@
/**********************************************************
NANO UI FRAMEWORK
nanoui class (or whatever Byond calls classes)
nanoui is used to open and update nano browser uis
**********************************************************/
/datum/nanoui
// the user who opened this ui
var/mob/user
// the object this ui "belongs" to
var/datum/src_object
// the title of this ui
var/title
// the key of this ui, this is to allow multiple (different) uis for each src_object
var/ui_key
// window_id is used as the window name/identifier for browse and onclose
var/window_id
// the browser window width
var/width = 0
// the browser window height
var/height = 0
// whether to use extra logic when window closes
var/on_close_logic = 1
// an extra ref to use when the window is closed, usually null
var/atom/ref = null
// options for modifying window behaviour
var/window_options = "focus=0;can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id
// the list of stylesheets to apply to this ui
var/list/stylesheets = list()
// the list of javascript scripts to use for this ui
var/list/scripts = list()
// a list of templates which can be used with this ui
var/templates[0]
// the layout key for this ui (this is used on the frontend, leave it as "default" unless you know what you're doing)
var/layout_key = "default"
// this sets whether to re-render the ui layout with each update (default 0, turning on will break the map ui if it's in use)
var/auto_update_layout = 0
// this sets whether to re-render the ui content with each update (default 1)
var/auto_update_content = 1
// the default state to use for this ui (this is used on the frontend, leave it as "default" unless you know what you're doing)
var/state_key = "default"
// show the map ui, this is used by the default layout
var/show_map = 0
// the map z level to display
var/map_z_level = 1
// initial data, containing the full data structure, must be sent to the ui (the data structure cannot be extended later on)
var/list/initial_data[0]
// set to 1 to update the ui automatically every master_controller tick
var/is_auto_updating = 0
// the current status/visibility of the ui
var/status = STATUS_INTERACTIVE
// Relationship between a master interface and its children. Used in update_status
var/datum/nanoui/master_ui
var/list/datum/nanoui/children = list()
var/datum/topic_state/state = null
/**
* Create a new nanoui instance.
*
* @param nuser /mob The mob who has opened/owns this ui
* @param nsrc_object /obj|/mob The obj or mob which this ui belongs to
* @param nui_key string A string key to use for this ui. Allows for multiple unique uis on one src_oject
* @param ntemplate string The filename of the template file from /nano/templates (e.g. "my_template.tmpl")
* @param ntitle string The title of this ui
* @param nwidth int the width of the ui window
* @param nheight int the height of the ui window
* @param nref /atom A custom ref to use if "on_close_logic" is set to 1
*
* @return /nanoui new nanoui object
*/
/datum/nanoui/New(nuser, nsrc_object, nui_key, ntemplate_filename, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = default_state)
user = nuser
src_object = nsrc_object
ui_key = nui_key
window_id = "[ui_key]\ref[src_object]"
src.master_ui = master_ui
if(master_ui)
master_ui.children += src
src.state = state
// add the passed template filename as the "main" template, this is required
add_template("main", ntemplate_filename)
if (ntitle)
title = sanitize(ntitle)
if (nwidth)
width = nwidth
if (nheight)
height = nheight
if (nref)
ref = nref
add_common_assets()
/**
* Use this proc to add assets which are common to (and required by) all nano uis
*
* @return nothing
*/
/datum/nanoui/proc/add_common_assets()
add_script("libraries.min.js") // A JS file comprising of jQuery, doT.js and jQuery Timer libraries (compressed together)
add_script("nano_utility.js") // The NanoUtility JS, this is used to store utility functions.
add_script("nano_templates_bundle.js") // Contains all templates, generated by asset cache system at server start.
add_script("nano_template.js") // The NanoTemplate JS, this is used to render templates.
add_script("nano_state_manager.js") // The NanoStateManager JS, it handles updates from the server and passes data to the current state
add_script("nano_state.js") // The NanoState JS, this is the base state which all states must inherit from
add_script("nano_state_default.js") // The NanoStateDefault JS, this is the "default" state (used by all UIs by default), which inherits from NanoState
add_script("nano_state_pda.js") // The NanoStatePDA JS, this is the state used for PDAs.
add_script("nano_base_callbacks.js") // The NanoBaseCallbacks JS, this is used to set up (before and after update) callbacks which are common to all UIs
add_script("nano_base_helpers.js") // The NanoBaseHelpers JS, this is used to set up template helpers which are common to all UIs
add_stylesheet("shared.css") // this CSS sheet is common to all UIs
add_stylesheet("shared_vr.css") // VOREStation Add
add_stylesheet("icons.css") // this CSS sheet is common to all UIs
/**
* Set the current status (also known as visibility) of this ui.
*
* @param state int The status to set, see the defines at the top of this file
* @param push_update int (bool) Push an update to the ui to update it's status (an update is always sent if the status has changed to red (0))
*
* @return nothing
*/
/datum/nanoui/proc/set_status(state, push_update)
if (state != status) // Only update if it is different
if (status == STATUS_DISABLED)
status = state
if (push_update)
update()
else
status = state
if (push_update || status == 0)
push_data(null, 1) // Update the UI, force the update in case the status is 0, data is null so that previous data is used
/**
* Update the status (visibility) of this ui based on the user's status
*
* @param push_update int (bool) Push an update to the ui to update it's status. This is set to 0/false if an update is going to be pushed anyway (to avoid unnessary updates)
*
* @return nothing
*/
/datum/nanoui/proc/update_status(var/push_update = 0)
var/obj/host = src_object.nano_host()
var/new_status = host.CanUseTopic(user, state)
if(master_ui)
new_status = min(new_status, master_ui.status)
set_status(new_status, push_update)
if(new_status == STATUS_CLOSE)
close()
/**
* Set the ui to auto update (every master_controller tick)
*
* @param state int (bool) Set auto update to 1 or 0 (true/false)
*
* @return nothing
*/
/datum/nanoui/proc/set_auto_update(nstate = 1)
is_auto_updating = nstate
/**
* Set the initial data for the ui. This is vital as the data structure set here cannot be changed when pushing new updates.
*
* @param data /list The list of data for this ui
*
* @return nothing
*/
/datum/nanoui/proc/set_initial_data(list/data)
initial_data = data
/**
* Get config data to sent to the ui.
*
* @return /list config data
*/
/datum/nanoui/proc/get_config_data()
var/name = "[src_object]"
name = sanitize(name)
var/list/config_data = list(
"title" = title,
"srcObject" = list("name" = name),
"stateKey" = state_key,
"status" = status,
"autoUpdateLayout" = auto_update_layout,
"autoUpdateContent" = auto_update_content,
"showMap" = show_map,
"mapZLevel" = map_z_level,
"user" = list("name" = user.name)
)
return config_data
/**
* Get data to sent to the ui.
*
* @param data /list The list of general data for this ui (can be null to use previous data sent)
*
* @return /list data to send to the ui
*/
/datum/nanoui/proc/get_send_data(var/list/data)
var/list/config_data = get_config_data()
var/list/send_data = list("config" = config_data)
if (!isnull(data))
send_data["data"] = data
return send_data
/**
* Set the browser window options for this ui
*
* @param nwindow_options string The new window options
*
* @return nothing
*/
/datum/nanoui/proc/set_window_options(nwindow_options)
window_options = nwindow_options
/**
* Add a CSS stylesheet to this UI
* These must be added before the UI has been opened, adding after that will have no effect
*
* @param file string The name of the CSS file from /nano/css (e.g. "my_style.css")
*
* @return nothing
*/
/datum/nanoui/proc/add_stylesheet(file)
stylesheets.Add(file)
/**
* Add a JavsScript script to this UI
* These must be added before the UI has been opened, adding after that will have no effect
*
* @param file string The name of the JavaScript file from /nano/js (e.g. "my_script.js")
*
* @return nothing
*/
/datum/nanoui/proc/add_script(file)
scripts.Add(file)
/**
* Add a template for this UI
* Templates are combined with the data sent to the UI to create the rendered view
* These must be added before the UI has been opened, adding after that will have no effect
*
* @param key string The key which is used to reference this template in the frontend
* @param filename string The name of the template file from /nano/templates (e.g. "my_template.tmpl")
*
* @return nothing
*/
/datum/nanoui/proc/add_template(key, filename)
templates[key] = filename
/**
* Set the layout key for use in the frontend Javascript
* The layout key is the basic layout key for the page
* Two files are loaded on the client based on the layout key varable:
* -> a template in /nano/templates with the filename "layout_<layout_key>.tmpl
* -> a CSS stylesheet in /nano/css with the filename "layout_<layout_key>.css
*
* @param nlayout string The layout key to use
*
* @return nothing
*/
/datum/nanoui/proc/set_layout_key(nlayout_key)
layout_key = lowertext(nlayout_key)
/**
* Set the ui to update the layout (re-render it) on each update, turning this on will break the map ui (if it's being used)
*
* @param state int (bool) Set update to 1 or 0 (true/false) (default 0)
*
* @return nothing
*/
/datum/nanoui/proc/set_auto_update_layout(nstate)
auto_update_layout = nstate
/**
* Set the ui to update the main content (re-render it) on each update
*
* @param state int (bool) Set update to 1 or 0 (true/false) (default 1)
*
* @return nothing
*/
/datum/nanoui/proc/set_auto_update_content(nstate)
auto_update_content = nstate
/**
* Set the state key for use in the frontend Javascript
*
* @param nstate_key string The key of the state to use
*
* @return nothing
*/
/datum/nanoui/proc/set_state_key(nstate_key)
state_key = nstate_key
/**
* Toggle showing the map ui
*
* @param nstate_key boolean 1 to show map, 0 to hide (default is 0)
*
* @return nothing
*/
/datum/nanoui/proc/set_show_map(nstate)
show_map = nstate
/**
* Toggle showing the map ui
*
* @param nstate_key boolean 1 to show map, 0 to hide (default is 0)
*
* @return nothing
*/
/datum/nanoui/proc/set_map_z_level(nz)
map_z_level = nz
/**
* Set whether or not to use the "old" on close logic (mainly unset_machine())
*
* @param state int (bool) Set on_close_logic to 1 or 0 (true/false)
*
* @return nothing
*/
/datum/nanoui/proc/use_on_close_logic(state)
on_close_logic = state
/**
* Return the HTML for this UI
*
* @return string HTML for the UI
*/
/datum/nanoui/proc/get_html()
// before the UI opens, add the layout files based on the layout key
add_stylesheet("layout_[layout_key].css")
add_template("layout", "layout_[layout_key].tmpl")
var/head_content = ""
for (var/filename in scripts)
head_content += "<script type='text/javascript' src='[filename]'></script> "
for (var/filename in stylesheets)
head_content += "<link rel='stylesheet' type='text/css' href='[filename]'> "
var/template_data_json = "{}" // An empty JSON object
if (templates.len > 0)
template_data_json = strip_improper(json_encode(templates))
var/list/send_data = get_send_data(initial_data)
var/initial_data_json = replacetext(replacetext(json_encode(send_data), "&#34;", "&amp;#34;"), "'", "&#39;")
initial_data_json = strip_improper(initial_data_json);
var/url_parameters_json = json_encode(list("src" = "\ref[src]"))
return {"
<!DOCTYPE html>
<html>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<script type='text/javascript'>
function receiveUpdateData(jsonString)
{
// We need both jQuery and NanoStateManager to be able to recieve data
// At the moment any data received before those libraries are loaded will be lost
if (typeof NanoStateManager != 'undefined' && typeof jQuery != 'undefined')
{
NanoStateManager.receiveUpdateData(jsonString);
}
//else
//{
// alert('browser.recieveUpdateData failed due to jQuery or NanoStateManager being unavailiable.');
//}
}
</script>
[head_content]
</head>
<body scroll=auto data-template-data='[template_data_json]' data-url-parameters='[url_parameters_json]' data-initial-data='[initial_data_json]'>
<div id='uiLayout'>
</div>
<noscript>
<div id='uiNoScript'>
<h2>JAVASCRIPT REQUIRED</h2>
<p>Your Internet Explorer's Javascript is disabled (or broken).<br/>
Enable Javascript and then open this UI again.</p>
</div>
</noscript>
</body>
</html>
"}
/**
* Open this UI
*
* @return nothing
*/
/datum/nanoui/proc/open()
if(!user.client)
return
// An attempted fix to UIs sometimes locking up spamming runtime errors due to src_object being null for whatever reason.
// This hard-deletes the UI, preventing the device that uses the UI from being locked up permanently.
if(!src_object)
del(src)
var/window_size = ""
if (width && height)
window_size = "size=[width]x[height];"
update_status(0)
if(status == STATUS_CLOSE)
return
user << browse(get_html(), "window=[window_id];[window_size][window_options]")
winset(user, "mapwindow.map", "focus=true") // return keyboard focus to map
on_close_winset()
//onclose(user, window_id)
SSnanoui.ui_opened(src)
/**
* Reinitialise this UI, potentially with a different template and/or initial data
*
* @return nothing
*/
/datum/nanoui/proc/reinitialise(template, new_initial_data)
if(template)
add_template("main", template)
if(new_initial_data)
set_initial_data(new_initial_data)
open()
/**
* Close this UI
*
* @return nothing
*/
/datum/nanoui/proc/close()
is_auto_updating = 0
SSnanoui.ui_closed(src)
user << browse(null, "window=[window_id]")
for(var/datum/nanoui/child in children)
child.close()
children.Cut()
state = null
master_ui = null
/**
* Set the UI window to call the nanoclose verb when the window is closed
* This allows Nano to handle closed windows
*
* @return nothing
*/
/datum/nanoui/proc/on_close_winset()
if(!user.client)
return
var/params = "\ref[src]"
winset(user, window_id, "on-close=\"nanoclose [params]\"")
/**
* Push data to an already open UI window
*
* @return nothing
*/
/datum/nanoui/proc/push_data(data, force_push = 0)
update_status(0)
if (status == STATUS_DISABLED && !force_push)
return // Cannot update UI, no visibility
var/list/send_data = get_send_data(data)
//to_chat(user,list2json_usecache(send_data)) // used for debugging //NANO DEBUG HOOK
user << output(list2params(list(strip_improper(json_encode(send_data)))),"[window_id].browser:receiveUpdateData")
/**
* This Topic() proc is called whenever a user clicks on a link within a Nano UI
* If the UI status is currently STATUS_INTERACTIVE then call the src_object Topic()
* If the src_object Topic() returns 1 (true) then update all UIs attached to src_object
*
* @return nothing
*/
/datum/nanoui/Topic(href, href_list)
update_status(0) // update the status
if (status != STATUS_INTERACTIVE || user != usr) // If UI is not interactive or usr calling Topic is not the UI user
return
// This is used to toggle the nano map ui
var/map_update = 0
if(href_list["showMap"])
set_show_map(text2num(href_list["showMap"]))
map_update = 1
if(href_list["mapZLevel"])
set_map_z_level(text2num(href_list["mapZLevel"]))
map_update = 1
if ((src_object && src_object.Topic(href, href_list, state)) || map_update)
SSnanoui.update_uis(src_object) // update all UIs attached to src_object
/**
* Process this UI, updating the entire UI or just the status (aka visibility)
* This process proc is called by the master_controller
*
* @param update string For this UI to update
*
* @return nothing
*/
/datum/nanoui/process(update = 0)
if (!src_object || !user)
close()
return
if (status && (update || is_auto_updating))
update() // Update the UI (update_status() is called whenever a UI is updated)
else
update_status(1) // Not updating UI, so lets check here if status has changed
/**
* Update the UI
*
* @return nothing
*/
/datum/nanoui/proc/update(var/force_open = 0)
src_object.ui_interact(user, ui_key, src, force_open, master_ui, state)
@@ -47,6 +47,6 @@
else
to_chat(usr,"<span class='warning'>No valid landing sites in range.</span>")
possible_d = shuttle.get_possible_destinations()
if(CanInteract(usr, global.default_state) && (D in possible_d))
if(CanInteract(usr, GLOB.tgui_default_state) && (D in possible_d))
shuttle.set_destination(possible_d[D])
return TRUE
+1 -1
View File
@@ -59,7 +59,7 @@
if(opened)
wires.Interact(user)
return ui_interact(user)
return tgui_interact(user)
/obj/machinery/power/grid_checker/proc/power_failure(var/announce = TRUE)
if(announce)
@@ -25,7 +25,7 @@
C.reagents.add_reagent(id, to_restore)
. = 1
if(.)
SSnanoui.update_uis(src)
SStgui.update_uis(src)
/obj/machinery/chemical_dispenser
dispense_reagents = list(
+3 -3
View File
@@ -147,9 +147,9 @@ var/list/infomorph_emotions = list(
return 0
..()
/mob/living/silicon/infomorph/default_can_use_topic(var/src_object)
/mob/living/silicon/infomorph/default_can_use_tgui_topic(var/src_object)
if(src_object in src)
return shared_nano_interaction()
return shared_tgui_interaction()
/////////// DAMAGES
/mob/living/silicon/infomorph/emp_act(severity)
@@ -190,7 +190,7 @@ var/list/infomorph_emotions = list(
medicalActive1 = null
medicalActive2 = null
medical_cannotfind = 0
SSnanoui.update_uis(src)
SStgui.update_uis(src)
to_chat(usr, "<span class='notice'>You reset your record-viewing software.</span>")
/*
@@ -26,7 +26,7 @@
switch(action)
if("pick")
var/dest_key = input("Choose shuttle destination", "Shuttle Destination") as null|anything in shuttle.get_destinations()
if(dest_key && CanInteract(usr, global.default_state))
if(dest_key && CanInteract(usr, GLOB.tgui_default_state))
shuttle.set_destination(dest_key, usr)
return TRUE
@@ -34,6 +34,11 @@
ui.set_map_z_level(params["mapZLevel"])
return TRUE
/datum/tgui_module/atmos_control/ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/simple/nanomaps),
)
/datum/tgui_module/atmos_control/tgui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
@@ -2,6 +2,11 @@
name = "Crew monitor"
tgui_id = "CrewMonitor"
/datum/tgui_module/crew_monitor/ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/simple/nanomaps),
)
/datum/tgui_module/crew_monitor/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
@@ -48,7 +48,7 @@
sleep(3)
return NANOMAP_TERMINALERR
var/icon/Tile = icon(file("nano/mapbase1200.png"))
var/icon/Tile = icon('icons/_nanomaps/mapbase1200.png')
if (Tile.Width() != NANOMAP_MAX_ICON_DIMENSION || Tile.Height() != NANOMAP_MAX_ICON_DIMENSION)
to_world_log("NanoMapGen: <B>ERROR: BASE IMAGE DIMENSIONS ARE NOT [NANOMAP_MAX_ICON_DIMENSION]x[NANOMAP_MAX_ICON_DIMENSION]</B>")
sleep(3)
+4
View File
@@ -123,3 +123,7 @@
if((TK in mutations) && (get_dist(src, src_object) <= 2))
return STATUS_INTERACTIVE
return ..()
// Topic Extensions for old UIs
/datum/proc/CanUseTopic(var/mob/user, var/datum/tgui_state/state)
return tgui_status(user, state)
@@ -10,3 +10,11 @@ GLOBAL_DATUM_INIT(tgui_deep_inventory_state, /datum/tgui_state/deep_inventory_st
if(!user.contains(src_object))
return STATUS_CLOSE
return user.shared_tgui_interaction(src_object)
/atom/proc/contains(var/atom/location)
if(!location)
return 0
if(location == src)
return 1
return contains(location.loc)
+2 -2
View File
@@ -68,12 +68,12 @@ GLOBAL_DATUM_INIT(tgui_default_state, /datum/tgui_state/default, new)
/mob/living/silicon/pai/default_can_use_tgui_topic(src_object)
// pAIs can only use themselves and the owner's radio.
if((src_object == src || src_object == radio) && !stat)
if((src_object == src || src_object == radio || src_object == communicator) && !stat)
return STATUS_INTERACTIVE
else
return ..()
/mob/observer/dead/default_can_use_tgui_topic()
if(check_rights(R_ADMIN, 0, src))
if(can_admin_interact())
return STATUS_INTERACTIVE // Admins are more equal
return STATUS_UPDATE // Ghosts can view updates

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 246 KiB

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Before

Width:  |  Height:  |  Size: 383 KiB

After

Width:  |  Height:  |  Size: 383 KiB

Before

Width:  |  Height:  |  Size: 222 KiB

After

Width:  |  Height:  |  Size: 222 KiB

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

-297
View File
@@ -1,297 +0,0 @@
<!-- TOC depth:6 withLinks:1 updateOnSave:0 orderedList:0 -->
- [NanoUI](#nanoui)
- [Introduction](#introduction)
- [Components](#components)
- [`ui_interact()`](#ui_interact)
- [`Topic()`](#topic)
- [Template (doT)](#template-dot)
- [Helpers](#helpers)
- [Link](#link)
- [displayBar](#displayBar)
- [doT](#dot)
- [Styling](#styling)
- [Contributing](#contributing)
<!-- /TOC -->
# NanoUI
## Introduction
### Credit goes to Neersighted of /tg/station for the styling and large chunks of content of this README.
NanoUI is one of the three primary user interface libraries currently in use
on Polaris (browse(), /datum/browser, NanoUI). It is the most complex of the three,
but offers quite a few advantages, most notably in default features.
NanoUI adds a `ui_interact()` proc to all atoms, which, ideally, should be called
via `interact()`; However, the current standardized layout is `ui_interact()` being
directly called from anywhere in the atom, generally `attack_hand()` or `attack_self()`.
The `ui_interact()` proc should not contain anything but NanoUI data and code.
Here is a simple example from
[poolcontroller.dm @ ParadiseSS13/Paradise](https://github.com/ParadiseSS13/Paradise/blob/master/code/game/machinery/poolcontroller.dm).
```
/obj/machinery/poolcontroller/attack_hand(mob/user)
ui_interact(user)
/obj/machinery/poolcontroller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
var/data[0]
data["currentTemp"] = temperature
data["emagged"] = emagged
data["TempColor"] = temperaturecolor
ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
ui = new(user, src, ui_key, "poolcontroller.tmpl", "Pool Controller Interface", 520, 410)
ui.set_initial_data(data)
ui.open()
```
## Components
### `ui_interact()`
The `ui_interact()` proc is used to open a NanoUI (or update it if already open).
As NanoUI will call this proc to update your UI, you should include the data list
within it. On /tg/station, this is handled via `get_ui_data()`, however, as it would
take quite a long time to convert every single one of the 100~ UI's to using such a method,
it is instead just directly created within `ui_interact()`.
The parameters for `try_update_ui` and `/datum/nanoui/New()` are documented in
the code [here](https://github.com/PolarisSS13/Polaris/tree/master/code/modules/nano).
For:
`/datum/nanoui/New(nuser, nsrc_object, nui_key, ntemplate_filename, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = default_state)`
Most of the parameters are fairly self explanatory.
- `nuser` is the person who gets to see the UI window
- `nsrc_obj` is the thing you want to call Topic() on
- `nui_key` should almost always be `main`
- `ntemplate_filename` is the filename with `.tmpl` extension in /nano/templates/
- `ntitle` is what you want to show at the top of the UI window
- `nwidth` is the width of the new window
- `nheight` is the height of the new window
- `nref` is used for onclose()
- `master_ui` is used for UIs that have multiple children, see code for examples
- And finally, `state`.
The most interesting parameter here is `state`, which allows the object to choose the
checks that allow the UI to be interacted with.
The default state (`default_state`) checks that the user is alive, conscious,
and within a few tiles. It allows universal access to silicons. Other states
exist, and may be more appropriate for different interfaces. For example,
`physical_state` requires the user to be nearby, even if they are a silicon.
`inventory_state` checks that the user has the object in their first-level
(not container) inventory, this is suitable for devices such as radios;
`admin_state` checks that the user is an admin (good for admin tools).
```
/obj/item/the/thing/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, force_open = 0)
var/data[0]
ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open = force_open)
if(!ui)
ui = new(user, src, ui_key, "template_name_here.tmpl", title, width, height)
ui.set_initial_data(data)
ui.open()
```
### `Topic()`
`Topic()` handles input from the UI. Typically you will recieve some data from
a button press, or pop up a input dialog to take a numerical value from the
user. Sanity checking is useful here, as `Topic()` is trivial to spoof with
arbitrary data.
The `Topic()` interface is just the same as with more conventional,
stringbuilder-based UIs, and this needs little explanation.
```
/obj/item/weapon/tank/Topic(href, href_list)
if(..())
return 1
if(href_list["dist_p"])
if(href_list["dist_p"] == "custom")
var/custom = input(usr, "What rate do you set the regulator to? The dial reads from 0 to [TANK_MAX_RELEASE_PRESSURE].") as null|num
if(isnum(custom))
href_list["dist_p"] = custom
.()
else if(href_list["dist_p"] == "reset")
distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE
else if(href_list["dist_p"] == "min")
distribute_pressure = TANK_MIN_RELEASE_PRESSURE
else if(href_list["dist_p"] == "max")
distribute_pressure = TANK_MAX_RELEASE_PRESSURE
else
distribute_pressure = text2num(href_list["dist_p"])
distribute_pressure = min(max(round(distribute_pressure), TANK_MIN_RELEASE_PRESSURE), TANK_MAX_RELEASE_PRESSURE)
if(href_list["stat"])
if(istype(loc,/mob/living/carbon))
var/mob/living/carbon/location = loc
if(location.internal == src)
location.internal = null
location.internals.icon_state = "internal0"
to_chat(usr, "<span class='notice'>You close the tank release valve.</span>")
if(location.internals)
location.internals.icon_state = "internal0"
else
if(location.wear_mask && (location.wear_mask.flags & MASKINTERNALS))
location.internal = src
to_chat(usr, "<span class='notice'>You open \the [src] valve.</span>")
if(location.internals)
location.internals.icon_state = "internal1"
else
to_chat(usr, "<span class='warning'>You need something to connect to \the [src]!</span>")
```
### Template (doT)
NanoUI templates are written in a customized version of
[doT](https://olado.github.io/doT/index.html),
a Javascript template engine. Data is accessed from the `data` object,
configuration (not used in pratice) from the `config` object, and template
helpers are accessed from the `helper` object.
It is worth explaining that Polaris's version of doT uses custom syntax
for the templates. The `?` operator is split into `if`, `else if parameter`, and `else`,
instead of `?`, `?? paramater`, `??`, and the `=` operator is replaced with `:`. Refer
to the chart below for a full comparison.
#### Helpers
##### Link
`{{:helpers.link(text, icon, {'parameter': true}, status, class, id)}}`
Used to create a link (button), which will pass its parameters to `Topic()`.
* Text: The text content of the link/button
* Icon: The icon shown to the left of the link (http://fontawesome.io/)
* Parameters: The values to be passed to `Topic()`'s `href_list`.
* Status: `null` for clickable, a class for selected/unclickable.
* Class: Styling to apply to the link.
* ID: Sets the element ID.
Status and Class have almost the same effect. However, changing a link's status
from `null` to something else makes it unclickable, while setting a custom Class
does not.
Ternary operators are often used to avoid writing many `if` statements.
For example, depending on if a value in `data` is true or false we can set a
button to clickable or selected:
`{{:helper.link('Close', 'lock', {'stat': 1}, data.valveOpen ? null : 'selected')}}`
Available classes/statuses are:
* null (normal)
* selected
* disabled
* yellowButton
* redButton
* linkDanger
##### displayBar
`{{:helpers.displayBar(value, min, max, class, text)}}`
Used to create a bar, to display a numerical value visually. Min and Max default
to 0 and 100, but you can change them to avoid doing your own percent calculations.
* Value: Defaults to a percentage but can be a straight number if Min/Max are set
* Min: The minimum value (left hand side) of the bar
* Max: The maximum value (right hand side) of the bar
* Class: The color of the bar (null/normal, good, average, bad)
* Text: The text label for the data contained in the bar (often just number form)
As with buttons, ternary operators are quite useful:
`{{:helper.bar(data.tankPressure, 0, 1013, (data.tankPressure > 200) ? 'good' : ((data.tankPressure > 100) ? 'average' : 'bad'))}}`
#### doT
doT is a simple template language, with control statements mixed in with
regular HTML and interpolation expressions.
However, Polaris uses a custom version with a different syntax. Refer
to the chart below for the differences.
Operator | doT | equiv |
|-----------|------------|-------------------|
|Conditional| ? | if |
| | ?? | else |
| | ?? (param) | else if(param) |
|Interpolate| = | : |
|^ + Encode | ! | > |
|Evaluation | # | # |
|Defines | ## # | ## # |
|Iteration | ~ (param) | for (param) |
Here is a simple example from tanks, checking if a variable is true:
```
{{if data.maskConnected}}
<span>The regulator is connected to a mask.</span>
{{else if}}
<span>The regulator is not connected to a mask.</span>
{{/if}}
```
The doT tutorial is [here](https://olado.github.io/doT/tutorial.html).
__Print Tag__
- The print tag outputs the given expression as text to the UI.
`{{:data.variable}}`
`{{:functioncall()}}`
(with escape):
`{{>expression }}`
__If Tag__
- The if tag displays content conditionally based on the provided expression being true.
- When combined with the else tag the if tag can also show content if the provided expression is false.
- The else tag can optionally have an expression provided (e.g. "`{{else expression2}}`"), giving it "elseif" functionality.
`{{if expression}} <expression true content> {{/if}}`
`{{if expression}} <expression true content> {{else}} <expression false content> {{/if}}`
`{{if expression1}} <expression1 true content> {{else expression2}} <expression2 true content> {{/if}}`
__For Tag__
- Loop through entries in an array; it can be associative (with keys) or numerical indexed, but you have to use some special syntax for assocative lists.
- Each time the `for` tag iterates though the array it sets a variable (default "value") to the data of the current entry (another variable, default "index", contains the index). An example of this is using the print tag to print the contents (e.g. `{{:value.key1}}` and `{{:value.key2}}`).
- If combined with an `empty` tag the for tag can display content when the array is empty.
Indexed:
`{{for array}} <list entry content> {{/for}}`
`{{for array}} <list entry content> {{empty}} <empty list content> {{/for}}`
Associative:
`{{for object:key:index}} <key, value> {{/for}}`
__Inclusion Tag__
- Include the contents of another template which has been added to the ui.
`{{#def.atmosphericScan}}`
- You first must have added a template to the ui server side in your DM code:
`ui.add_template("atmosphericScan", "atmospheric_scan.tmpl")`
- Then you can reference it in the main template. The tag will be replaced by the contents of the named template. All tags in the named template are evaluated as normal.
#### Styling
/tg/station has standardized styling, with specific article tags, and headers, and sections.
However, as the templates are already horrifying unstandardized, Polaris does not have any
particular styling standards.
The only real requirement is that it, A. Looks alrightish, and B. Functions properly. Try
to avoid snowflaking anything into the main CSS file, please.
-53
View File
@@ -1,53 +0,0 @@
#!/usr/bin/python3
# Setup
import os, json, shutil, glob, platform
if(platform.system() != "Windows"):
print("Error: This script doesn't work on anything but Windows. How are you even planning to develop BYOND off windows?")
exit()
cdir = (os.getcwd())
if(cdir[-4:] != "nano"):
print("This script must be run from the nano directory.")
exit()
def find_cache():
target = os.path.join(os.path.expanduser("~"), "Documents", "BYOND", "cache")
for root, dirs, files in os.walk(target):
if "nano_templates_bundle.js" in files:
return root
cache = find_cache()
if cache == None:
print("Failed to find BYOND Cache.")
exit()
# Send all of the random files to the cache
def send_to_cache(arrayOfFiles):
for file in arrayOfFiles:
target = os.path.join(cache, os.path.split(file)[1])
shutil.copyfile(file, target)
send_to_cache([os.path.join(cdir, "css", f) for f in os.listdir(os.path.join(cdir, "css")) if os.path.isfile(os.path.join(cdir, "css", f))])
send_to_cache([os.path.join(cdir, "images", f) for f in os.listdir(os.path.join(cdir, "images")) if os.path.isfile(os.path.join(cdir, "images", f))])
send_to_cache([os.path.join(cdir, "js", f) for f in os.listdir(os.path.join(cdir, "js")) if os.path.isfile(os.path.join(cdir, "js", f))])
# Handle creating the tmpl bundle
arrOfFiles = glob.glob(os.path.join(cdir, "templates", "*.tmpl"))
tmpl_bundle_header = "function nanouiTemplateBundle(){return "
tmpl_bundle_footer = ";}"
big_json_array = {}
for file in arrOfFiles:
tmpl_name = os.path.split(file)[1]
with open(file, 'r') as tmpl:
big_json_array[tmpl_name] = tmpl.read()
tmpl_bundle = tmpl_bundle_header + json.dumps(big_json_array) + tmpl_bundle_footer
# Send the tmpl bundle to the cache
with open(os.path.join(cache, "nano_templates_bundle.js"), "w") as templateBundleFile:
templateBundleFile.write(tmpl_bundle)
templateBundleFile.close()
-378
View File
@@ -1,378 +0,0 @@
/* Icons
----------------------------------*/
.icon24
{
width: 24px;
height: 24px;
}
.icon24.uiStatusGood
{
background: url(uiIcons24.png) 0 0 no-repeat;
}
.icon24.uiStatusAverage
{
background: url(uiIcons24.png) 0 -24px no-repeat;
}
.icon24.uiStatusBad
{
background: url(uiIcons24.png) 0 -48px no-repeat;
}
/* states and images */
.uiIcon16 {
float: left;
width: 16px;
height: 16px;
margin: 2px 2px 0 2px;
background-image: url(uiIcons16.png);
}
.uiLinkPendingIcon {
display: none;
float: left;
width: 16px;
height: 16px;
margin: 2px 2px 0 2px;
background-image: url(uiLinkPendingIcon.gif);
}
.linkPending .uiIcon16 {
display: none;
}
.linkPending .uiLinkPendingIcon {
display: block;
}
/* positioning */
.uiIcon16.icon-blank { background-position: 16px 16px; }
.uiIcon16.icon-carat-1-n { background-position: 0 0; }
.uiIcon16.icon-carat-1-ne { background-position: -16px 0; }
.uiIcon16.icon-carat-1-e { background-position: -32px 0; }
.uiIcon16.icon-carat-1-se { background-position: -48px 0; }
.uiIcon16.icon-carat-1-s { background-position: -64px 0; }
.uiIcon16.icon-carat-1-sw { background-position: -80px 0; }
.uiIcon16.icon-carat-1-w { background-position: -96px 0; }
.uiIcon16.icon-carat-1-nw { background-position: -112px 0; }
.uiIcon16.icon-carat-2-n-s { background-position: -128px 0; }
.uiIcon16.icon-carat-2-e-w { background-position: -144px 0; }
.uiIcon16.icon-triangle-1-n { background-position: 0 -16px; }
.uiIcon16.icon-triangle-1-ne { background-position: -16px -16px; }
.uiIcon16.icon-triangle-1-e { background-position: -32px -16px; }
.uiIcon16.icon-triangle-1-se { background-position: -48px -16px; }
.uiIcon16.icon-triangle-1-s { background-position: -64px -16px; }
.uiIcon16.icon-triangle-1-sw { background-position: -80px -16px; }
.uiIcon16.icon-triangle-1-w { background-position: -96px -16px; }
.uiIcon16.icon-triangle-1-nw { background-position: -112px -16px; }
.uiIcon16.icon-triangle-2-n-s { background-position: -128px -16px; }
.uiIcon16.icon-triangle-2-e-w { background-position: -144px -16px; }
.uiIcon16.icon-arrow-1-n { background-position: 0 -32px; }
.uiIcon16.icon-arrow-1-ne { background-position: -16px -32px; }
.uiIcon16.icon-arrow-1-e { background-position: -32px -32px; }
.uiIcon16.icon-arrow-1-se { background-position: -48px -32px; }
.uiIcon16.icon-arrow-1-s { background-position: -64px -32px; }
.uiIcon16.icon-arrow-1-sw { background-position: -80px -32px; }
.uiIcon16.icon-arrow-1-w { background-position: -96px -32px; }
.uiIcon16.icon-arrow-1-nw { background-position: -112px -32px; }
.uiIcon16.icon-arrow-2-n-s { background-position: -128px -32px; }
.uiIcon16.icon-arrow-2-ne-sw { background-position: -144px -32px; }
.uiIcon16.icon-arrow-2-e-w { background-position: -160px -32px; }
.uiIcon16.icon-arrow-2-se-nw { background-position: -176px -32px; }
.uiIcon16.icon-arrowstop-1-n { background-position: -192px -32px; }
.uiIcon16.icon-arrowstop-1-e { background-position: -208px -32px; }
.uiIcon16.icon-arrowstop-1-s { background-position: -224px -32px; }
.uiIcon16.icon-arrowstop-1-w { background-position: -240px -32px; }
.uiIcon16.icon-arrowthick-1-n { background-position: 0 -48px; }
.uiIcon16.icon-arrowthick-1-ne { background-position: -16px -48px; }
.uiIcon16.icon-arrowthick-1-e { background-position: -32px -48px; }
.uiIcon16.icon-arrowthick-1-se { background-position: -48px -48px; }
.uiIcon16.icon-arrowthick-1-s { background-position: -64px -48px; }
.uiIcon16.icon-arrowthick-1-sw { background-position: -80px -48px; }
.uiIcon16.icon-arrowthick-1-w { background-position: -96px -48px; }
.uiIcon16.icon-arrowthick-1-nw { background-position: -112px -48px; }
.uiIcon16.icon-arrowthick-2-n-s { background-position: -128px -48px; }
.uiIcon16.icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.uiIcon16.icon-arrowthick-2-e-w { background-position: -160px -48px; }
.uiIcon16.icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.uiIcon16.icon-arrowthickstop-1-n { background-position: -192px -48px; }
.uiIcon16.icon-arrowthickstop-1-e { background-position: -208px -48px; }
.uiIcon16.icon-arrowthickstop-1-s { background-position: -224px -48px; }
.uiIcon16.icon-arrowthickstop-1-w { background-position: -240px -48px; }
.uiIcon16.icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.uiIcon16.icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.uiIcon16.icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.uiIcon16.icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.uiIcon16.icon-arrowreturn-1-w { background-position: -64px -64px; }
.uiIcon16.icon-arrowreturn-1-n { background-position: -80px -64px; }
.uiIcon16.icon-arrowreturn-1-e { background-position: -96px -64px; }
.uiIcon16.icon-arrowreturn-1-s { background-position: -112px -64px; }
.uiIcon16.icon-arrowrefresh-1-w { background-position: -128px -64px; }
.uiIcon16.icon-arrowrefresh-1-n { background-position: -144px -64px; }
.uiIcon16.icon-arrowrefresh-1-e { background-position: -160px -64px; }
.uiIcon16.icon-arrowrefresh-1-s { background-position: -176px -64px; }
.uiIcon16.icon-arrow-4 { background-position: 0 -80px; }
.uiIcon16.icon-arrow-4-diag { background-position: -16px -80px; }
.uiIcon16.icon-extlink { background-position: -32px -80px; }
.uiIcon16.icon-newwin { background-position: -48px -80px; }
.uiIcon16.icon-refresh { background-position: -64px -80px; }
.uiIcon16.icon-shuffle { background-position: -80px -80px; }
.uiIcon16.icon-transfer-e-w { background-position: -96px -80px; }
.uiIcon16.icon-transferthick-e-w { background-position: -112px -80px; }
.uiIcon16.icon-radiation { background-position: -128px -80px; }
.uiIcon16.icon-folder-collapsed { background-position: 0 -96px; }
.uiIcon16.icon-folder-open { background-position: -16px -96px; }
.uiIcon16.icon-document { background-position: -32px -96px; }
.uiIcon16.icon-document-b { background-position: -48px -96px; }
.uiIcon16.icon-note { background-position: -64px -96px; }
.uiIcon16.icon-mail-closed { background-position: -80px -96px; }
.uiIcon16.icon-mail-open { background-position: -96px -96px; }
.uiIcon16.icon-suitcase { background-position: -112px -96px; }
.uiIcon16.icon-comment { background-position: -128px -96px; }
.uiIcon16.icon-person { background-position: -144px -96px; }
.uiIcon16.icon-print { background-position: -160px -96px; }
.uiIcon16.icon-trash { background-position: -176px -96px; }
.uiIcon16.icon-locked { background-position: -192px -96px; }
.uiIcon16.icon-unlocked { background-position: -208px -96px; }
.uiIcon16.icon-bookmark { background-position: -224px -96px; }
.uiIcon16.icon-tag { background-position: -240px -96px; }
.uiIcon16.icon-home { background-position: 0 -112px; }
.uiIcon16.icon-flag { background-position: -16px -112px; }
.uiIcon16.icon-calendar { background-position: -32px -112px; }
.uiIcon16.icon-cart { background-position: -48px -112px; }
.uiIcon16.icon-pencil { background-position: -64px -112px; }
.uiIcon16.icon-clock { background-position: -80px -112px; }
.uiIcon16.icon-disk { background-position: -96px -112px; }
.uiIcon16.icon-calculator { background-position: -112px -112px; }
.uiIcon16.icon-zoomin { background-position: -128px -112px; }
.uiIcon16.icon-zoomout { background-position: -144px -112px; }
.uiIcon16.icon-search { background-position: -160px -112px; }
.uiIcon16.icon-wrench { background-position: -176px -112px; }
.uiIcon16.icon-gear { background-position: -192px -112px; }
.uiIcon16.icon-heart { background-position: -208px -112px; }
.uiIcon16.icon-star { background-position: -224px -112px; }
.uiIcon16.icon-link { background-position: -240px -112px; }
.uiIcon16.icon-cancel { background-position: 0 -128px; }
.uiIcon16.icon-plus { background-position: -16px -128px; }
.uiIcon16.icon-plusthick { background-position: -32px -128px; }
.uiIcon16.icon-minus { background-position: -48px -128px; }
.uiIcon16.icon-minusthick { background-position: -64px -128px; }
.uiIcon16.icon-close { background-position: -80px -128px; }
.uiIcon16.icon-closethick { background-position: -96px -128px; }
.uiIcon16.icon-key { background-position: -112px -128px; }
.uiIcon16.icon-lightbulb { background-position: -128px -128px; }
.uiIcon16.icon-scissors { background-position: -144px -128px; }
.uiIcon16.icon-clipboard { background-position: -160px -128px; }
.uiIcon16.icon-copy { background-position: -176px -128px; }
.uiIcon16.icon-contact { background-position: -192px -128px; }
.uiIcon16.icon-image { background-position: -208px -128px; }
.uiIcon16.icon-video { background-position: -224px -128px; }
.uiIcon16.icon-script { background-position: -240px -128px; }
.uiIcon16.icon-alert { background-position: 0 -144px; }
.uiIcon16.icon-alert-red { background-image: url(uiIcons16Red.png); background-position: 0 -144px; }
.uiIcon16.icon-info { background-position: -16px -144px; }
.uiIcon16.icon-notice { background-position: -32px -144px; }
.uiIcon16.icon-help { background-position: -48px -144px; }
.uiIcon16.icon-check { background-position: -64px -144px; }
.uiIcon16.icon-bullet { background-position: -80px -144px; }
.uiIcon16.icon-radio-on { background-position: -96px -144px; }
.uiIcon16.icon-radio-off { background-position: -112px -144px; }
.uiIcon16.icon-pin-w { background-position: -128px -144px; }
.uiIcon16.icon-pin-s { background-position: -144px -144px; }
.uiIcon16.icon-phone { background-position: -160px -144px; }
.uiIcon16.icon-list { background-position: -176px -144px; }
.uiIcon16.icon-syringe { background-position: -192px -144px; }
.uiIcon16.icon-play { background-position: 0 -160px; }
.uiIcon16.icon-pause { background-position: -16px -160px; }
.uiIcon16.icon-seek-next { background-position: -32px -160px; }
.uiIcon16.icon-seek-prev { background-position: -48px -160px; }
.uiIcon16.icon-seek-end { background-position: -64px -160px; }
.uiIcon16.icon-seek-start { background-position: -80px -160px; }
/* uiIcon-seek-first is deprecated, use uiIcon-seek-start instead */
.uiIcon16.icon-seek-first { background-position: -80px -160px; }
.uiIcon16.icon-stop { background-position: -96px -160px; }
.uiIcon16.icon-eject { background-position: -112px -160px; }
.uiIcon16.icon-volume-off { background-position: -128px -160px; }
.uiIcon16.icon-volume-on { background-position: -144px -160px; }
.uiIcon16.icon-power { background-position: 0 -176px; }
.uiIcon16.icon-signal-diag { background-position: -16px -176px; }
.uiIcon16.icon-signal { background-position: -32px -176px; }
.uiIcon16.icon-signal-green { background-image: url(uiIcons16Green.png); background-position: -32px -176px; }
.uiIcon16.icon-battery-0 { background-position: -48px -176px; }
.uiIcon16.icon-battery-1 { background-position: -64px -176px; }
.uiIcon16.icon-battery-2 { background-position: -80px -176px; }
.uiIcon16.icon-battery-3 { background-position: -96px -176px; }
.uiIcon16.icon-circle-plus { background-position: 0 -192px; }
.uiIcon16.icon-circle-minus { background-position: -16px -192px; }
.uiIcon16.icon-circle-close { background-position: -32px -192px; }
.uiIcon16.icon-circle-triangle-e { background-position: -48px -192px; }
.uiIcon16.icon-circle-triangle-s { background-position: -64px -192px; }
.uiIcon16.icon-circle-triangle-w { background-position: -80px -192px; }
.uiIcon16.icon-circle-triangle-n { background-position: -96px -192px; }
.uiIcon16.icon-circle-arrow-e { background-position: -112px -192px; }
.uiIcon16.icon-circle-arrow-s { background-position: -128px -192px; }
.uiIcon16.icon-circle-arrow-w { background-position: -144px -192px; }
.uiIcon16.icon-circle-arrow-n { background-position: -160px -192px; }
.uiIcon16.icon-circle-zoomin { background-position: -176px -192px; }
.uiIcon16.icon-circle-zoomout { background-position: -192px -192px; }
.uiIcon16.icon-circle-check { background-position: -208px -192px; }
.uiIcon16.icon-circlesmall-plus { background-position: 0 -208px; }
.uiIcon16.icon-circlesmall-minus { background-position: -16px -208px; }
.uiIcon16.icon-circlesmall-close { background-position: -32px -208px; }
.uiIcon16.icon-squaresmall-plus { background-position: -48px -208px; }
.uiIcon16.icon-squaresmall-minus { background-position: -64px -208px; }
.uiIcon16.icon-squaresmall-close { background-position: -80px -208px; }
.uiIcon16.icon-grip-dotted-vertical { background-position: 0 -224px; }
.uiIcon16.icon-grip-dotted-horizontal { background-position: -16px -224px; }
.uiIcon16.icon-grip-solid-vertical { background-position: -32px -224px; }
.uiIcon16.icon-grip-solid-horizontal { background-position: -48px -224px; }
.uiIcon16.icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.uiIcon16.icon-grip-diagonal-se { background-position: -80px -224px; }
.uiIcon16.icon-batt_full { background-image: url(c_max.gif); background-position: 0px 0px }
.uiIcon16.icon-batt_disc { background-image: url(c_discharging.gif); background-position: 0px 0px }
.uiIcon16.icon-batt_chrg { background-image: url(c_charging.gif); background-position: 0px 0px }
/*yes, defining these all like this is awful, but unless the javascript for icon handling is sorted out this will have to do*/
.uiIcon16.icon-empty64 { background-image: url(uiIcons64.png); background-position: 0 0; width: 64px; height: 64px; }
.uiIcon16.icon-phone64 { background-image: url(uiIcons64.png); background-position: -64px 0; width: 64px; height: 64px; }
.uiIcon16.icon-comment64 { background-image: url(uiIcons64.png); background-position: -128px 0; width: 64px; height: 64px; }
.uiIcon16.icon-list64 { background-image: url(uiIcons64.png); background-position: -192px 0; width: 64px; height: 64px; }
.uiIcon16.icon-gear64 { background-image: url(uiIcons64.png); background-position: -256px 0; width: 64px; height: 64px; }
.uiIcon16.icon-person64 { background-image: url(uiIcons64.png); background-position: -320px 0; width: 64px; height: 64px; }
.uiIcon16.icon-newspaper64 { background-image: url(uiIcons64.png); background-position: 0 -64px; width: 64px; height: 64px; }
.uiIcon16.icon-note64 { background-image: url(uiIcons64.png); background-position: -64px -64px; width: 64px; height: 64px; }
.uiIcon16.icon-close64 { background-image: url(uiIcons64.png); background-position: -128px -64px; width: 64px; height: 64px; }
.uiIcon16.icon-sun64 { background-image: url(uiIcons64.png); background-position: -192px -64px; width: 64px; height: 64px; }
.uiIcon16.icon-external64 { background-image: url(uiIcons64.png); background-position: -256px -64px; width: 64px; height: 64px; }
.uiIcon16.icon-pill { background-image: url(pills32.png); width: 32px; height: 32px;}
.uiIcon16.icon-pill.pill1 { background-position: -64px -96px; }
.uiIcon16.icon-pill.pill2 { background-position: -64px -96px; }
.uiIcon16.icon-pill.pill3 { background-position: -96px -32px; }
.uiIcon16.icon-pill.pill4 { background-position: -96px -32px; }
.uiIcon16.icon-pill.pill5 { background-position: 0 0; }
.uiIcon16.icon-pill.pill6 { background-position: -32px 0; }
.uiIcon16.icon-pill.pill7 { background-position: -64px 0; }
.uiIcon16.icon-pill.pill8 { background-position: -96px 0; }
.uiIcon16.icon-pill.pill9 { background-position: -128px 0; }
.uiIcon16.icon-pill.pill10 { background-position: 0 -32px; }
.uiIcon16.icon-pill.pill11 { background-position: -32px -32px; }
.uiIcon16.icon-pill.pill12 { background-position: -64px -32px; }
.uiIcon16.icon-pill.pill13 { background-position: -96px -32px; }
.uiIcon16.icon-pill.pill14 { background-position: -128px -32px; }
.uiIcon16.icon-pill.pill15 { background-position: 0 -64px; }
.uiIcon16.icon-pill.pill16 { background-position: -32px -64px; }
.uiIcon16.icon-pill.pill17 { background-position: -64px -64px; }
.uiIcon16.icon-pill.pill18 { background-position: -96px -64px; }
.uiIcon16.icon-pill.pill19 { background-position: -128px -64px; }
.uiIcon16.icon-pill.pill20 { background-position: 0 -96px; }
.uiIcon16.icon-pill.pill21 { background-position: -32px -96px; }
.uiIcon16.icon-pill.pill22 { background-position: -64px -96px; }
.uiIcon16.icon-pill.pill23 { background-position: -96px -96px; }
.uiIcon16.icon-pill.pill24 { background-position: -128px -96px; }
.uiIcon16.icon-pill.bottle1 { background-position: 0 -128px; }
.uiIcon16.icon-pill.bottle2 { background-position: -32px -128px; }
.uiIcon16.icon-pill.bottle3 { background-position: -64px -128px; }
.uiIcon16.icon-pill.bottle4 { background-position: -96px -128px; }
.mapIcon16 {
position: absolute;
width: 16px;
height: 16px;
background-image: url(uiIcons16Green.png);
background-position: -144px -96px;
background-repeat: no-repeat;
zoom: 0.125;
margin-left: -1px;
/*margin-bottom: -1px;*/
}
.mapIcon16.dead {
background-image: url(uiIcons16Red.png);
}
/* Command Positions */
.mapIcon16.rank-captain {
background-position: -224px -112px;
}
.mapIcon16.rank-headofpersonnel {
background-position: -112px -96px;
}
.mapIcon16.rank-headofsecurity {
background-position: -112px -128px;
}
.mapIcon16.rank-chiefengineer {
background-position: -176px -112px;
}
.mapIcon16.rank-researchdirector {
background-position: -128px -128px;
}
.mapIcon16.rank-chiefmedicalofficer {
background-position: -32px -128px;
}
/* Engineering Positions */
.mapIcon16.rank-stationengineer {
background-position: -176px -112px;
}
.mapIcon16.rank-atmospherictechnician {
background-position: -176px -112px;
}
/* Medical Positions */
.mapIcon16.rank-medicaldoctor {
background-position: -32px -128px;
}
.mapIcon16.rank-geneticist {
background-position: -32px -128px;
}
.mapIcon16.rank-psychiatrist {
background-position: -32px -128px;
}
.mapIcon16.rank-chemist {
background-position: -32px -128px;
}
/* Science Positions */
.mapIcon16.rank-scientist {
background-position: -128px -128px;
}
.mapIcon16.rank-geneticist {
background-position: -128px -128px;
}
.mapIcon16.rank-roboticist {
background-position: -128px -128px;
}
.mapIcon16.rank-xenobiologist {
background-position: -128px -128px;
}
/* Security Positions */
.mapIcon16.rank-warden {
background-position: -112px -128px;
}
.mapIcon16.rank-detective {
background-position: -112px -128px;
}
.mapIcon16.rank-securityofficer {
background-position: -112px -128px;
}
-21
View File
@@ -1,21 +0,0 @@
body {
background: #272727 url(uiBasicBackground.png) 50% 0 repeat-x;
}
#uiContent {
clear: both;
padding: 8px;
}
#uiLoadingNotice {
position: relative;
background: url(uiNoticeBackground.jpg) 50% 50%;
color: #000000;
font-size: 14px;
font-style: italic;
font-weight: bold;
padding: 3px 4px 3px 4px;
margin: 4px 0 4px 0;
}
-128
View File
@@ -1,128 +0,0 @@
body {
background: #272727 url(uiBackground.png) 50% 0 repeat-x;
}
#uiWrapper {
width: 100%;
height: 100%;
-ms-user-select: none;
user-select: none;
}
#uiTitleWrapper {
position: relative;
height: 30px;
}
#uiTitleText {
position: absolute;
top: 6px;
left: 44px;
width: 66%;
overflow: hidden;
color: #E9C183;
font-size: 16px;
}
#uiTitle.icon {
padding: 6px 8px 6px 42px;
background-position: 2px 50%;
background-repeat: no-repeat;
}
#uiTitleFluff {
position: absolute;
top: 4px;
right: 12px;
width: 42px;
height: 24px;
background: url(uiTitleFluff.png) 50% 50% no-repeat;
}
#uiStatusIcon {
position: absolute;
top: 4px;
left: 12px;
width: 24px;
height: 24px;
}
#uiMapWrapper {
clear: both;
padding: 8px;
}
#uiMapHeader {
position: relative;
clear: both;
}
#uiMapContainer {
position: relative;
width: 100%;
height: 550px;
overflow: hidden;
border: 1px solid #40628a;
background: url(nanomapBackground.png);
}
#uiMap {
position: absolute;
top: 50%;
left: 50%;
margin: -280px 0 0 -280px; /* VOREStation Edit - Tether map is small */
width: 140px; /* VOREStation Edit - Tether map is small */
height: 140px; /* VOREStation Edit - Tether map is small */
overflow: hidden;
zoom: 4;
}
#uiMapImage {
position: absolute;
bottom: 1px;
left: 1px;
width: 140px; /* VOREStation Edit - Tether map is small */
height: 140px; /* VOREStation Edit - Tether map is small */
}
#uiMapContent {
position: absolute;
bottom: 0px;
left: 0px;
width: 140px; /* VOREStation Edit - Tether map is small */
height: 140px; /* VOREStation Edit - Tether map is small */
}
#uiMapFooter {
position: relative;
clear: both;
}
#uiContent {
clear: both;
padding: 8px;
}
#uiMapTooltip {
position: absolute;
right: 10px;
top: 10px;
border: 1px solid #40628a;
background-color: #272727;
padding: 8px;
display: none;
z-index: 9999;
}
#uiLoadingNotice {
position: relative;
background: url(uiNoticeBackground.jpg) 50% 50%;
color: #000000;
font-size: 14px;
font-style: italic;
font-weight: bold;
padding: 3px 4px 3px 4px;
margin: 4px 0 4px 0;
}
-803
View File
@@ -1,803 +0,0 @@
body {
padding: 0;
margin: 0;
font-size: 12px;
color: #ffffff;
line-height: 170%;
font-family: Verdana, Geneva, sans-serif;
background: #272727;
}
#uiNoScript {
position: fixed;
top: 50%;
left: 50%;
margin: -60px 0 0 -150px;
width: 280px;
height: 120px;
background: #ffffff;
border: 2px solid #ff0000;
color: #000000;
font-size: 10px;
font-weight: bold;
z-index: 9999;
padding: 0px 10px;
text-align: center;
}
hr {
background-color: #40628a;
height: 1px;
}
.link, .linkOn, .linkOff, .selected, .disabled, .yellowButton, .redButton {
float: left;
min-width: 15px;
height: 16px;
text-align: center;
color: #ffffff;
text-decoration: none;
background: #40628a;
border: 1px solid #161616;
padding: 0px 4px 4px 4px;
margin: 0 2px 2px 0;
cursor: default;
white-space: nowrap;
}
.link32 {
float: left;
min-width: 15px;
max-width: 31px;
height: 31px;
text-align: center;
text-decoration: none;
background: #40628a;
border: 1px solid #161616;
margin: 0 2px 2px 0;
cursor: default;
}
.hasIcon {
padding: 0px 4px 4px 0px;
}
a:hover, .zoomLink:hover, .linkActive:hover {
background: #507aac;
}
.linkPending, .linkPending:hover {
color: #ffffff;
background: #507aac;
}
a.white, a.white:link, a.white:visited, a.white:active {
color: #40628a;
text-decoration: none;
background: #ffffff;
border: 1px solid #161616;
padding: 1px 4px 1px 4px;
margin: 0 2px 0 0;
cursor: default;
}
a.white:hover {
color: #ffffff;
background: #40628a;
}
.hidden {
display: none;
}
.linkOn, a.linkOn:link, a.linkOn:visited, a.linkOn:active, a.linkOn:hover, .selected, a.selected:link, a.selected:visited, a.selected:active, a.selected:hover {
color: #ffffff;
background: #2f943c;
}
.linkOff, a.linkOff:link, a.linkOff:visited, a.linkOff:active, a.linkOff:hover, .disabled, a.disabled:link, a.disabled:visited, a.disabled:active, a.disabled:hover {
color: #ffffff;
background: #999999;
border-color: #666666;
}
a.icon, .linkOn.icon, .linkOff.icon, .selected.icon, .disabled.icon {
position: relative;
padding: 1px 4px 2px 20px;
}
a.icon img, .linkOn.icon img, .linkOff.icon img, .selected.icon img, .disabled.icon img {
position: absolute;
top: 0;
left: 0;
width: 18px;
height: 18px;
}
.linkDanger, a.linkDanger:link, a.linkDanger:visited, a.linkDanger:active {
color: #ffffff;
background-color: #ff0000;
border-color: #aa0000;
}
.linkDanger:hover {
background-color: #ff6666;
}
ul {
padding: 4px 0 0 10px;
margin: 0;
list-style-type: none;
}
li {
padding: 0 0 2px 0;
}
img, a img {
border-style: none;
}
h1, h2, h3, h4, h5, h6 {
margin: 0;
padding: 12px 0 6px 0;
color: #FFFFFF;
clear: both;
}
h1 {
font-size: 18px;
}
h2 {
font-size: 16px;
}
h3 {
font-size: 14px;
}
h4 {
font-size: 12px;
}
.white {
color: white;
font-weight: bold;
}
.good {
color: #4f7529;
font-weight: bold;
}
.average {
color: #cd6500;
font-weight: bold;
}
.bad {
color: #ee0000;
font-weight: bold;
}
.idle {
color: #272727;
font-weight: bold;
}
.redButton {
background: #ea0000;
}
.greenButton {
background: #00aa00;
}
.yellowButton {
background: #cacc00;
}
.highlight {
color: #8BA5C4;
}
.dark {
color: #272727;
}
.caption {
font-size: 10px;
font-weight: bold;
padding: 5px;
}
.footer {
font-size: 10px;
}
.multiLine {
white-space: pre-wrap;
}
.noticePlaceholder {
position: relative;
font-size: 12px;
font-style: italic;
font-weight: bold;
padding: 3px 4px 3px 4px;
margin: 4px 0 4px 0;
}
.notice {
position: relative;
background: url(uiNoticeBackground.jpg) 50% 50%;
color: #000000;
font-size: 12px;
font-style: italic;
font-weight: bold;
padding: 3px 4px 3px 4px;
margin: 4px 0 4px 0;
}
.notice.icon {
padding: 2px 4px 0 20px;
}
.notice img {
position: absolute;
top: 0;
left: 0;
width: 16px;
height: 16px;
}
div.notice {
clear: both;
}
.itemGroup {
border: 1px solid #e9c183;
background: #2c2c2c;
padding: 4px;
clear: both;
}
.item {
width: 100%;
margin: 4px 0 0 0;
clear: both;
overflow: auto;
}
.itemContentNarrow, .itemContent, .itemContentWide, .itemContentSmall, .itemContentMedium {
float: left;
}
.itemContentNarrow {
width: 30%;
}
.itemContent {
width: 69%;
}
.itemLabelNarrow, .itemLabel, .itemLabelWide, .itemLabelWider, .itemLabelWidest {
float: left;
color: #e9c183;
}
.itemLabelNarrow {
width: 20%;
}
.itemLabel {
width: 30%;
}
.itemLabelWide {
width: 45%;
}
.itemLabelWider {
width: 69%;
}
.itemLabelWidest {
width: 100%;
}
.itemContentWide {
width: 79%;
}
.itemContentSmall {
width: 33%;
}
.itemContentMedium {
width: 55%;
}
.statusDisplay {
background: #000000;
color: #ffffff;
border: 1px solid #40628a;
padding: 4px;
margin: 3px 0;
overflow: hidden;
}
.statusDisplayRecords {
background: #000000;
color: #ffffff;
border: 1px solid #40628a;
padding: 4px;
margin: 3px 0;
overflow-x: hidden;
overflow-y: auto;
}
.statusDisplayComm {
width: 100%;
background: rgba(0, 0, 0, 0.5);
color: #ffffff;
padding-bottom: 4px;
border-top: 0 none;
border-left: 0 none;
border-right: 0 none;
border-bottom: 2px inset #40628a;
margin: 3px 0;
overflow: hidden;
}
.statusLabel {
width: 138px;
float: left;
overflow: hidden;
color: #98B0C3;
}
.statusValue {
float: left;
}
.block {
padding: 8px;
margin: 10px 4px 4px 4px;
border: 1px solid #40628a;
background-color: #202020;
}
.block h3 {
padding: 0;
}
.displayBar {
position: relative;
width: 236px;
height: 16px;
border: 1px solid #666666;
float: left;
margin: 0 5px 0 0;
overflow: hidden;
background: #000000;
}
.displayBarText, .displayBarVerticalText, .displayBarBeakerText{
position: absolute;
top: -2px;
left: 5px;
width: 100%;
height: 100%;
color: #ffffff;
font-weight: normal;
}
.displayBarFill {
width: 0%;
height: 100%;
background: #40628a;
overflow: hidden;
float: left;
}
.displayBarVertical {
position: relative;
width: 16px;
height: 200px;
border: 1px solid #666666;
float: left;
margin: 0 5px 0 0;
overflow: hidden;
background: #40628a;
}
.displayBarVerticalFill {
width: 100%;
height: 0%;
overflow: hidden;
float: left;
background: #000000;
}
/*used in xenobio2 computer*/
.displayBarBeaker {
position: relative;
width: 100px;
height: 110px;
border-right: 2px solid rgb(102, 179, 255);
border-left: 2px solid rgb(102, 179, 255);
border-bottom: 2px solid rgb(102, 179, 255);
float: left;
margin: 0 5px 0 0;
overflow: hidden;
background: #40628a;
}
.displayBarBeakerFill {
width: 100%;
height: 0%;
overflow: hidden;
float: left;
background: rgba(153, 204, 255, 0.3);
}
.displayBarFill.alignRight {
float: right;
}
.displayBarFill.good {
color: #ffffff;
background: #4f7529;
}
.displayBarFill.average {
color: #ffffff;
background: #cd6500;
}
.displayBarFill.bad {
color: #ffffff;
background: #ee0000;
}
.displayBarFill.highlight {
color: #ffffff;
background: #8BA5C4;
}
.clearBoth {
clear: both;
}
.clearLeft {
clear: left;
}
.clearRight {
clear: right;
}
.line {
width: 100%;
clear: both;
}
.inactive, a.inactive:link, a.inactive:visited, a.inactive:active, a.inactive:hover {
color: #ffffff;
background: #999999;
border-color: #666666;
}
.fixedLeft {
width: 110px;
float: left;
}
.fixedLeftWide {
width: 165px;
float: left;
}
.fixedLeftWider {
width: 220px;
float: left;
}
.fixedLeftWidest {
width: 250px;
float: left;
}
.fixedLeftWiderRed {
width: 220px;
float: left;
background: #ee0000;
}
.floatRight {
float: right;
}
.floatLeft {
float: left;
}
/* Used in PDA */
.wholeScreen {
position: absolute;
color: #517087;
font-size: 16px;
font-weight: bold;
text-align: center;
}
.pdalink {
float: left;
white-space: nowrap;
}
/* DNA Modifier UI (dna_modifier.tmpl) */
.dnaBlock {
float: left;
width: 90px;
padding: 0 0 5px 0;
}
.dnaBlockNumber {
font-family: Fixed, monospace;
float: left;
color: #ffffff;
background: #363636;
min-width: 20px;
height: 20px;
padding: 0;
text-align: center;
}
.dnaSubBlock {
font-family: Fixed, monospace;
float: left;
padding: 0;
min-width: 16px;
height: 20px;
text-align: center;
}
.mask {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: url(uiMaskBackground.png);
}
.maskContent {
width: 100%;
height: 200px;
margin: 200px 0;
text-align: center;
}
table.fixed {
table-layout:fixed;
}
table.fixed td {
overflow: hidden;
}
/* Table stuffs for power monitor */
table.pmon {
border: 2px solid RoyalBlue;
}
table.pmon td, table.pmon th {
border-bottom: 1px dotted black;
padding: 0px 5px 0px 5px;
}
/* Table Stuffs for manifest*/
th.Command {
background: #3333FF;
font-weight: bold;
color: #ffffff;
}
th.Security {
background: #8e0000;
font-weight: bold;
color: #ffffff;
}
th.Medical {
background: #006600;
font-weight: bold;
color: #ffffff;
}
th.Engineering {
background: #b27300;
font-weight: bold;
color: #ffffff;
}
th.Science {
background: #a65ba6;
font-weight: bold;
color: #ffffff;
}
th.Cargo {
background: #bb9040;
font-weight: bold;
color: #ffffff;
}
th.Planetside{
background: #555555;
font-weight: bold;
color: #ffffff;
}
th.Civilian {
background: #a32800;
font-weight: bold;
color: #ffffff;
}
th.Miscellaneous {
background: #666666;
font-weight: bold;
color: #ffffff;
}
th.Silicon {
background: #222222;
font-weight: bold;
color: #ffffff;
}
/* Damage/health colors for crew monitoring computer */
.dead {
color: red;
}
.alive {
color: #7cfc00;
}
.burn {
color: orange;
}
.brute {
color: red;
}
.toxin {
color: lime;
}
.oxyloss {
color: cyan;
}
/* 75px width used in power monitoring console buttons */
.width75btn {
width: 75px;
}
/*Communicator Homescreen*/
div.homeContainer {
width: 100%;
text-align: center;
margin: auto;
padding-top: 5px;
}
div.homeScreen {
padding: 0 20px 0 20px;
}
.link64 {
float: left;
min-width: 15px;
max-width: 68px;
height: 64px;
text-align: center;
color: #ffffff;
text-decoration: none;
background: rgba(64, 98, 138, 0.6);
border: 1px solid #161616;
padding: 0 0 4px 0;
margin: 0 0 30px 5.5%;
cursor: default;
border-radius: 10px;
}
.link64:hover {
font-size: 13px;
}
/*Communicator Dialing*/
.dialPad {
clear: both;
text-align: center;
margin: auto;
}
.dialPadKeys {
float: left;
width: 47px;
height: 47px;
font-size: 32px;
text-align: center;
color: #ffffff;
text-decoration: none;
background: rgba(64, 98, 138, 0.15);
border: 1px inset rgba(100, 100, 100, 0.25);
cursor: default;
line-height: 47px;
}
.dialPadKeys:hover {
background: rgba(80, 122, 172, 0.5);
}
.dialPadButtons {
float: left;
width: 63.2px;
height: 63.2px;
text-align: center;
color: #ffffff;
text-decoration: none;
background: rgba(64, 98, 138, 0.15);
border: 1px inset rgba(100, 100, 100, 0.25);
padding: 0 0 4px 0;
cursor: default;
margin-bottom: 25px;
}
.dialPadButtons:hover {
background: rgba(80, 122, 172, 0.5);
font-size: 13px;
}
.dialPadAddress {
float: left;
width: 192px;
height: 18px;
background: rgba(64, 98, 138, 0.15);
color: #ffffff;
border-left: 1px inset #40628a;
border-top: 1px inset #40628a;
border-bottom: 1px inset #40628a;
}
.dialPadAddress:hover{
background: rgba(80, 122, 172, 0.5);
}
.dialPadClear {
float: left;
width: 19%;
height: 18px;
background: rgba(64, 98, 138, 0.15);
color: #ffffff;
border-right: 1px inset #40628a;
border-top: 1px inset #40628a;
border-bottom: 1px inset #40628a;
}
.dialPadClear:hover{
background: rgba(80, 122, 172, 0.5);
}
-5
View File
@@ -1,5 +0,0 @@
th.Exploration{
background: #bab421;
font-weight: bold;
color: #ffffff;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Some files were not shown because too many files have changed in this diff Show More