TGUI Input Checkboxes

This commit is contained in:
Heroman3003
2023-06-02 05:20:01 +10:00
committed by CHOMPStation2
parent f5ab670839
commit 2630ac13dc
4 changed files with 250 additions and 2 deletions

View File

@@ -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()

View File

@@ -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<Data>(context);
const {
items = [],
min_checked,
max_checked,
message,
timeout,
title,
} = data;
const [selections, setSelections] = useLocalState<string[]>(
context,
'selections',
[]
);
const [searchQuery, setSearchQuery] = useLocalState<string>(
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 (
<Window title={title} width={425} height={300}>
{!!timeout && <Loader value={timeout} />}
<Window.Content>
<Stack fill vertical>
<Stack.Item>
<NoticeBox info textAlign="center">
{decodeHtmlEntities(message)}{' '}
{min_checked > 0 && ` (Min: ${min_checked})`}
{max_checked < 50 && ` (Max: ${max_checked})`}
</NoticeBox>
</Stack.Item>
<Stack.Item grow mt={0}>
<Section fill scrollable>
<Table>
{toDisplay.map((item, index) => (
<TableRow className="candystripe" key={index}>
<TableCell>
<Button.Checkbox
checked={selections.includes(item)}
disabled={
selections.length >= max_checked &&
!selections.includes(item)
}
fluid
onClick={() => selectItem(item)}>
{item}
</Button.Checkbox>
</TableCell>
</TableRow>
))}
</Table>
</Section>
</Stack.Item>
<Stack m={1} mb={0}>
<Stack.Item>
<Tooltip content="Search" position="bottom">
<Icon name="search" mt={0.5} />
</Tooltip>
</Stack.Item>
<Stack.Item grow>
<Input
fluid
value={searchQuery}
onInput={(_, value) => setSearchQuery(value)}
/>
</Stack.Item>
</Stack>
<Stack.Item mt={0.7}>
<Section>
<InputButtons input={selections} />
</Section>
</Stack.Item>
</Stack>
</Window.Content>
</Window>
);
};

View File

@@ -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;
};

View File

@@ -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"