/obj/screen/movable/action_button var/datum/action/linked_action var/datum/hud/our_hud var/actiontooltipstyle = "" screen_loc = null icon = null // we don't use the base icon at all, just underlays and overlays /// The icon state of our active overlay, used to prevent re-applying identical overlays var/active_overlay_icon_state /// The icon state of our active underlay, used to prevent re-applying identical underlays var/active_underlay_icon_state /// The overlay we have overtop our button var/mutable_appearance/button_overlay /// Where we are currently placed on the hud. SCRN_OBJ_DEFAULT asks the linked action what it thinks var/location = SCRN_OBJ_DEFAULT /// A unique bitflag, combined with the name of our linked action this lets us persistently remember any user changes to our position var/id /// A weakref of the last thing we hovered over /// God I hate how dragging works var/datum/weakref/last_hovored_ref /obj/screen/movable/action_button/Destroy() if(our_hud) var/mob/viewer = our_hud.mymob our_hud.hide_action(src) viewer?.client?.screen -= src linked_action.viewers -= our_hud viewer.update_action_buttons() our_hud = null linked_action = null return ..() /obj/screen/movable/action_button/proc/can_use(mob/user) // if(isobserver(user)) // var/mob/dead/observer/dead_mob = user // if(dead_mob.observetarget) // Observers can only click on action buttons if they're not observing something // return FALSE if(linked_action) if(linked_action.viewers[user.hud_used]) return TRUE return FALSE return TRUE /obj/screen/movable/action_button/Click(location,control,params) if(!can_use(usr)) return var/list/modifiers = params2list(params) if(LAZYACCESS(modifiers, SHIFT_CLICK)) var/datum/hud/our_hud = usr.hud_used our_hud.position_action(src, SCRN_OBJ_DEFAULT) return TRUE if(!usr.checkClickCooldown()) return usr.setClickCooldown(1) var/trigger_flags if(LAZYACCESS(modifiers, RIGHT_CLICK)) trigger_flags |= TRIGGER_SECONDARY_ACTION linked_action.Trigger(trigger_flags = trigger_flags) return TRUE // Entered and Exited won't fire while you're dragging something, because you're still "holding" it // Very much byond logic, but I want nice behavior, so we fake it with drag /obj/screen/movable/action_button/MouseDrag(atom/over_object, src_location, over_location, src_control, over_control, params) . = ..() if(!can_use(usr)) return if(IS_WEAKREF_OF(over_object, last_hovored_ref)) return var/atom/old_object if(last_hovored_ref) old_object = last_hovored_ref.resolve() else // If there is no current ref, we assume it was us. We also treat this as our "first go" location. old_object = src var/datum/hud/our_hud = usr.hud_used our_hud?.generate_landings(src) if(old_object) old_object.MouseExited(over_location, over_control, params) last_hovored_ref = WEAKREF(over_object) over_object?.MouseEntered(over_location, over_control, params) /obj/screen/movable/action_button/MouseEntered(location, control, params) . = ..() if(!QDELETED(src)) openToolTip(usr, src, params, title = name, content = desc, theme = actiontooltipstyle) /obj/screen/movable/action_button/MouseExited(location, control, params) closeToolTip(usr) return ..() /obj/screen/movable/action_button/MouseDrop(over_object) last_hovored_ref = null if(!can_use(usr)) return var/datum/hud/our_hud = usr.hud_used if(over_object == src) our_hud.hide_landings() return if(istype(over_object, /obj/screen/action_landing)) var/obj/screen/action_landing/reserve = over_object reserve.hit_by(src) our_hud.hide_landings() save_position() return our_hud.hide_landings() if(istype(over_object, /obj/screen/button_palette) || istype(over_object, /obj/screen/palette_scroll)) our_hud.position_action(src, SCRN_OBJ_IN_PALETTE) save_position() return if(istype(over_object, /obj/screen/movable/action_button)) var/obj/screen/movable/action_button/button = over_object our_hud.position_action_relative(src, button) save_position() return . = ..() our_hud.position_action(src, screen_loc) save_position() /obj/screen/movable/action_button/proc/save_position() var/mob/user = our_hud.mymob if(!user?.client) return var/position_info = "" switch(location) if(SCRN_OBJ_FLOATING) position_info = screen_loc if(SCRN_OBJ_IN_LIST) position_info = SCRN_OBJ_IN_LIST if(SCRN_OBJ_IN_PALETTE) position_info = SCRN_OBJ_IN_PALETTE LAZYSET(user.client.prefs.action_button_screen_locs, "[name]_[id]", position_info) /obj/screen/movable/action_button/proc/load_position() var/mob/user = our_hud.mymob if(!user) return var/position_info = LAZYACCESS(user.client?.prefs?.action_button_screen_locs, "[name]_[id]") || SCRN_OBJ_DEFAULT user.hud_used.position_action(src, position_info) /obj/screen/movable/action_button/proc/dump_save() var/mob/user = our_hud.mymob if(!user?.client) return LAZYREMOVE(user.client.prefs.action_button_screen_locs, "[name]_[id]") /** * This is a silly proc used in hud code code to determine what icon and icon state we should be using * for hud elements (such as action buttons) that don't have their own icon and icon state set. * * It returns a list, which is pretty much just a struct of info */ /datum/hud/proc/get_action_buttons_icons() . = list() .["bg_icon"] = 'icons/mob/actions/backgrounds.dmi' // ui_style // TODO: Implement hud-specific icon stuff .["bg_state"] = "bg_default" .["bg_state_active"] = "bg_default_on" /** * Updates all action buttons this mob has. * * Arguments: * * update_flags - Which flags of the action should we update * * force - Force buttons update even if the given button icon state has not changed */ /mob/proc/update_mob_action_buttons(update_flags = ALL, force = FALSE) for(var/datum/action/current_action as anything in actions) current_action.build_all_button_icons(update_flags, force) /** * This proc handles adding all of the mob's actions to their screen * * If you just need to update existing buttons, use [/mob/proc/update_mob_action_buttons]! * * Arguments: * * update_flags - reload_screen - bool, if TRUE, this proc will add the button to the screen of the passed mob as well */ /mob/proc/update_action_buttons(reload_screen = FALSE) if(!hud_used || !client) return if(!hud_used.hud_shown) //Hud toggled to minimal return for(var/datum/action/action as anything in actions) var/obj/screen/movable/action_button/button = action.viewers[hud_used] action.build_all_button_icons() if(reload_screen) client.screen += button if(reload_screen) hud_used.update_our_owner() // This holds the logic for the palette buttons hud_used?.palette_actions?.refresh_actions() /** * Show (most) of the another mob's action buttons to this mob * * Used for observers viewing another mob's screen */ /mob/proc/show_other_mob_action_buttons(mob/take_from) if(!hud_used || !client) return for(var/datum/action/action as anything in take_from.actions) if(!action.show_to_observers) continue action.GiveAction(src) RegisterSignal(take_from, COMSIG_MOB_GRANTED_ACTION, PROC_REF(on_observing_action_granted)) RegisterSignal(take_from, COMSIG_MOB_REMOVED_ACTION, PROC_REF(on_observing_action_removed)) /** * Hide another mob's action buttons from this mob * * Used for observers viewing another mob's screen */ /mob/proc/hide_other_mob_action_buttons(mob/take_from) for(var/datum/action/action as anything in take_from.actions) action.HideFrom(src) UnregisterSignal(take_from, list(COMSIG_MOB_GRANTED_ACTION, COMSIG_MOB_REMOVED_ACTION)) /// Signal proc for [COMSIG_MOB_GRANTED_ACTION] - If we're viewing another mob's action buttons, /// we need to update with any newly added buttons granted to the mob. /mob/proc/on_observing_action_granted(mob/living/source, datum/action/action) SIGNAL_HANDLER if(!action.show_to_observers) return action.GiveAction(src) /// Signal proc for [COMSIG_MOB_REMOVED_ACTION] - If we're viewing another mob's action buttons, /// we need to update with any removed buttons from the mob. /mob/proc/on_observing_action_removed(mob/living/source, datum/action/action) SIGNAL_HANDLER action.HideFrom(src) // Button Palette // A new way to interact with actions /obj/screen/button_palette desc = "Drag buttons to move them
Shift-click any button to reset it
Alt-click this to reset all buttons" icon = 'icons/hud/64x16_actions.dmi' icon_state = "screen_gen_palette" screen_loc = ui_action_palette var/datum/hud/our_hud var/expanded = FALSE /// Id of any currently running timers that set our color matrix var/color_timer_id /obj/screen/button_palette/Destroy() if(our_hud) our_hud.mymob?.client?.screen -= src our_hud.toggle_palette = null our_hud = null return ..() /obj/screen/button_palette/Initialize(mapload) . = ..() // update_appearance() update_name() /obj/screen/button_palette/proc/set_hud(datum/hud/our_hud) src.our_hud = our_hud refresh_owner() // /obj/screen/button_palette/update_name(updates) /obj/screen/button_palette/proc/update_name() // . = ..() if(expanded) name = "Hide Buttons" else name = "Show Buttons" /obj/screen/button_palette/proc/refresh_owner() var/mob/viewer = our_hud.mymob if(viewer.client) viewer.client.screen |= src // var/list/settings = our_hud.get_action_buttons_icons() // var/ui_icon = "[settings["bg_icon"]]" // var/list/ui_segments = splittext(ui_icon, ".") // var/list/ui_paths = splittext(ui_segments[1], "/") // var/ui_name = ui_paths[length(ui_paths)] // icon_state = "[ui_name]_palette" /obj/screen/button_palette/MouseEntered(location, control, params) . = ..() if(QDELETED(src)) return show_tooltip(params) /obj/screen/button_palette/MouseExited() closeToolTip(usr) return ..() /obj/screen/button_palette/proc/show_tooltip(params) openToolTip(usr, src, params, title = name, content = desc) GLOBAL_LIST_INIT(palette_added_matrix, list(0.4,0.5,0.2,0, 0,1.4,0,0, 0,0.4,0.6,0, 0,0,0,1, 0,0,0,0)) GLOBAL_LIST_INIT(palette_removed_matrix, list(1.4,0,0,0, 0.7,0.4,0,0, 0.4,0,0.6,0, 0,0,0,1, 0,0,0,0)) /obj/screen/button_palette/proc/play_item_added() color_for_now(GLOB.palette_added_matrix) /obj/screen/button_palette/proc/play_item_removed() color_for_now(GLOB.palette_removed_matrix) /obj/screen/button_palette/proc/color_for_now(list/color) if(color_timer_id) return add_atom_colour(color, TEMPORARY_COLOUR_PRIORITY) //We unfortunately cannot animate matrix colors. Curse you lummy it would be ~~non~~trivial to interpolate between the two valuessssssssss color_timer_id = addtimer(CALLBACK(src, PROC_REF(remove_color), color), 2 SECONDS) /obj/screen/button_palette/proc/remove_color(list/to_remove) color_timer_id = null remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, to_remove) /obj/screen/button_palette/proc/can_use(mob/user) if(isobserver(user)) // var/mob/dead/observer/O = user // return !O.observetarget return TRUE return TRUE /obj/screen/button_palette/Click(location, control, params) if(!can_use(usr)) return var/list/modifiers = params2list(params) if(LAZYACCESS(modifiers, ALT_CLICK)) for(var/datum/action/action as anything in usr.actions) // Reset action positions to default for(var/datum/hud/hud as anything in action.viewers) var/obj/screen/movable/action_button/button = action.viewers[hud] hud.position_action(button, SCRN_OBJ_DEFAULT) to_chat(usr, span_notice("Action button positions have been reset.")) return TRUE set_expanded(!expanded) /obj/screen/button_palette/proc/clicked_while_open(datum/source, atom/target, atom/location, control, params, mob/user) if(istype(target, /obj/screen/movable/action_button) || istype(target, /obj/screen/palette_scroll) || target == src) // If you're clicking on an action button, or us, you can live return set_expanded(FALSE) if(source) UnregisterSignal(source, COMSIG_CLIENT_CLICK) /obj/screen/button_palette/proc/set_expanded(new_expanded) var/datum/action_group/our_group = our_hud.palette_actions if(!length(our_group.actions)) //Looks dumb, trust me lad new_expanded = FALSE if(expanded == new_expanded) return expanded = new_expanded our_group.refresh_actions() // update_appearance() update_name() if(!usr.client) return if(expanded) RegisterSignal(usr.client, COMSIG_CLIENT_CLICK, PROC_REF(clicked_while_open)) else UnregisterSignal(usr.client, COMSIG_CLIENT_CLICK) closeToolTip(usr) //Our tooltips are now invalid, can't seem to update them in one frame, so here, just close them /obj/screen/palette_scroll icon = 'icons/hud/screen_gen.dmi' screen_loc = ui_palette_scroll /// How should we move the palette's actions? /// Positive scrolls down the list, negative scrolls back var/scroll_direction = 0 var/datum/hud/our_hud /obj/screen/palette_scroll/proc/can_use(mob/user) if(isobserver(user)) // var/mob/dead/observer/O = user // return !O.observetarget return TRUE return TRUE /obj/screen/palette_scroll/proc/set_hud(datum/hud/our_hud) src.our_hud = our_hud refresh_owner() /obj/screen/palette_scroll/proc/refresh_owner() var/mob/viewer = our_hud.mymob if(viewer.client) viewer.client.screen |= src // var/list/settings = our_hud.get_action_buttons_icons() // icon = settings["bg_icon"] /obj/screen/palette_scroll/Click(location, control, params) if(!can_use(usr)) return our_hud.palette_actions.scroll(scroll_direction) /obj/screen/palette_scroll/MouseEntered(location, control, params) . = ..() if(QDELETED(src)) return openToolTip(usr, src, params, title = name, content = desc) /obj/screen/palette_scroll/MouseExited() closeToolTip(usr) return ..() /obj/screen/palette_scroll/down name = "Scroll Down" desc = "Click on this to scroll the actions above down" icon_state = "scroll_down" scroll_direction = 1 /obj/screen/palette_scroll/down/Destroy() if(our_hud) our_hud.mymob?.client?.screen -= src our_hud.palette_down = null our_hud = null return ..() /obj/screen/palette_scroll/up name = "Scroll Up" desc = "Click on this to scroll the actions above up" icon_state = "scroll_up" scroll_direction = -1 /obj/screen/palette_scroll/up/Destroy() if(our_hud) our_hud.mymob?.client?.screen -= src our_hud.palette_up = null our_hud = null return ..() /// Exists so you have a place to put your buttons when you move them around /obj/screen/action_landing name = "Button Space" desc = "Drag and drop a button into this spot
to add it to the group" icon = 'icons/hud/screen_gen.dmi' icon_state = "reserved" // We want our whole 32x32 space to be clickable, so dropping's forgiving mouse_opacity = MOUSE_OPACITY_OPAQUE var/datum/action_group/owner /obj/screen/action_landing/Destroy() if(owner) owner.landing = null owner?.owner?.mymob?.client?.screen -= src owner.refresh_actions() owner = null return ..() /obj/screen/action_landing/proc/set_owner(datum/action_group/owner) src.owner = owner refresh_owner() /obj/screen/action_landing/proc/refresh_owner() var/datum/hud/our_hud = owner.owner var/mob/viewer = our_hud.mymob if(viewer.client) viewer.client.screen |= src // var/list/settings = our_hud.get_action_buttons_icons() // icon = settings["bg_icon"] /// Reacts to having a button dropped on it /obj/screen/action_landing/proc/hit_by(obj/screen/movable/action_button/button) var/datum/hud/our_hud = owner.owner our_hud.position_action(button, owner.location)