diff --git a/code/__DEFINES/_planes+layers.dm b/code/__DEFINES/_planes+layers.dm index b897a46c5f4..22a3b7f248e 100644 --- a/code/__DEFINES/_planes+layers.dm +++ b/code/__DEFINES/_planes+layers.dm @@ -416,6 +416,10 @@ // todo: deprecate #define HUD_LAYER_ABOVE 8 /// Things that reside above items (highlights). +#define RADIAL_BACKGROUND_LAYER 0 +///1000 is an unimportant number, it's just to normalize copied layers +#define RADIAL_CONTENT_LAYER 1000 + /** *! -- Player HUD Plane - Items *? Anything rendering in HUD as itself instead of as part of HUD is here. diff --git a/code/__DEFINES/appearance.dm b/code/__DEFINES/appearance.dm index faa97e8f066..1f7fe99f842 100644 --- a/code/__DEFINES/appearance.dm +++ b/code/__DEFINES/appearance.dm @@ -1,3 +1,5 @@ -// Consider these images/atoms as part of the UI/HUD -#define APPEARANCE_UI_IGNORE_ALPHA RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA -#define APPEARANCE_UI RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR +// Consider these images/atoms as part of the UI/HUD (apart of the appearance_flags) +/// Used for progress bars and chat messages +#define APPEARANCE_UI_IGNORE_ALPHA (RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA|PIXEL_SCALE) +/// Used for HUD objects +#define APPEARANCE_UI (RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|PIXEL_SCALE) diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 19fab494b13..3f8900d9e5c 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -515,3 +515,7 @@ GLOBAL_LIST_EMPTY(##LIST_NAME);\ //name for blank icon states for clothing #define CLOTHING_BLANK_ICON_STATE "blank" + +#define BUTTON_SLIDE_IN (1<<0) +#define BUTTON_FADE_IN (1<<1) +#define BUTTON_FADE_OUT (1<<2) diff --git a/code/game/rendering/legacy/alert.dm b/code/game/rendering/legacy/alert.dm index fce64d37e72..1e4b3af2ea9 100644 --- a/code/game/rendering/legacy/alert.dm +++ b/code/game/rendering/legacy/alert.dm @@ -119,8 +119,10 @@ owner = null return ..() -/atom/movable/screen/alert/MouseEntered(location,control,params) - openToolTip(usr, src, params, title = name, content = desc, theme = alerttooltipstyle) +/atom/movable/screen/alert/MouseEntered(location, control, params) + . = ..() + if(!QDELETED(src)) + openToolTip(usr, src, params, title = name, content = desc, theme = alerttooltipstyle) /atom/movable/screen/alert/MouseExited() closeToolTip(usr) diff --git a/code/game/rendering/legacy/ghost.dm b/code/game/rendering/legacy/ghost.dm index f7b5d59af92..2ad2e502d1e 100644 --- a/code/game/rendering/legacy/ghost.dm +++ b/code/game/rendering/legacy/ghost.dm @@ -2,6 +2,7 @@ icon = 'icons/screen/hud/styles/common/observer.dmi' /atom/movable/screen/ghost/MouseEntered(location,control,params) + . = ..() flick(icon_state + "_anim", src) openToolTip(usr, src, params, title = name, content = desc) diff --git a/code/game/rendering/legacy/radial.dm b/code/game/rendering/legacy/radial.dm index 6d37d8f09e0..10a2485d49c 100644 --- a/code/game/rendering/legacy/radial.dm +++ b/code/game/rendering/legacy/radial.dm @@ -11,24 +11,35 @@ GLOBAL_LIST_EMPTY(radial_menus) icon = 'icons/mob/radial.dmi' layer = HUD_LAYER_ABOVE plane = ABOVE_HUD_PLANE - appearance_flags = PIXEL_SCALE | NO_CLIENT_COLOR | KEEP_APART | RESET_TRANSFORM | RESET_ALPHA | RESET_COLOR + vis_flags = VIS_INHERIT_PLANE + var/click_on_hover = FALSE var/datum/radial_menu/parent -/atom/movable/screen/radial/Destroy() - parent = null - return ..() +/atom/movable/screen/radial/proc/set_parent(new_value) + if(parent) + UnregisterSignal(parent, COMSIG_PARENT_QDELETING) + parent = new_value + if(parent) + RegisterSignal(parent, COMSIG_PARENT_QDELETING, PROC_REF(handle_parent_del)) + +/atom/movable/screen/radial/proc/handle_parent_del() + SIGNAL_HANDLER + set_parent(null) /atom/movable/screen/radial/slice icon_state = "radial_slice" var/choice var/next_page = FALSE var/tooltips = FALSE + var/tooltip_theme /atom/movable/screen/radial/slice/MouseEntered(location, control, params) . = ..() icon_state = "radial_slice_focus" if(tooltips) - openToolTip(usr, src, params, title = name) + openToolTip(usr, src, params, title = name, theme = tooltip_theme) + if (click_on_hover && !isnull(usr) && !isnull(parent)) + Click(location, control, params) /atom/movable/screen/radial/slice/MouseExited(location, control, params) . = ..() @@ -41,7 +52,7 @@ GLOBAL_LIST_EMPTY(radial_menus) if(next_page) parent.next_page() else - parent.element_chosen(choice,usr) + parent.element_chosen(choice, usr, params) /atom/movable/screen/radial/center name = "Close Menu" @@ -57,15 +68,17 @@ GLOBAL_LIST_EMPTY(radial_menus) /atom/movable/screen/radial/center/Click(location, control, params) if(usr.client == parent.current_user) - parent.hide() parent.finished = TRUE /datum/radial_menu - var/list/choices = list() //List of choice id's - var/list/choices_icons = list() //choice_id -> icon - var/list/choices_values = list() //choice_id -> choice - var/list/page_data = list() //list of choices per page - + /// List of choice IDs + var/list/choices = list() + /// choice_id -> icon + var/list/choices_icons = list() + /// choice_id -> choice + var/list/choices_values = list() + /// list of choices per page + var/list/page_data = list() var/selected_choice var/list/atom/movable/screen/elements = list() @@ -89,14 +102,7 @@ GLOBAL_LIST_EMPTY(radial_menus) var/hudfix_method = TRUE //TRUE to change anchor to user, FALSE to shift by py_shift var/py_shift = 0 - var/entry_animation = TRUE - -/datum/radial_menu/Destroy() - Reset() - hide() - QDEL_NULL(close_button) - QDEL_LIST(elements) - return ..() + var/button_animation_flags = BUTTON_SLIDE_IN //If we swap to vis_contens inventory these will need a redo /datum/radial_menu/proc/check_screen_border(mob/user) @@ -109,6 +115,8 @@ GLOBAL_LIST_EMPTY(radial_menus) else py_shift = 32 restrict_to_dir(NORTH) //I was going to parse screen loc here but that's more effort than it's worth. + else if(hudfix_method && AM.loc) + anchor = get_atom_on_turf(anchor) //Sets defaults //These assume 45 deg min_angle @@ -127,7 +135,7 @@ GLOBAL_LIST_EMPTY(radial_menus) starting_angle = 180 ending_angle = 45 -/datum/radial_menu/proc/setup_menu(use_tooltips) +/datum/radial_menu/proc/setup_menu(use_tooltips, set_page = 1, click_on_hover = FALSE) if(ending_angle > starting_angle) zone = ending_angle - starting_angle else @@ -140,7 +148,9 @@ GLOBAL_LIST_EMPTY(radial_menus) for(var/i in 1 to elements_to_add) //Create all elements var/atom/movable/screen/radial/slice/new_element = new /atom/movable/screen/radial/slice new_element.tooltips = use_tooltips - new_element.parent = src + new_element.set_parent(src) + if(button_animation_flags & BUTTON_FADE_IN) + new_element.alpha = 0 elements += new_element var/page = 1 @@ -163,22 +173,31 @@ GLOBAL_LIST_EMPTY(radial_menus) page_data[page] = current pages = page - current_page = 1 - update_screen_objects(anim = entry_animation) + current_page = clamp(set_page, 1, pages) + update_screen_objects(button_animation_flags, click_on_hover) -/datum/radial_menu/proc/update_screen_objects(anim = FALSE) +/datum/radial_menu/proc/update_screen_objects(anim_flag = NONE, click_on_hover = FALSE) var/list/page_choices = page_data[current_page] var/angle_per_element = round(zone / page_choices.len) for(var/i in 1 to elements.len) - var/atom/movable/screen/radial/E = elements[i] + var/atom/movable/screen/radial/element = elements[i] var/angle = WRAP(starting_angle + (i - 1) * angle_per_element,0,360) if(i > page_choices.len) - HideElement(E) + HideElement(element) + element.click_on_hover = FALSE else - SetElement(E,page_choices[i],angle,anim = anim,anim_order = i) + SetElement(element,page_choices[i],angle,anim_flag = anim_flag,anim_order = i) + // Only activate click on hover after the animation plays + if (!click_on_hover) + continue + if (anim_flag) + addtimer(VARSET_CALLBACK(element, click_on_hover, TRUE), i * 0.5) + else + element.click_on_hover = TRUE /datum/radial_menu/proc/HideElement(atom/movable/screen/radial/slice/E) E.cut_overlays() + E.vis_contents.Cut() E.alpha = 0 E.name = "None" E.maptext = null @@ -186,11 +205,11 @@ GLOBAL_LIST_EMPTY(radial_menus) E.choice = null E.next_page = FALSE -/datum/radial_menu/proc/SetElement(atom/movable/screen/radial/slice/E,choice_id,angle,anim,anim_order) +/datum/radial_menu/proc/SetElement(atom/movable/screen/radial/slice/E, choice_id, angle, anim_flag, anim_order) //Position var/py = round(cos(angle) * radius) + py_shift var/px = round(sin(angle) * radius) - if(anim) + if(anim_flag & BUTTON_SLIDE_IN) var/timing = anim_order * 0.5 var/matrix/starting = matrix() starting.Scale(0.1,0.1) @@ -201,18 +220,25 @@ GLOBAL_LIST_EMPTY(radial_menus) E.pixel_y = py E.pixel_x = px - //Visuals - E.alpha = 255 + if(anim_flag & BUTTON_FADE_IN) + animate(E, alpha = 255, time = 0.15 SECONDS, easing = CUBIC_EASING|EASE_OUT) + else + E.alpha = 255 + E.mouse_opacity = MOUSE_OPACITY_ICON E.cut_overlays() + E.vis_contents.Cut() if(choice_id == NEXT_PAGE_ID) E.name = "Next Page" E.next_page = TRUE + E.icon_state = "radial_slice" // Resets the bg icon state to the default for next page buttons. E.add_overlay("radial_next") - E.compile_overlays() else if(istext(choices_values[choice_id])) E.name = choices_values[choice_id] + else if(ispath(choices_values[choice_id],/atom)) + var/atom/A = choices_values[choice_id] + E.name = initial(A.name) else var/atom/movable/AM = choices_values[choice_id] //Movables only E.name = AM.name @@ -221,11 +247,12 @@ GLOBAL_LIST_EMPTY(radial_menus) E.next_page = FALSE if(choices_icons[choice_id]) E.add_overlay(choices_icons[choice_id]) - E.compile_overlays() -/datum/radial_menu/New() +/datum/radial_menu/New(display_close_button) + if(!display_close_button) + return close_button = new - close_button.parent = src + close_button.set_parent(src) /datum/radial_menu/proc/Reset() choices.Cut() @@ -239,7 +266,7 @@ GLOBAL_LIST_EMPTY(radial_menus) /datum/radial_menu/proc/get_next_id() return "c_[choices.len]" -/datum/radial_menu/proc/set_choices(list/new_choices, use_tooltips) +/datum/radial_menu/proc/set_choices(list/new_choices, use_tooltips, click_on_hover = FALSE, set_page = 1) if(choices.len) Reset() for(var/E in new_choices) @@ -247,28 +274,17 @@ GLOBAL_LIST_EMPTY(radial_menus) choices += id choices_values[id] = E if(new_choices[E]) - var/image/I = extract_image(new_choices[E]) + var/I = extract_image(new_choices[E]) if(I) - //! perform fixup - I.plane = FLOAT_PLANE - I.layer = FLOAT_LAYER - I.maptext = MAPTEXT(I.maptext) - I.maptext_width = 64 - I.maptext_height = 32 - I.maptext_y = 32 - //! end choices_icons[id] = I - else - choices_icons[id] = extract_image(E) - setup_menu(use_tooltips) -/datum/radial_menu/proc/extract_image(E) - if(!isimage(E) && !isatom(E) && !ismutableappearance(E) && !IS_APPEARANCE(E)) - return null - var/mutable_appearance/MA = new /mutable_appearance(E) + setup_menu(use_tooltips, set_page, click_on_hover) + +/datum/radial_menu/proc/extract_image(to_extract_from) + var/mutable_appearance/MA = new /mutable_appearance(to_extract_from) if(MA) - MA.layer = HUD_LAYER_ABOVE MA.plane = ABOVE_HUD_PLANE + MA.layer = RADIAL_CONTENT_LAYER MA.appearance_flags |= RESET_TRANSFORM return MA @@ -277,16 +293,22 @@ GLOBAL_LIST_EMPTY(radial_menus) current_page = WRAP(current_page + 1,1,pages+1) update_screen_objects() -/datum/radial_menu/proc/show_to(mob/M) +/datum/radial_menu/proc/show_to(mob/M, offset_x = 0, offset_y = 0) if(current_user) hide() if(!M.client || !anchor) return current_user = M.client //Blank - menu_holder = image(icon='icons/effects/effects.dmi',loc=anchor,icon_state="nothing",layer = HUD_LAYER_ABOVE) - menu_holder.appearance_flags |= KEEP_APART - menu_holder.vis_contents += elements + close_button + menu_holder = image(icon='icons/effects/effects.dmi',loc=anchor,icon_state="nothing", layer = RADIAL_BACKGROUND_LAYER) + menu_holder.pixel_w = offset_x + menu_holder.pixel_z = offset_y + + menu_holder.plane = ABOVE_HUD_PLANE + menu_holder.appearance_flags |= KEEP_APART|RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM + menu_holder.vis_contents += elements + if(!isnull(close_button)) + menu_holder.vis_contents += close_button current_user.images += menu_holder /datum/radial_menu/proc/hide() @@ -304,34 +326,71 @@ GLOBAL_LIST_EMPTY(radial_menus) next_check = world.time + check_delay stoplag(1) +/datum/radial_menu/proc/remove_menu() + if(!(button_animation_flags & BUTTON_FADE_OUT)) + qdel(src) + return + for(var/atom/movable/element as anything in elements) + animate(element, alpha = 0, time = 0.15 SECONDS) + QDEL_IN(src, 0.5 SECONDS) + +/datum/radial_menu/Destroy() + Reset() + hide() + custom_check_callback = null + . = ..() + /* Presents radial menu to user anchored to anchor (or user if the anchor is currently in users screen) Choices should be a list where list keys are movables or text used for element names and return value and list values are movables/icons/images used for element icons */ -/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE) +/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE, autopick_single_option = TRUE, button_animation_flags = BUTTON_SLIDE_IN, click_on_hover = FALSE, user_space = FALSE, check_delay = DEFAULT_CHECK_DELAY, display_close_button = TRUE, radial_menu_offset = list(0, 0)) if(!user || !anchor || !length(choices)) return + + if(length(choices) == 1 && autopick_single_option) + return choices[1] + if(!uniqueid) uniqueid = "defmenu_[REF(user)]_[REF(anchor)]" if(GLOB.radial_menus[uniqueid]) + if(!no_repeat_close) + var/datum/radial_menu/menu = GLOB.radial_menus[uniqueid] + menu.finished = TRUE return - var/datum/radial_menu/menu = new + var/datum/radial_menu/menu = new(display_close_button) + menu.button_animation_flags = button_animation_flags + menu.check_delay = check_delay GLOB.radial_menus[uniqueid] = menu if(radius) menu.radius = radius if(istype(custom_check)) menu.custom_check_callback = custom_check - menu.anchor = anchor + menu.anchor = user_space ? user : anchor menu.check_screen_border(user) //Do what's needed to make it look good near borders or on hud - menu.set_choices(choices, tooltips) - menu.show_to(user) + menu.set_choices(choices, tooltips, click_on_hover) + var/offset_x = 0 + var/offset_y = 0 + if (user_space) + var/turf/user_turf = get_turf(user) + var/turf/anchor_turf = get_turf(anchor) + offset_x = (anchor_turf.x - user_turf.x) * world.icon_size + anchor.pixel_x - user.pixel_x + offset_y = (anchor_turf.y - user_turf.y) * world.icon_size + anchor.pixel_y - user.pixel_y + offset_x += radial_menu_offset[1] + offset_y += radial_menu_offset[2] + menu.show_to(user, offset_x, offset_y) menu.wait(user, anchor, require_near) var/answer = menu.selected_choice - QDEL_NULL(menu) + menu.remove_menu() GLOB.radial_menus -= uniqueid + if(require_near && !in_range(anchor, user)) + return + if(istype(custom_check)) + if(!custom_check.Invoke()) + return return answer /datum/radial_menu/context_menu diff --git a/code/game/rendering/screen.dm b/code/game/rendering/screen.dm index 79f6536adcb..17e9b7feb8d 100644 --- a/code/game/rendering/screen.dm +++ b/code/game/rendering/screen.dm @@ -2,9 +2,10 @@ //* Copyright (c) 2024 Citadel Station Developers *// /atom/movable/screen - appearance_flags = PIXEL_SCALE | NO_CLIENT_COLOR plane = HUD_PLANE layer = HUD_LAYER_BASE + animate_movement = SLIDE_STEPS + appearance_flags = APPEARANCE_UI var/obj/master = null //A reference to the object in the slot. Grabs or items, generally. var/datum/hud/hud_legacy = null // A reference to the owner HUD, if any. diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index e2ee9e6bb7f..218436c6b3b 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -216,7 +216,6 @@ // Instantiate cutscene system spawn(1) init_cutscene_system() - tooltips = new(src) //* Setup on-map HUDs *// action_drawer = new(src) @@ -278,8 +277,9 @@ tgui_panel.initialize() // initialize cutscene browser // - (we don't, the JS does it for us.) - - // Initialize tooltips - tooltips.initialize() + //This is down here because of the browse() calls in tooltip/New() + if(!tooltips) + tooltips = new /datum/tooltip(src) connection_time = world.time connection_realtime = world.realtime diff --git a/code/modules/tooltip/tooltip.dm b/code/modules/tooltip/tooltip.dm index 0b5ff331feb..5d4dcd55757 100644 --- a/code/modules/tooltip/tooltip.dm +++ b/code/modules/tooltip/tooltip.dm @@ -1,16 +1,4 @@ /* -Tooltips v1.1 - 22/10/15 -Developed by Wire (#goonstation on irc.synirc.net) -- Added support for screen_loc pixel offsets. Should work. Maybe. -- Added init function to more efficiently send base vars - -Configuration: -- Set control to the correct skin element (remember to actually place the skin element) -- Set file to the correct path for the .html file (remember to actually place the html file) -- Attach the datum to the user client on login, e.g. - /client/New() - src.tooltips = new /datum/tooltip(src) - Usage: - Define mouse event procs on your (probably HUD) object and simply call the show and hide procs respectively: /atom/movable/screen/hud @@ -26,51 +14,41 @@ Customization: Notes: - You may have noticed 90% of the work is done via javascript on the client. Gotta save those cycles man. -- This is entirely untested in any other codebase besides goonstation so I have no idea if it will port nicely. Good luck! - - After testing and discussion (Wire, Remie, MrPerson, AnturK) ToolTips are ok and work for /tg/station13 */ /datum/tooltip - var/client/client + var/client/owner var/control = "mainwindow.tooltip" var/showing = 0 var/queueHide = 0 var/init = 0 + var/atom/last_target + /datum/tooltip/New(client/C) - if(!C) - return - client = C + if (C) + owner = C + SSassets.send_asset_pack(owner, /datum/asset_pack/simple/jquery) + owner << browse(file2text('code/modules/tooltip/tooltip.html'), "window=[control]") -/datum/tooltip/Destroy() - client = null - return ..() - -/datum/tooltip/proc/initialize() - if(!client.initialized) - // todo: this should be a timer, but current MC doesn't really support that until we have - // MC init stages - spawn(1 SECONDS) - UNTIL(!client || client.initialized) - if(!client) - return - boot() - else - spawn(0) - boot() - -/datum/tooltip/proc/boot() - SSassets.send_asset_pack(client, /datum/asset_pack/simple/jquery) - client << browse(file2text('code/modules/tooltip/tooltip.html'), "window=[control]") + ..() /datum/tooltip/proc/show(atom/movable/thing, params = null, title = null, content = null, theme = "default", special = "none") - if (!thing || !params || (!title && !content) || !client || !isnum(world.icon_size)) + if (!thing || !params || (!title && !content) || !owner || !isnum(world.icon_size)) return FALSE + + if (!isnull(last_target)) + UnregisterSignal(last_target, COMSIG_PARENT_QDELETING) + + RegisterSignal(thing, COMSIG_PARENT_QDELETING, PROC_REF(on_target_qdel)) + + last_target = thing + if (!init) //Initialize some vars init = 1 - client << output(list2params(list(world.icon_size, control)), "[control]:tooltip.init") + owner << output(list2params(list(world.icon_size, control)), "[control]:tooltip.init") showing = 1 @@ -90,7 +68,8 @@ Notes: params = {"{ "cursor": "[params]", "screenLoc": "[thing.screen_loc]" }"} //Send stuff to the tooltip - client << output(list2params(list(params, client.current_viewport_width, client.current_viewport_height, "[title][content]", theme, special)), "[control]:tooltip.update") + var/view_size = decode_view_size(owner.view) + owner << output(list2params(list(params, view_size[1] , view_size[2], "[title][content]", theme, special)), "[control]:tooltip.update") //If a hide() was hit while we were showing, run hide() again to avoid stuck tooltips showing = 0 @@ -103,34 +82,42 @@ Notes: queueHide = showing ? TRUE : FALSE if (queueHide) - addtimer(CALLBACK(src, PROC_REF(do_hide)), 1) + addtimer(CALLBACK(src, PROC_REF(do_hide)), 0.1 SECONDS) else do_hide() return TRUE +/datum/tooltip/proc/on_target_qdel() + SIGNAL_HANDLER + + INVOKE_ASYNC(src, PROC_REF(hide)) + last_target = null + /datum/tooltip/proc/do_hide() - winshow(client, control, FALSE) - -/* TG SPECIFIC CODE */ + winshow(owner, control, FALSE) +/datum/tooltip/Destroy(force) + last_target = null + return ..() //Open a tooltip for user, at a location based on params //Theme is a CSS class in tooltip.html, by default this wrapper chooses a CSS class based on the user's UI_style (Midnight, Plasmafire, Retro, etc) //Includes sanity.checks /proc/openToolTip(mob/user = null, atom/movable/tip_src = null, params = null, title = "", content = "", theme = "") - if(istype(user)) - if(user.client && user.client.tooltips) - if(!theme) - theme = lowertext(user.get_preference_entry(/datum/game_preference_entry/dropdown/tooltip_style)) - if(!theme) - theme = "midnight" - user.client.tooltips.show(tip_src, params, title, content, theme) + if(!istype(user) || !user.client?.tooltips) + return + var/ui_style = user.get_preference_entry(/datum/game_preference_entry/dropdown/tooltip_style) + if(!theme && ui_style) + theme = lowertext(ui_style) + if(!theme) + theme = "default" + user.client.tooltips.show(tip_src, params, title, content, theme) //Arbitrarily close a user's tooltip //Includes sanity checks. /proc/closeToolTip(mob/user) - if(istype(user)) - if(user.client && user.client.tooltips) - user.client.tooltips.hide() + if(!istype(user) || !user.client?.tooltips) + return + user.client.tooltips.hide() diff --git a/code/modules/tooltip/tooltip.html b/code/modules/tooltip/tooltip.html index 5be29994cf1..0dff6882735 100644 --- a/code/modules/tooltip/tooltip.html +++ b/code/modules/tooltip/tooltip.html @@ -1,261 +1,419 @@ - + -
-