diff --git a/code/modules/tgui_input/checkboxes.dm b/code/modules/tgui_input/checkboxes.dm new file mode 100644 index 0000000000..0b1d653955 --- /dev/null +++ b/code/modules/tgui_input/checkboxes.dm @@ -0,0 +1,136 @@ +/** + * ### tgui_input_checkbox + * Opens a window with a list of checkboxes and returns a list of selected choices. + * + * user - The mob to display the window to + * message - The message inside the window + * title - The title of the window + * list/items - The list of items to display + * min_checked - The minimum number of checkboxes that must be checked (defaults to 1) + * max_checked - The maximum number of checkboxes that can be checked (optional) + * timeout - The timeout for the input (optional) + */ +/proc/tgui_input_checkboxes(mob/user, message, title = "Select", list/items, min_checked = 1, max_checked = 50, timeout = 0, ui_state = GLOB.tgui_always_state) + if (!user) + user = usr + if(!length(items)) + return + if (!istype(user)) + if (istype(user, /client)) + var/client/client = user + user = client.mob + else + return + if(!user.client.prefs.tgui_input_mode) + return input(user, message, title) as null|anything in items + var/datum/tgui_checkbox_input/input = new(user, message, title, items, min_checked, max_checked, timeout, ui_state) + input.tgui_interact(user) + input.wait() + if (input) + . = input.choices + qdel(input) + +/// Window for tgui_input_checkboxes +/datum/tgui_checkbox_input + /// Title of the window + var/title + /// Message to display + var/message + /// List of items to display + var/list/items + /// List of selected items + var/list/choices + /// Time when the input was created + var/start_time + /// Timeout for the input + var/timeout + /// Whether the input was closed + var/closed + /// Minimum number of checkboxes that must be checked + var/min_checked + /// Maximum number of checkboxes that can be checked + var/max_checked + /// The TGUI UI state that will be returned in ui_state(). Default: always_state + var/datum/tgui_state/state + +/datum/tgui_checkbox_input/New(mob/user, message, title, list/items, min_checked, max_checked, timeout, ui_state) + src.title = title + src.message = message + src.items = items.Copy() + src.min_checked = min_checked + src.max_checked = max_checked + src.state = ui_state + + if (timeout) + src.timeout = timeout + start_time = world.time + QDEL_IN(src, timeout) + +/datum/tgui_checkbox_input/Destroy(force, ...) + SStgui.close_uis(src) + state = null + QDEL_NULL(items) + + return ..() + +/datum/tgui_checkbox_input/proc/wait() + while (!closed && !QDELETED(src)) + stoplag(1) + +/datum/tgui_checkbox_input/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "CheckboxInput") + ui.open() + +/datum/tgui_checkbox_input/tgui_close(mob/user) + . = ..() + closed = TRUE + +/datum/tgui_checkbox_input/tgui_state(mob/user) + return state + +/datum/tgui_checkbox_input/tgui_data(mob/user) + var/list/data = list() + + if(timeout) + data["timeout"] = CLAMP01((timeout - (world.time - start_time) - 1 SECONDS) / (timeout - 1 SECONDS)) + + return data + +/datum/tgui_checkbox_input/tgui_static_data(mob/user) + var/list/data = list() + + data["items"] = items + data["min_checked"] = min_checked + data["max_checked"] = max_checked + data["large_buttons"] = user.client.prefs.tgui_large_buttons + data["message"] = message + data["swapped_buttons"] = !user.client.prefs.tgui_swapped_buttons + data["title"] = title + + return data + +/datum/tgui_checkbox_input/tgui_act(action, list/params) + . = ..() + if (.) + return + + switch(action) + if("submit") + var/list/selections = params["entry"] + if(length(selections) >= min_checked && length(selections) <= max_checked) + set_choices(selections) + closed = TRUE + SStgui.close_uis(src) + return TRUE + + if("cancel") + closed = TRUE + SStgui.close_uis(src) + return TRUE + + return FALSE + +/datum/tgui_checkbox_input/proc/set_choices(list/selections) + src.choices = selections.Copy() diff --git a/tgui/packages/tgui/interfaces/CheckboxInput.tsx b/tgui/packages/tgui/interfaces/CheckboxInput.tsx new file mode 100644 index 0000000000..64bbecd02f --- /dev/null +++ b/tgui/packages/tgui/interfaces/CheckboxInput.tsx @@ -0,0 +1,110 @@ +import { Button, Icon, Input, NoticeBox, Section, Stack, Table, Tooltip } from '../components'; +import { TableCell, TableRow } from '../components/Table'; +import { createSearch, decodeHtmlEntities } from 'common/string'; +import { useBackend, useLocalState } from '../backend'; + +import { InputButtons } from './common/InputButtons'; +import { Loader } from './common/Loader'; +import { Window } from '../layouts'; + +type Data = { + items: string[]; + message: string; + title: string; + timeout: number; + min_checked: number; + max_checked: number; +}; + +/** Renders a list of checkboxes per items for input. */ +export const CheckboxInput = (props, context) => { + const { data } = useBackend(context); + const { + items = [], + min_checked, + max_checked, + message, + timeout, + title, + } = data; + + const [selections, setSelections] = useLocalState( + context, + 'selections', + [] + ); + + const [searchQuery, setSearchQuery] = useLocalState( + context, + 'searchQuery', + '' + ); + const search = createSearch(searchQuery, (item: string) => item); + const toDisplay = items.filter(search); + + const selectItem = (name: string) => { + const newSelections = selections.includes(name) + ? selections.filter((item) => item !== name) + : [...selections, name]; + + setSelections(newSelections); + }; + + return ( + + {!!timeout && } + + + + + {decodeHtmlEntities(message)}{' '} + {min_checked > 0 && ` (Min: ${min_checked})`} + {max_checked < 50 && ` (Max: ${max_checked})`} + + + +
+ + {toDisplay.map((item, index) => ( + + + = max_checked && + !selections.includes(item) + } + fluid + onClick={() => selectItem(item)}> + {item} + + + + ))} +
+
+
+ + + + + + + + setSearchQuery(value)} + /> + + + +
+ +
+
+
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/common/InputButtons.tsx b/tgui/packages/tgui/interfaces/common/InputButtons.tsx index e9ca2ad26d..5e0d45f776 100644 --- a/tgui/packages/tgui/interfaces/common/InputButtons.tsx +++ b/tgui/packages/tgui/interfaces/common/InputButtons.tsx @@ -1,13 +1,14 @@ -import { useBackend } from '../../backend'; import { Box, Button, Flex } from '../../components'; +import { useBackend } from '../../backend'; + type InputButtonsData = { large_buttons: boolean; swapped_buttons: boolean; }; type InputButtonsProps = { - input: string | number; + input: string | number | string[]; message?: string; }; diff --git a/vorestation.dme b/vorestation.dme index b65fdc5e3f..9384f83ed2 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -4284,6 +4284,7 @@ #include "code\modules\tgui\states\vorepanel_vr.dm" #include "code\modules\tgui\states\zlevel.dm" #include "code\modules\tgui_input\alert.dm" +#include "code\modules\tgui_input\checkboxes.dm" #include "code\modules\tgui_input\list.dm" #include "code\modules\tgui_input\number.dm" #include "code\modules\tgui_input\text.dm"