// This is the window/UI manager for Nano UI // There should only ever be one (global) instance of nanomanger /datum/nanomanager // a list of current open /nanoui UIs, grouped by src_object and ui_key var/nano_open_uis[0] // a list of current open /nanoui UIs, not grouped, for use in processing var/list/processing_uis = list() // a list of asset filenames which are to be sent to the client on user logon var/list/asset_files = list() /** * Create a new nanomanager instance. * This proc generates a list of assets which are to be sent to each client on connect * * @return /nanomanager new nanomanager object */ //Uncomment to enable nano file debugging // #define NANO_DEBUG 1 /datum/nanomanager/proc/rebuild_asset_dirs() asset_files.len = 0 var/list/nano_asset_dirs = list(\ "nano/css/",\ "nano/images/",\ "nano/js/",\ "nano/templates/"\ ) var/list/filenames = null for (var/path in nano_asset_dirs) #ifdef NANO_DEBUG world.log << "loading [path]" #endif filenames = flist(path) for(var/filename in filenames) if(copytext(filename, length(filename)) != "/") // filenames which end in "/" are actually directories, which we want to ignore if(fexists(path + filename)) #ifdef NANO_DEBUG world.log << "Found [path+filename]!" #endif asset_files.Add(fcopy_rsc(path + filename)) // add this file to asset_files for sending to clients when they connect return /datum/nanomanager/New() var/list/nano_asset_dirs = list(\ "nano/css/",\ "nano/images/",\ "nano/js/",\ "nano/templates/"\ ) var/list/filenames = null for (var/path in nano_asset_dirs) #ifdef NANO_DEBUG world.log << "loading [path]" #endif filenames = flist(path) for(var/filename in filenames) if(copytext(filename, length(filename)) != "/") // filenames which end in "/" are actually directories, which we want to ignore if(fexists(path + filename)) #ifdef NANO_DEBUG world.log << "Found [path+filename]!" #endif asset_files.Add(fcopy_rsc(path + filename)) // add this file to asset_files for sending to clients when they connect return /** * 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/nanomanager/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 != NANOUI_FORCE_OPEN) ui.push_data(data) if (force_open == NANOUI_FOCUS) ui.focus() return ui else //testing("nanomanager/try_update_ui mob [user.name] [src_object:name] [ui_key] [force_open] - forcing opening of ui") ui.close() 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/nanomanager/proc/get_open_ui(var/mob/user, src_object, ui_key) var/src_object_key = "\ref[src_object]" if (isnull(nano_open_uis[src_object_key]) || !istype(nano_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(nano_open_uis[src_object_key][ui_key]) || !istype(nano_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 nano_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/nanomanager/proc/update_uis(src_object) var/src_object_key = "\ref[src_object]" if (isnull(nano_open_uis[src_object_key]) || !istype(nano_open_uis[src_object_key], /list)) return 0 var/update_count = 0 for (var/ui_key in nano_open_uis[src_object_key]) for (var/datum/nanoui/ui in nano_open_uis[src_object_key][ui_key]) if(ui && ui.src_object && ui.user) ui.process(1) update_count++ return update_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/nanomanager/proc/update_user_uis(var/mob/user, src_object = null, ui_key = null) if (isnull(user.nano_open_uis) || !istype(user.nano_open_uis, /list) || nano_open_uis.len == 0) return 0 // has no open uis var/update_count = 0 for (var/datum/nanoui/ui in user.nano_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/nanomanager/proc/close_user_uis(var/mob/user, src_object = null, ui_key = null) if (isnull(user.nano_open_uis) || !istype(user.nano_open_uis, /list) || nano_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.nano_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 [nano_open_uis.len] of [close_count] uis") return close_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 closed */ /datum/nanomanager/proc/close_uis(src_object) var/src_object_key = "\ref[src_object]" if(!istype(nano_open_uis[src_object_key], /list)) return 0 var/close_count = 0 for(var/ui_key in nano_open_uis[src_object_key]) for(var/datum/nanoui/ui in nano_open_uis[src_object_key][ui_key]) ui.close() close_count++ 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/nanomanager/proc/ui_opened(var/datum/nanoui/ui) var/src_object_key = "\ref[ui.src_object]" if (isnull(nano_open_uis[src_object_key]) || !istype(nano_open_uis[src_object_key], /list)) nano_open_uis[src_object_key] = list(ui.ui_key = list()) else if (isnull(nano_open_uis[src_object_key][ui.ui_key]) || !istype(nano_open_uis[src_object_key][ui.ui_key], /list)) nano_open_uis[src_object_key][ui.ui_key] = list(); ui.user.nano_open_uis.Add(ui) var/list/uis = nano_open_uis[src_object_key][ui.ui_key] uis.Add(ui) processing_uis.Add(ui) //testing("nanomanager/ui_opened mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.nano_open_uis [ui.user.nano_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/nanomanager/proc/ui_closed(var/datum/nanoui/ui) var/src_object_key = "\ref[ui.src_object]" if (isnull(nano_open_uis[src_object_key]) || !istype(nano_open_uis[src_object_key], /list)) return 0 // wasn't open else if (isnull(nano_open_uis[src_object_key][ui.ui_key]) || !istype(nano_open_uis[src_object_key][ui.ui_key], /list)) return 0 // wasn't open processing_uis.Remove(ui) if(ui.user) ui.user.nano_open_uis.Remove(ui) var/list/uis = nano_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.nano_open_uis [ui.user.nano_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/nanomanager/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/nanomanager/proc/user_transferred(var/mob/oldMob, var/mob/newMob) if(!istype(oldMob)) return 0 // no mob, no uis //testing("nanomanager/user_transferred from mob [oldMob.name] to mob [newMob.name]") if (isnull(oldMob.nano_open_uis) || !istype(oldMob.nano_open_uis, /list) || nano_open_uis.len == 0) //testing("nanomanager/user_transferred mob [oldMob.name] has no open uis") return 0 // has no open uis if (isnull(newMob.nano_open_uis) || !istype(newMob.nano_open_uis, /list)) newMob.nano_open_uis = list() for (var/datum/nanoui/ui in oldMob.nano_open_uis) ui.user = newMob newMob.nano_open_uis.Add(ui) oldMob.nano_open_uis.len = 0 return 1 // success /** * Sends all nano assets to the client * This is called on user login * * @param client /client The user's client * * @return nothing */ /datum/nanomanager/proc/send_resources(client) for(var/file in asset_files) world.log << file client << browse_rsc(file) // send the file to the client /** * Sends a message to the client-side JS of UIs on the object. * * @param src_object /datum The object owning the interface being sent to. * @param ui_key string The string key of the UI being sent to. * @param js_function string The name of the JS function to execute. * @param data list List of arguments to send to the JS function. * @param user /mob If provided, a specific mob to send to. If null, all mobs with the UI open will be sent to. * * @return nothing */ /datum/nanomanager/proc/send_message(src_object, ui_key, js_function, data, mob/user = null) var/src_object_key = "\ref[src_object]" if (isnull(nano_open_uis[src_object_key])) return 0 var/paramlist = list2params(data) var/update_count = 0 for (var/datum/nanoui/ui in nano_open_uis[src_object_key][ui_key]) if (!ui.src_object || (user != null && ui.user != user)) continue ui.send_message(js_function, paramlist) update_count += 1 return update_count