Smarter pipes (#58296)

Smart pipe improvements
Co-authored-by: tralezab <spamqetuo2@gmail.com>
This commit is contained in:
Ghilker
2021-04-26 23:35:08 +02:00
committed by GitHub
parent a8ef83f093
commit 88a9e09fd6
11 changed files with 374 additions and 162 deletions
+9 -5
View File
@@ -577,16 +577,20 @@ GLOBAL_LIST_EMPTY(colored_images)
CHECK_TICK
/datum/controller/subsystem/air/proc/get_init_dirs(type, dir)
/datum/controller/subsystem/air/proc/get_init_dirs(type, dir, init_dir)
if(!pipe_init_dirs_cache[type])
pipe_init_dirs_cache[type] = list()
if(!pipe_init_dirs_cache[type]["[dir]"])
var/obj/machinery/atmospherics/temp = new type(null, FALSE, dir)
pipe_init_dirs_cache[type]["[dir]"] = temp.GetInitDirections()
if(!pipe_init_dirs_cache[type]["[init_dir]"])
pipe_init_dirs_cache[type]["[init_dir]"] = list()
if(!pipe_init_dirs_cache[type]["[init_dir]"]["[dir]"])
var/obj/machinery/atmospherics/temp = new type(null, FALSE, dir, init_dir)
pipe_init_dirs_cache[type]["[init_dir]"]["[dir]"] = temp.GetInitDirections()
qdel(temp)
return pipe_init_dirs_cache[type]["[dir]"]
return pipe_init_dirs_cache[type]["[init_dir]"]["[dir]"]
/datum/controller/subsystem/air/proc/generate_atmos()
atmos_gen = list()
+12 -5
View File
@@ -18,11 +18,16 @@ Buildable meters
icon_state = "simple"
inhand_icon_state = "buildpipe"
w_class = WEIGHT_CLASS_NORMAL
///Piping layer that we are going to be on
var/piping_layer = PIPING_LAYER_DEFAULT
///Type of pipe-object made, selected from the RPD
var/RPD_type
/// Whether it can be painted
///Whether it can be painted
var/paintable = FALSE
///Color of the pipe is going to be made from this pipe-object
var/pipe_color
///Initial direction of the created pipe (either made from the RPD or after unwrenching the pipe)
var/p_init_dir = SOUTH
/obj/item/pipe/directional
RPD_type = PIPE_UNARY
@@ -42,10 +47,11 @@ Buildable meters
//Flipping handled manually due to custom handling for trinary pipes
AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE)
/obj/item/pipe/Initialize(mapload, _pipe_type, _dir, obj/machinery/atmospherics/make_from, device_color)
/obj/item/pipe/Initialize(mapload, _pipe_type, _dir, obj/machinery/atmospherics/make_from, device_color, device_init_dir = SOUTH)
if(make_from)
make_from_existing(make_from)
else
p_init_dir = device_init_dir
pipe_type = _pipe_type
pipe_color = device_color
setDir(_dir)
@@ -56,6 +62,7 @@ Buildable meters
return ..()
/obj/item/pipe/proc/make_from_existing(obj/machinery/atmospherics/make_from)
p_init_dir = make_from.initialize_directions
setDir(make_from.dir)
pipename = make_from.name
add_atom_colour(make_from.color, FIXED_COLOUR_PRIORITY)
@@ -176,12 +183,12 @@ Buildable meters
if((machine.piping_layer != piping_layer) && !((machine.pipe_flags | flags) & PIPING_ALL_LAYER)) //don't continue if either pipe goes across all layers
continue
if(machine.GetInitDirections() & SSair.get_init_dirs(pipe_type, fixed_dir())) // matches at least one direction on either type of pipe
if(machine.GetInitDirections() & SSair.get_init_dirs(pipe_type, fixed_dir(), p_init_dir)) // matches at least one direction on either type of pipe
to_chat(user, "<span class='warning'>There is already a pipe at that location!</span>")
return TRUE
// no conflicts found
var/obj/machinery/atmospherics/built_machine = new pipe_type(loc)
var/obj/machinery/atmospherics/built_machine = new pipe_type(loc, , , p_init_dir)
build_pipe(built_machine)
built_machine.on_construction(pipe_color, piping_layer)
transfer_fingerprints_to(built_machine)
@@ -196,7 +203,7 @@ Buildable meters
/obj/item/pipe/proc/build_pipe(obj/machinery/atmospherics/A)
A.setDir(fixed_dir())
A.SetInitDirections()
A.SetInitDirections(p_init_dir)
if(pipename)
A.name = pipename
+46 -15
View File
@@ -196,23 +196,39 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
custom_materials = list(/datum/material/iron=75000, /datum/material/glass=37500)
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50)
resistance_flags = FIRE_PROOF
///Sparks system used when changing device in the UI
var/datum/effect_system/spark_spread/spark_system
var/working = 0
///Direction of the device we are going to spawn, set up in the UI
var/p_dir = NORTH
///Initial direction of the smart pipe we are going to spawn, set up in the UI
var/p_init_dir = ALL_CARDINALS
///Is the device of the flipped type?
var/p_flipped = FALSE
///Color of the device we are going to spawn
var/paint_color = "grey"
var/atmos_build_speed = 5 //deciseconds (500ms)
var/disposal_build_speed = 5
var/transit_build_speed = 5
var/destroy_speed = 5
var/paint_speed = 5
///Speed of building atmos devices
var/atmos_build_speed = 0.5 SECONDS
///Speed of building disposal devices
var/disposal_build_speed = 0.5 SECONDS
///Speed of building transit devices
var/transit_build_speed = 0.5 SECONDS
///Speed of removal of unwrenched devices
var/destroy_speed = 0.5 SECONDS
///Category currently active (Atmos, disposal, transit)
var/category = ATMOS_CATEGORY
///Piping layer we are going to spawn the atmos device in
var/piping_layer = PIPING_LAYER_DEFAULT
///Layer for disposal ducts
var/ducting_layer = DUCT_LAYER_DEFAULT
///Stores the current device to spawn
var/datum/pipe_info/recipe
///Stores the first atmos device
var/static/datum/pipe_info/first_atmos
///Stores the first disposal device
var/static/datum/pipe_info/first_disposal
///Stores the first transit device
var/static/datum/pipe_info/first_transit
///The modes that are allowed for the RPD
var/mode = BUILD_MODE | DESTROY_MODE | WRENCH_MODE
/// Bitflags for upgrades
var/upgrade_flags
@@ -344,6 +360,11 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
r += list(list("pipe_name" = info.name, "pipe_index" = i, "selected" = (info == recipe), "all_layers" = info.all_layers))
data["categories"] += list(list("cat_name" = c, "recipes" = r))
var/list/init_directions = list("north" = FALSE, "south" = FALSE, "east" = FALSE, "west" = FALSE)
for(var/direction in GLOB.cardinals)
if(p_init_dir & direction)
init_directions[dir2text(direction)] = TRUE
data["init_directions"] = init_directions
return data
/obj/item/pipe_dispenser/ui_act(action, params)
@@ -390,6 +411,10 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
mode &= ~n
else
mode |= n
if("init_dir_setting")
p_init_dir ^= text2dir(params["dir_flag"])
if("init_reset")
p_init_dir = ALL_CARDINALS
if(playeffect)
spark_system.start()
playsound(get_turf(src), 'sound/effects/pop.ogg', 50, FALSE)
@@ -456,19 +481,25 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
activate()
var/obj/machinery/atmospherics/path = queued_p_type
var/pipe_item_type = initial(path.construction_type) || /obj/item/pipe
var/obj/item/pipe/P = new pipe_item_type(get_turf(attack_target), queued_p_type, queued_p_dir, null, GLOB.pipe_paint_colors[paint_color])
if(queued_p_flipped && istype(P, /obj/item/pipe/trinary/flippable))
var/obj/item/pipe/trinary/flippable/F = P
var/obj/item/pipe/pipe_type = new pipe_item_type(
get_turf(attack_target),
queued_p_type,
queued_p_dir,
null,
GLOB.pipe_paint_colors[paint_color],
ispath(queued_p_type, /obj/machinery/atmospherics/pipe/smart) ? p_init_dir : null,
)
if(queued_p_flipped && istype(pipe_type, /obj/item/pipe/trinary/flippable))
var/obj/item/pipe/trinary/flippable/F = pipe_type
F.flipped = queued_p_flipped
P.update()
P.add_fingerprint(usr)
P.setPipingLayer(piping_layer)
pipe_type.update()
pipe_type.add_fingerprint(usr)
pipe_type.setPipingLayer(piping_layer)
if(ispath(queued_p_type, /obj/machinery/atmospherics) && !ispath(queued_p_type, /obj/machinery/atmospherics/pipe/color_adapter))
P.add_atom_colour(GLOB.pipe_paint_colors[paint_color], FIXED_COLOUR_PRIORITY)
pipe_type.add_atom_colour(GLOB.pipe_paint_colors[paint_color], FIXED_COLOUR_PRIORITY)
if(mode & WRENCH_MODE)
P.wrench_act(user, src)
pipe_type.wrench_act(user, src)
if(DISPOSALS_CATEGORY) //Making disposals pipes
if(!can_make_pipe)
@@ -77,7 +77,7 @@
if(HAS_TRAIT(L, TRAIT_VENTCRAWLER_NUDE) || HAS_TRAIT(L, TRAIT_VENTCRAWLER_ALWAYS))
. += "<span class='notice'>Alt-click to crawl through it.</span>"
/obj/machinery/atmospherics/New(loc, process = TRUE, setdir)
/obj/machinery/atmospherics/New(loc, process = TRUE, setdir, init_dir = ALL_CARDINALS)
if(!isnull(setdir))
setDir(setdir)
if(pipe_flags & PIPING_CARDINAL_AUTONORMALIZE)
@@ -88,7 +88,7 @@
..()
if(process)
SSair.start_processing_machine(src)
SetInitDirections()
SetInitDirections(init_dir)
/obj/machinery/atmospherics/Destroy()
for(var/i in 1 to device_type)
@@ -223,7 +223,18 @@
* * given_layer - the piping_layer we are checking
*/
/obj/machinery/atmospherics/proc/connection_check(obj/machinery/atmospherics/target, given_layer)
if(isConnectable(target, given_layer) && target.isConnectable(src, given_layer) && (target.initialize_directions & get_dir(target,src) || istype(target, /obj/machinery/atmospherics/pipe/multiz)))
if(isConnectable(target, given_layer) && target.isConnectable(src, given_layer) && check_init_directions(target))
return TRUE
return FALSE
/**
* check if the initialized direction are the same on both sides (or if is a multiz adapter)
* returns TRUE or FALSE if the connection is possible or not
* Arguments:
* * obj/machinery/atmospherics/target - the machinery we want to connect to
*/
/obj/machinery/atmospherics/proc/check_init_directions(obj/machinery/atmospherics/target)
if((initialize_directions & get_dir(src, target) && target.initialize_directions & get_dir(target,src)) || istype(target, /obj/machinery/atmospherics/pipe/multiz))
return TRUE
return FALSE
@@ -274,7 +285,7 @@
/**
* Set the initial directions of the device (NORTH || SOUTH || EAST || WEST), called on New()
*/
/obj/machinery/atmospherics/proc/SetInitDirections()
/obj/machinery/atmospherics/proc/SetInitDirections(init_dir)
return
/**
@@ -1,5 +1,5 @@
GLOBAL_LIST_INIT(atmos_components, typecacheof(list(/obj/machinery/atmospherics)))
//Smart pipes... or are they?
/obj/machinery/atmospherics/pipe/smart
icon = 'icons/obj/atmospherics/pipes/simple.dmi'
icon_state = "pipe11-3"
@@ -24,8 +24,11 @@ GLOBAL_LIST_INIT(atmos_components, typecacheof(list(/obj/machinery/atmospherics)
icon_state = ""
. = ..()
/obj/machinery/atmospherics/pipe/smart/SetInitDirections()
initialize_directions = ALL_CARDINALS
/obj/machinery/atmospherics/pipe/smart/SetInitDirections(init_dir)
if(init_dir)
initialize_directions = init_dir
else
initialize_directions = ALL_CARDINALS
/obj/machinery/atmospherics/pipe/smart/proc/check_connections()
var/mutable_appearance/center
@@ -5,6 +5,7 @@
#define MODE_TRAY "t-ray"
#define MODE_RAD "radiation"
#define MODE_SHUTTLE "shuttle"
#define MODE_PIPE_CONNECTABLE "connectable"
/obj/item/clothing/glasses/meson/engine
name = "engineering scanner goggles"
@@ -21,6 +22,7 @@
var/list/modes = list(MODE_NONE = MODE_MESON, MODE_MESON = MODE_TRAY, MODE_TRAY = MODE_RAD, MODE_RAD = MODE_NONE)
var/mode = MODE_NONE
var/range = 1
var/list/connection_images = list()
/obj/item/clothing/glasses/meson/engine/Initialize()
. = ..()
@@ -38,7 +40,8 @@
/obj/item/clothing/glasses/meson/engine/proc/toggle_mode(mob/user, voluntary)
mode = modes[mode]
to_chat(user, "<span class='[voluntary ? "notice":"warning"]'>[voluntary ? "You turn the goggles":"The goggles turn"] [mode ? "to [mode] mode":"off"][voluntary ? ".":"!"]</span>")
if(connection_images.len)
connection_images.Cut()
switch(mode)
if(MODE_MESON)
vision_flags = SEE_TURFS
@@ -52,6 +55,9 @@
lighting_alpha = null
change_glass_color(user, /datum/client_colour/glass_colour/lightblue)
if(MODE_PIPE_CONNECTABLE)
change_glass_color(user, /datum/client_colour/glass_colour/lightblue)
if(MODE_RAD)
change_glass_color(user, /datum/client_colour/glass_colour/lightgreen)
@@ -87,6 +93,8 @@
show_rads()
if(MODE_SHUTTLE)
show_shuttle()
if(MODE_PIPE_CONNECTABLE)
show_connections()
/obj/item/clothing/glasses/meson/engine/proc/show_rads()
var/mob/living/carbon/human/user = loc
@@ -130,6 +138,30 @@
pic = new('icons/turf/overlays.dmi', place, "redOverlay", AREA_LAYER)
flick_overlay(pic, list(user.client), 8)
/obj/item/clothing/glasses/meson/engine/proc/show_connections()
var/mob/living/carbon/human/user = loc
for(var/obj/machinery/atmospherics/pipe/smart/smart in connection_images)
if(get_dist(loc, smart.loc) > range)
connection_images -= smart
for(var/obj/machinery/atmospherics/pipe/smart/smart in orange(range, user))
if(!connection_images[smart])
connection_images[smart] = list()
for(var/direction in GLOB.cardinals)
if(!(smart.GetInitDirections() & direction))
continue
if(!connection_images[smart][dir2text(direction)])
var/image/arrow
arrow = new('icons/obj/atmospherics/pipes/simple.dmi', get_turf(smart), "connection_overlay")
arrow.dir = direction
arrow.layer = smart.layer
arrow.color = smart.pipe_color
PIPING_LAYER_DOUBLE_SHIFT(arrow, smart.piping_layer)
connection_images[smart][dir2text(direction)] = arrow
if(connection_images.len)
flick_overlay(connection_images[smart][dir2text(direction)], list(user.client), 1.5 SECONDS)
/obj/item/clothing/glasses/meson/engine/update_icon_state()
icon_state = inhand_icon_state = "trayson-[mode]"
return ..()
@@ -141,7 +173,12 @@
desc = "Used by engineering staff to see underfloor objects such as cables and pipes."
range = 2
modes = list(MODE_NONE = MODE_TRAY, MODE_TRAY = MODE_NONE)
modes = list(MODE_NONE = MODE_TRAY, MODE_TRAY = MODE_PIPE_CONNECTABLE, MODE_PIPE_CONNECTABLE = MODE_NONE)
/obj/item/clothing/glasses/meson/engine/tray/dropped(mob/user)
. = ..()
if(connection_images.len)
connection_images.Cut()
/obj/item/clothing/glasses/meson/engine/shuttle
name = "shuttle region scanner"
@@ -156,3 +193,4 @@
#undef MODE_TRAY
#undef MODE_RAD
#undef MODE_SHUTTLE
#undef MODE_PIPE_CONNECTABLE
Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

@@ -1,6 +1,7 @@
import { classes } from 'common/react';
import { multiline } from 'common/string';
import { useBackend, useLocalState } from '../backend';
import { Box, Button, ColorBox, Flex, LabeledList, Section, Tabs } from '../components';
import { Box, Button, ColorBox, Dimmer, LabeledList, Section, Stack, Tabs } from '../components';
import { Window } from '../layouts';
const ROOT_CATEGORIES = [
@@ -35,16 +36,127 @@ const TOOLS = [
},
];
export const RapidPipeDispenser = (props, context) => {
const SelectionSection = (props, context) => {
const { act, data } = useBackend(context);
const {
category: rootCategoryIndex,
categories = [],
selected_color,
piping_layer,
mode,
} = data;
return (
<Section>
<LabeledList>
<LabeledList.Item
label="Category">
{ROOT_CATEGORIES.map((categoryName, i) => (
<Button
key={categoryName}
selected={rootCategoryIndex === i}
icon={ICON_BY_CATEGORY_NAME[categoryName]}
color="transparent"
onClick={() => act('category', { category: i })} >
{categoryName}
</Button>
))}
</LabeledList.Item>
<LabeledList.Item label="Modes">
<Stack fill>
{TOOLS.map(tool => (
<Stack.Item grow key={tool.bitmask}>
<Button.Checkbox
checked={mode & tool.bitmask}
fluid
content={tool.name}
onClick={() => act('mode', {
mode: tool.bitmask,
})} />
</Stack.Item>
))}
</Stack>
</LabeledList.Item>
<LabeledList.Item
label="Color">
<Box
inline
width="64px"
color={data.paint_colors[selected_color]}>
{selected_color}
</Box>
{Object.keys(data.paint_colors)
.map(colorName => (
<ColorBox
key={colorName}
ml={1}
color={data.paint_colors[colorName]}
onClick={() => act('color', {
paint_color: colorName,
})} />
))}
</LabeledList.Item>
</LabeledList>
</Section>
);
};
const LayerSection = (props, context) => {
const { act, data } = useBackend(context);
const {
category: rootCategoryIndex,
piping_layer,
} = data;
const previews = data.preview_rows.flatMap(row => row.previews);
return (
<Section fill width={7.5}>
{rootCategoryIndex === 0 && (
<Stack vertical mb={1}>
{[1, 2, 3, 4, 5].map(layer => (
<Stack.Item my={0} key={layer}>
<Button.Checkbox
checked={layer === piping_layer}
content={'Layer ' + layer}
onClick={() => act('piping_layer', {
piping_layer: layer,
})} />
</Stack.Item>
))}
</Stack>
)}
<Box width="120px">
{previews.map(preview => (
<Button
ml={0}
key={preview.dir}
title={preview.dir_name}
selected={preview.selected}
style={{
width: '40px',
height: '40px',
padding: 0,
}}
onClick={() => act('setdir', {
dir: preview.dir,
flipped: preview.flipped,
})}>
<Box
className={classes([
'pipes32x32',
preview.dir + '-' + preview.icon_state,
])}
style={{
transform: 'scale(1.5) translate(9.5%, 9.5%)',
}} />
</Button>
))}
</Box>
</Section>
);
};
const PipeTypeSection = (props, context) => {
const { act, data } = useBackend(context);
const {
categories = [],
} = data;
const [
categoryName,
setCategoryName,
@@ -52,132 +164,138 @@ export const RapidPipeDispenser = (props, context) => {
const shownCategory = categories
.find(category => category.cat_name === categoryName)
|| categories[0];
return (
<Section fill scrollable>
<Tabs>
{categories.map((category, i) => (
<Tabs.Tab
fluid
key={category.cat_name}
icon={ICON_BY_CATEGORY_NAME[category.cat_name]}
selected={category.cat_name === shownCategory.cat_name}
onClick={() => setCategoryName(category.cat_name)}>
{category.cat_name}
</Tabs.Tab>
))}
</Tabs>
{shownCategory?.recipes.map(recipe => (
<Button.Checkbox
key={recipe.pipe_index}
fluid
ellipsis
checked={recipe.selected}
content={recipe.pipe_name}
title={recipe.pipe_name}
onClick={() => act('pipe_type', {
pipe_type: recipe.pipe_index,
category: shownCategory.cat_name,
})} />
))}
</Section>
);
};
const SmartPipeBlockSection = (props, context) => {
const { act, data } = useBackend(context);
const init_directions = data.init_directions || [];
const {
category: rootCategoryIndex,
} = data;
return (
<Section>
<Stack fill vertical textAlign="center">
<Stack.Item basis={1.5}>
<Stack>
<Stack.Item>
<Button
color="transparent"
icon="info"
tooltipPosition="right"
tooltip={multiline`
This is a panel for blocking certain connection
directions for the smart pipes.
The button in the center resets to
default (all directions can connect)`} />
</Stack.Item>
<Stack.Item>
<Button iconRotation={-90} icon="arrow-right"
disabled={!!data.smart_pipe}
selected={init_directions["north"]}
onClick={() => act('init_dir_setting', {
dir_flag: "north",
})} />
</Stack.Item>
</Stack>
</Stack.Item>
<Stack.Item basis={1.5}>
<Stack fill>
<Stack.Item>
<Button icon="arrow-left"
selected={init_directions["west"]}
onClick={() => act('init_dir_setting', {
dir_flag: "west",
})} />
</Stack.Item>
<Stack.Item grow>
<Button icon="circle"
onClick={() => act('init_reset', {
})} />
</Stack.Item>
<Stack.Item>
<Button icon="arrow-right"
selected={init_directions["east"]}
onClick={() => act('init_dir_setting', {
dir_flag: "east",
})} />
</Stack.Item>
</Stack>
</Stack.Item>
<Stack.Item grow>
<Button iconRotation={90} icon="arrow-right"
selected={init_directions["south"]}
onClick={() => act('init_dir_setting', {
dir_flag: "south",
})} />
</Stack.Item>
</Stack>
</Section>
);
};
export const RapidPipeDispenser = (props, context) => {
const { act, data } = useBackend(context);
const {
category: rootCategoryIndex,
} = data;
return (
<Window
width={425}
height={515}>
<Window.Content scrollable>
<Section>
<LabeledList>
<LabeledList.Item
label="Category">
{ROOT_CATEGORIES.map((categoryName, i) => (
<Button
key={categoryName}
selected={rootCategoryIndex === i}
icon={ICON_BY_CATEGORY_NAME[categoryName]}
color="transparent"
content={categoryName}
onClick={() => act('category', { category: i })} />
))}
</LabeledList.Item>
<LabeledList.Item label="Modes">
{TOOLS.map(tool => (
<Button.Checkbox
key={tool.bitmask}
checked={mode & tool.bitmask}
content={tool.name}
onClick={() => act('mode', {
mode: tool.bitmask,
})} />
))}
</LabeledList.Item>
<LabeledList.Item
label="Color">
<Box
inline
width="64px"
color={data.paint_colors[selected_color]}>
{selected_color}
</Box>
{Object.keys(data.paint_colors)
.map(colorName => (
<ColorBox
key={colorName}
ml={1}
color={data.paint_colors[colorName]}
onClick={() => act('color', {
paint_color: colorName,
})} />
))}
</LabeledList.Item>
</LabeledList>
</Section>
<Flex m={-0.5}>
<Flex.Item m={0.5}>
<Section>
{rootCategoryIndex === 0 && (
<Box mb={1}>
{[1, 2, 3, 4, 5].map(layer => (
<Button.Checkbox
key={layer}
fluid
checked={layer === piping_layer}
content={'Layer ' + layer}
onClick={() => act('piping_layer', {
piping_layer: layer,
})} />
))}
</Box>
)}
<Box width="108px">
{previews.map(preview => (
<Button
key={preview.dir}
title={preview.dir_name}
selected={preview.selected}
style={{
width: '48px',
height: '48px',
padding: 0,
}}
onClick={() => act('setdir', {
dir: preview.dir,
flipped: preview.flipped,
})}>
<Box
className={classes([
'pipes32x32',
preview.dir + '-' + preview.icon_state,
])}
style={{
transform: 'scale(1.5) translate(17%, 17%)',
}} />
</Button>
))}
</Box>
</Section>
</Flex.Item>
<Flex.Item m={0.5} grow={1}>
<Section>
<Tabs>
{categories.map((category, i) => (
<Tabs.Tab
fluid
key={category.cat_name}
icon={ICON_BY_CATEGORY_NAME[category.cat_name]}
selected={category.cat_name === shownCategory.cat_name}
onClick={() => setCategoryName(category.cat_name)}>
{category.cat_name}
</Tabs.Tab>
))}
</Tabs>
{shownCategory?.recipes.map(recipe => (
<Button.Checkbox
key={recipe.pipe_index}
fluid
ellipsis
checked={recipe.selected}
content={recipe.pipe_name}
title={recipe.pipe_name}
onClick={() => act('pipe_type', {
pipe_type: recipe.pipe_index,
category: shownCategory.cat_name,
})} />
))}
</Section>
</Flex.Item>
</Flex>
width={450}
height={575}>
<Window.Content>
<Stack fill vertical>
<Stack.Item>
<SelectionSection />
</Stack.Item>
<Stack.Item grow>
<Stack fill>
<Stack.Item>
<Stack vertical fill>
{rootCategoryIndex === 0 && (
<Stack.Item>
<SmartPipeBlockSection />
</Stack.Item>
)}
<Stack.Item grow>
<LayerSection />
</Stack.Item>
</Stack>
</Stack.Item>
<Stack.Item grow>
<PipeTypeSection />
</Stack.Item>
</Stack>
</Stack.Item>
</Stack>
</Window.Content>
</Window>
);