/** * A component that stores colors for use by painting-related items like spraycans or palettes * which can be accessed through a radial menu by right clicking the item while it's held by the user mob. * Right-clicking a color will open a color input prompt to edit it. Left clicking will instead select it * and call set_painting_tool_color() on the parent for more specific object behavior. */ /datum/component/palette /// The maximum number of colors this palette can have. var/max_colors /* * A list that stores a selection of colors. */ var/list/colors = list() /* * The currently selected color. This should be synced with that of the parent item, so please * use the item/proc/painting_tool_pick_color proc for color */ var/selected_color /// The persistent radial menu for this component. var/datum/radial_menu/persistent/color_picker_menu /// The radial menu choice datums are stored here as a microop to avoid generating new ones every time the menu is opened or updated. var/list/datum/radial_menu_choice/menu_choices /datum/component/palette/Initialize(max_colors, selected_color) if(!isitem(parent)) return COMPONENT_INCOMPATIBLE if(!isnum(max_colors) || max_colors < 1) /// This component means nothing if there's no space for colors stack_trace("palette component initialized without a proper value for the max_colors arg") return COMPONENT_INCOMPATIBLE src.max_colors = max_colors src.selected_color = selected_color || "#ffffff" RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF_SECONDARY, PROC_REF(on_attack_self_secondary)) RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) RegisterSignal(parent, COMSIG_PAINTING_TOOL_SET_COLOR, PROC_REF(on_painting_tool_set_color)) /datum/component/palette/Destroy() QDEL_NULL(color_picker_menu) QDEL_LIST(menu_choices) UnregisterSignal(parent, list(COMSIG_ITEM_ATTACK_SELF_SECONDARY, COMSIG_ATOM_EXAMINE, COMSIG_ITEM_DROPPED, COMSIG_PAINTING_TOOL_SET_COLOR, COMSIG_PAINTING_TOOL_GET_ADDITIONAL_DATA)) return ..() /datum/component/palette/proc/on_examine(datum/source, mob/user, list/examine_list) SIGNAL_HANDLER examine_list += span_notice("Right-Click this item while it's in your active hand to open/close its color picker menu.") examine_list += span_notice("In the color picker, Left-Click a color button to pick it or Right-Click to remove it.") /datum/component/palette/proc/on_attack_self_secondary(datum/source, mob/user) SIGNAL_HANDLER if(!color_picker_menu) INVOKE_ASYNC(src, PROC_REF(open_radial_menu), user) else close_radial_menu() return COMPONENT_CANCEL_ATTACK_CHAIN /datum/component/palette/proc/open_radial_menu(mob/user) var/list/choices = build_radial_list() color_picker_menu = show_radial_menu_persistent(user, parent, choices, select_proc = CALLBACK(src, PROC_REF(choice_selected), user), tooltips = TRUE, radial_slice_icon = "palette_bg") RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(close_radial_menu)) /datum/component/palette/proc/build_radial_list() var/radial_list = list() var/color_count = length(colors) LAZYSETLEN(menu_choices, max(color_count+1)) if(color_count < max_colors && !(selected_color in colors)) var/datum/radial_menu_choice/add_option = peek(menu_choices) if(!add_option) add_option = new menu_choices[color_count+1] = add_option var/image/element = image(icon = 'icons/hud/radial.dmi', icon_state = "palette_element") element.color = selected_color var/image/plus = image(icon = 'icons/hud/radial.dmi', icon_state = "palette_add") plus.appearance_flags = /image::appearance_flags | RESET_COLOR element.add_overlay(plus) add_option.image = element add_option.name = "Add Color ([selected_color])" radial_list["add"] = add_option for(var/index in 1 to length(colors)) var/hexcolor = colors[index] var/datum/radial_menu_choice/option = menu_choices[index] if(!option) option = new menu_choices[index] = option var/icon_state_to_use = hexcolor == selected_color ? "palette_selected" : "palette_element" var/image/element = image(icon = 'icons/hud/radial.dmi', icon_state = icon_state_to_use) element.color = hexcolor option.image = element // We want only the name/tooltip to show the hexcolor to avoid having multiple choices with same ids (identical colors). option.name = hexcolor radial_list["[index]"] = option return radial_list /datum/component/palette/proc/close_radial_menu() SIGNAL_HANDLER QDEL_NULL(color_picker_menu) UnregisterSignal(parent, COMSIG_ITEM_DROPPED) /datum/component/palette/proc/update_radial_list() if(QDELETED(color_picker_menu)) return var/list/choices = build_radial_list() color_picker_menu.change_choices(choices, tooltips = TRUE, keep_same_page = TRUE) /datum/component/palette/proc/choice_selected(mob/user, choice, params) if(!choice || IS_DEAD_OR_INCAP(user)) // center button or incapacitated but still holding on the item. close_radial_menu() return var/is_right_clicking = LAZYACCESS(params2list(params), RIGHT_CLICK) if(choice == "add") if(length(colors) < max_colors) colors += selected_color update_radial_list() return var/index = text2num(choice) if(is_right_clicking) colors.Cut(index, index+1) update_radial_list() else var/obj/item/parent_item = parent parent_item.set_painting_tool_color(colors[index]) // This will send a signal back to us. See below. /datum/component/palette/proc/on_painting_tool_set_color(datum/source, chosen_color) SIGNAL_HANDLER selected_color = chosen_color update_radial_list()