diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm
index 326e664b715..9c88473dd22 100644
--- a/code/modules/paperwork/clipboard.dm
+++ b/code/modules/paperwork/clipboard.dm
@@ -1,3 +1,6 @@
+/**
+ * Clipboard
+ */
/obj/item/clipboard
name = "clipboard"
icon = 'icons/obj/bureaucracy.dmi'
@@ -8,119 +11,172 @@
w_class = WEIGHT_CLASS_SMALL
throw_speed = 3
throw_range = 7
- var/obj/item/pen/haspen //The stored pen.
- var/obj/item/paper/toppaper //The topmost piece of paper.
slot_flags = ITEM_SLOT_BELT
resistance_flags = FLAMMABLE
+ /// The stored pen
+ var/obj/item/pen/pen
+ /**
+ * Weakref of the topmost piece of paper
+ *
+ * This is used for the paper displayed on the clipboard's icon
+ * and it is the one attacked, when attacking the clipboard.
+ * (As you can't organise contents directly in BYOND)
+ */
+ var/datum/weakref/toppaper_ref
/obj/item/clipboard/suicide_act(mob/living/carbon/user)
user.visible_message("[user] begins putting [user.p_their()] head into the clip of \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return BRUTELOSS//the clipboard's clip is very strong. industrial duty. can kill a man easily.
+ return BRUTELOSS //The clipboard's clip is very strong. Industrial duty. Can kill a man easily.
/obj/item/clipboard/Initialize()
update_appearance()
. = ..()
/obj/item/clipboard/Destroy()
- QDEL_NULL(haspen)
- QDEL_NULL(toppaper) //let movable/Destroy handle the rest
+ QDEL_NULL(pen)
return ..()
+/obj/item/clipboard/examine()
+ . = ..()
+ if(pen)
+ . += "Alt-click to remove [pen]."
+ var/obj/item/paper/toppaper = toppaper_ref?.resolve()
+ if(toppaper)
+ . += "Right-click to remove [toppaper]."
+
+/// Take out the topmost paper
+/obj/item/clipboard/proc/remove_paper(obj/item/paper/paper, mob/user)
+ if(!istype(paper))
+ return
+ paper.forceMove(user.loc)
+ user.put_in_hands(paper)
+ to_chat(user, "You remove [paper] from [src].")
+ var/obj/item/paper/toppaper = toppaper_ref?.resolve()
+ if(paper == toppaper)
+ toppaper_ref = null
+ var/obj/item/paper/newtop = locate(/obj/item/paper) in src
+ if(newtop && (newtop != paper))
+ toppaper_ref = WEAKREF(newtop)
+ else
+ toppaper_ref = null
+ update_icon()
+
+/obj/item/clipboard/proc/remove_pen(mob/user)
+ pen.forceMove(user.loc)
+ user.put_in_hands(pen)
+ to_chat(user, "You remove [pen] from [src].")
+ pen = null
+ update_icon()
+
+/obj/item/clipboard/AltClick(mob/user)
+ ..()
+ if(pen)
+ remove_pen(user)
+
/obj/item/clipboard/update_overlays()
. = ..()
+ var/obj/item/paper/toppaper = toppaper_ref?.resolve()
if(toppaper)
. += toppaper.icon_state
. += toppaper.overlays
- if(haspen)
+ if(pen)
. += "clipboard_pen"
. += "clipboard_over"
-/obj/item/clipboard/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/paper))
- if(!user.transferItemToLoc(W, src))
+/obj/item/clipboard/attack_hand(mob/user, list/modifiers)
+ if(LAZYACCESS(modifiers, RIGHT_CLICK))
+ var/obj/item/paper/toppaper = toppaper_ref?.resolve()
+ remove_paper(toppaper, user)
+ return TRUE
+ . = ..()
+
+/obj/item/clipboard/attackby(obj/item/weapon, mob/user, params)
+ var/obj/item/paper/toppaper = toppaper_ref?.resolve()
+ if(istype(weapon, /obj/item/paper))
+ //Add paper into the clipboard
+ if(!user.transferItemToLoc(weapon, src))
return
- toppaper = W
- to_chat(user, "You clip the paper onto \the [src].")
- update_appearance()
+ toppaper_ref = WEAKREF(weapon)
+ to_chat(user, "You clip [weapon] onto [src].")
+ else if(istype(weapon, /obj/item/pen) && !pen)
+ //Add a pen into the clipboard, attack (write) if there is already one
+ if(!usr.transferItemToLoc(weapon, src))
+ return
+ pen = weapon
+ to_chat(usr, "You slot [weapon] into [src].")
else if(toppaper)
toppaper.attackby(user.get_active_held_item(), user)
- update_appearance()
-
+ update_appearance()
/obj/item/clipboard/attack_self(mob/user)
- var/dat = "
Clipboard"
- if(haspen)
- dat += "Remove Pen
"
- else
- dat += "Add Pen
"
-
- //The topmost paper. You can't organise contents directly in byond, so this is what we're stuck with. -Pete
- if(toppaper)
- var/obj/item/paper/P = toppaper
- dat += "Write Remove - [P.name]
"
-
- for(P in src)
- if(P == toppaper)
- continue
- dat += "Write Remove Move to top - [P.name]
"
- user << browse(dat, "window=clipboard")
- onclose(user, "clipboard")
add_fingerprint(usr)
+ ui_interact(user)
+ return
+/obj/item/clipboard/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Clipboard")
+ ui.open()
+
+/obj/item/clipboard/ui_data(mob/user)
+ // prepare data for TGUI
+ var/list/data = list()
+ data["pen"] = "[pen]"
+
+ var/obj/item/paper/toppaper = toppaper_ref?.resolve()
+ data["top_paper"] = "[toppaper]"
+ data["top_paper_ref"] = "[REF(toppaper)]"
+
+ data["paper"] = list()
+ data["paper_ref"] = list()
+ for(var/obj/item/paper/paper in src)
+ if(paper == toppaper)
+ continue
+ data["paper"] += "[paper]"
+ data["paper_ref"] += "[REF(paper)]"
+
+ return data
+
+/obj/item/clipboard/ui_act(action, params)
+ . = ..()
+ if(.)
+ return
-/obj/item/clipboard/Topic(href, href_list)
- ..()
if(usr.stat != CONSCIOUS || HAS_TRAIT(usr, TRAIT_HANDS_BLOCKED))
return
- if(usr.contents.Find(src))
-
- if(href_list["pen"])
- if(haspen)
- haspen.forceMove(usr.loc)
- usr.put_in_hands(haspen)
- haspen = null
-
- if(href_list["addpen"])
- if(!haspen)
- var/obj/item/held = usr.get_active_held_item()
- if(istype(held, /obj/item/pen))
- var/obj/item/pen/W = held
- if(!usr.transferItemToLoc(W, src))
- return
- haspen = W
- to_chat(usr, "You slot [W] into [src].")
-
- if(href_list["write"])
- var/obj/item/P = locate(href_list["write"]) in src
- if(istype(P))
- if(usr.get_active_held_item())
- P.attackby(usr.get_active_held_item(), usr)
-
- if(href_list["remove"])
- var/obj/item/P = locate(href_list["remove"]) in src
- if(istype(P))
- P.forceMove(usr.loc)
- usr.put_in_hands(P)
- if(P == toppaper)
- toppaper = null
- var/obj/item/paper/newtop = locate(/obj/item/paper) in src
- if(newtop && (newtop != P))
- toppaper = newtop
- else
- toppaper = null
-
- if(href_list["read"])
- var/obj/item/paper/P = locate(href_list["read"]) in src
- if(istype(P))
- usr.examinate(P)
-
- if(href_list["top"])
- var/obj/item/P = locate(href_list["top"]) in src
- if(istype(P))
- toppaper = P
- to_chat(usr, "You move [P.name] to the top.")
-
- //Update everything
- attack_self(usr)
- update_appearance()
+ switch(action)
+ // Take the pen out
+ if("remove_pen")
+ if(pen)
+ remove_pen(usr)
+ . = TRUE
+ // Take paper out
+ if("remove_paper")
+ var/obj/item/paper/paper = locate(params["ref"]) in src
+ if(istype(paper))
+ remove_paper(paper, usr)
+ . = TRUE
+ // Look at (or edit) the paper
+ if("edit_paper")
+ var/obj/item/paper/paper = locate(params["ref"]) in src
+ if(istype(paper))
+ paper.ui_interact(usr)
+ update_icon()
+ . = TRUE
+ // Move paper to the top
+ if("move_top_paper")
+ var/obj/item/paper/paper = locate(params["ref"]) in src
+ if(istype(paper))
+ toppaper_ref = WEAKREF(paper)
+ to_chat(usr, "You move [paper] to the top.")
+ update_icon()
+ . = TRUE
+ // Rename the paper (it's a verb)
+ if("rename_paper")
+ var/obj/item/paper/paper = locate(params["ref"]) in src
+ if(istype(paper))
+ paper.rename()
+ update_icon()
+ . = TRUE
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index dc44faefb40..0675632a750 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -124,7 +124,7 @@
H.update_damage_hud()
return
var/n_name = stripped_input(usr, "What would you like to label the paper?", "Paper Labelling", null, MAX_NAME_LEN)
- if((loc == usr && usr.stat == CONSCIOUS))
+ if(((loc == usr || istype(loc, /obj/item/clipboard)) && usr.stat == CONSCIOUS))
name = "paper[(n_name ? text("- '[n_name]'") : null)]"
add_fingerprint(usr)
@@ -161,7 +161,7 @@
// .. or if you cannot read
if(!user.can_read(src))
return UI_CLOSE
- if(in_contents_of(/obj/machinery/door/airlock))
+ if(in_contents_of(/obj/machinery/door/airlock) || in_contents_of(/obj/item/clipboard))
return UI_INTERACTIVE
return ..()
@@ -251,27 +251,32 @@
var/list/data = list()
data["edit_usr"] = "[user]"
- var/obj/O = user.get_active_held_item()
- if(istype(O, /obj/item/toy/crayon))
- var/obj/item/toy/crayon/PEN = O
+ var/obj/holding = user.get_active_held_item()
+ // Use a clipboard's pen, if applicable
+ if(istype(loc, /obj/item/clipboard))
+ var/obj/item/clipboard/clipboard = loc
+ if(clipboard.pen)
+ holding = clipboard.pen
+ if(istype(holding, /obj/item/toy/crayon))
+ var/obj/item/toy/crayon/PEN = holding
data["pen_font"] = CRAYON_FONT
data["pen_color"] = PEN.paint_color
data["edit_mode"] = MODE_WRITING
data["is_crayon"] = TRUE
data["stamp_class"] = "FAKE"
data["stamp_icon_state"] = "FAKE"
- else if(istype(O, /obj/item/pen))
- var/obj/item/pen/PEN = O
+ else if(istype(holding, /obj/item/pen))
+ var/obj/item/pen/PEN = holding
data["pen_font"] = PEN.font
data["pen_color"] = PEN.colour
data["edit_mode"] = MODE_WRITING
data["is_crayon"] = FALSE
data["stamp_class"] = "FAKE"
data["stamp_icon_state"] = "FAKE"
- else if(istype(O, /obj/item/stamp))
+ else if(istype(holding, /obj/item/stamp))
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/simple/paper)
- data["stamp_icon_state"] = O.icon_state
- data["stamp_class"] = sheet.icon_class_name(O.icon_state)
+ data["stamp_icon_state"] = holding.icon_state
+ data["stamp_class"] = sheet.icon_class_name(holding.icon_state)
data["edit_mode"] = MODE_STAMPING
data["pen_font"] = "FAKE"
data["pen_color"] = "FAKE"
diff --git a/tgui/packages/tgui/interfaces/Clipboard.js b/tgui/packages/tgui/interfaces/Clipboard.js
new file mode 100644
index 00000000000..69f56a26c9c
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Clipboard.js
@@ -0,0 +1,107 @@
+import { useBackend } from "../backend";
+import {
+ Box,
+ Button,
+ Divider,
+ LabeledList,
+ Flex,
+ Section,
+} from "../components";
+import { Window } from "../layouts";
+
+export const Clipboard = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { pen, top_paper, top_paper_ref, paper, paper_ref } = data;
+ return (
+
+
+
+ {pen ? (
+
+ act("remove_pen")} />
+ }
+ >
+ {pen}
+
+
+ ) : (
+
+ No pen attached!
+
+ )}
+
+
+ {top_paper ? (
+
+
+ {top_paper}
+
+
+
+
+ ) : (
+
+
+ The clipboard is empty!
+
+
+ )}
+ {paper.length > 0 && }
+ {paper.map((paper_item, index) => (
+
+
+ act("move_top_paper", { ref: paper_ref[index] })}
+ />
+
+
+ {paper_item}
+
+
+ act("edit_paper", { ref: paper_ref[index] })}
+ />
+ act("rename_paper", { ref: paper_ref[index] })}
+ />
+ act("remove_paper", { ref: paper_ref[index] })}
+ />
+
+
+ ))}
+
+
+ );
+};