LF it all!! - And actual tgui3

This commit is contained in:
Letter N
2020-07-21 17:45:03 +08:00
parent 775d84370f
commit 9fa060de9e
10 changed files with 1243 additions and 1263 deletions
+4 -4
View File
@@ -275,11 +275,11 @@ interface.
Example (button):
```
```jsx
<ByondUi
params={{
id: 'test_button', // optional, can be auto-generated
parent: config.window,
parent: 'some_container', // optional, defaults to the current window
type: 'button',
text: 'Hello, world!',
}} />
@@ -287,11 +287,10 @@ Example (button):
Example (map):
```
```jsx
<ByondUi
params={{
id: 'test_map',
parent: config.window,
type: 'map',
}} />
```
@@ -982,6 +981,7 @@ Example:
- `className: string` - Applies a CSS class to the element.
- `theme: string` - A name of the theme.
- For a list of themes, see `packages/tgui/styles/themes`.
- `title: string` - Window title.
- `resizable: boolean` - Controls resizability of the window.
- `children: any` - Child elements, which are rendered directly inside the
window. If you use a [Dimmer](#dimmer) or [Modal](#modal) in your UI,
+10 -7
View File
@@ -73,6 +73,7 @@ This might look a bit intimidating compared to the reactive part but it's not as
You don't really need to know all this to understand how to use it, but I find it helps with understanding when things go wrong.
Ractive conditionals can have an `else` as well
```ractive
{{#if data.condition}}
value
@@ -116,7 +117,7 @@ and you can mix string literals, values, and tags as well.
Ractive has loops for iterating over data and inserting something for each
member of an array or object
```
```ractive
{{#each data.list_of_foo}}
foo {{number}} is here.
{{/each}}
@@ -135,6 +136,7 @@ Objects are represented by `{}`, arrays by `[]`
`list("bla", "blo")` would become `["bla", "blo"]` and `list("foo" = 1, "bar" = 2)` would become `{"foo": 1, "bar": 2}`
First things first, above the `return` of the function you're making the interface in, you're going to want to add something like this
```jsx
const things = data.things || [];
```
@@ -142,6 +144,7 @@ const things = data.things || [];
This ensures that you'll never be reading a null entry by mistake. Substitute `{}` for objects as appropriate.
If it's an array, you'll want to do this in the template
```jsx
{things.map(thing => (
<Fragment>
@@ -187,7 +190,7 @@ const fooArray = toArray(fooObject);
Also occasionally you'd see an else:
```
```ractive
{{#each data.potentially_empty_list}}
Thing "{{name}}" is in this list!
{{else}}
@@ -220,7 +223,7 @@ This will be a reference of tgui components and the tgui-next equivalent.
Equivalent of `<ui-display>` is `<Section>`
```
```ractive
<ui-display title="Status">
Contents
</ui-display>
@@ -236,7 +239,7 @@ becomes
A feature sometimes used is if `ui-display` has the `button` property, it will contain a `partial` command. This becomes the `buttons` property on `Section`:
```
```ractive
<ui-display title="Status" button>
{{#partial button}}
<ui-button /> // lots more button bullshit here
@@ -263,7 +266,7 @@ Very important to note `ui-section` is NOT the equivalent of `Section`
`<ui-section>` does not have a direct equivalent, but the closest equivalent is `<LabeledList>`
```
```ractive
<ui-section label="power">
No Power
</ui-section>
@@ -293,7 +296,7 @@ Also good to know that if you need the contents of a `LabeledList.Item` to be co
`<ui-notice>` has a direct equivalent in `<NoticeBox>`
```
```ractive
<ui-notice>
Notice stuff!
</ui-notice>
@@ -311,7 +314,7 @@ becomes
The equivalent of `ui-button` is `Button` but it works quite a bit differently.
```
```ractive
<ui-button
state='{{data.condition ? "disabled" : null}}'
action="ui_action"
+91
View File
@@ -0,0 +1,91 @@
# tgui Migration Guide to v4 from v3
## The Easy Part
- Copy and replace the following files in bulk:
- `code/__DEFINES/tgui.dm`
- `code/controllers/subsystem/tgui.dm`
- `code/modules/tgui/**`
- `tgui/**`
- Except: `tgui/packages/tgui/interfaces`
- Manually resolve conflicts for files that were touched outside the
`interfaces` folder.
- Copy the updated `log_tgui` proc from:
- `code/__HELPERS/_logging.dm`
If you have a dual nano/tgui setup, then make sure to rename all ui procs
on `/datum`, such as `ui_interact` to `tgui_interact`, to avoid namespace
clashing. Usual stuff.
## Update `ui_interact` proc signatures
First of all, tgui states need to move from `ui_interact` to `ui_state`.
One way of doing it, is to just cherry pick those procs from upstream.
If you want to search and replace manually, search for `state = GLOB`, and
extract those things into `ui_state` procs like so:
```dm
.../ui_state(mob/user)
return GLOB.default_state
```
Then reduce `ui_interact` until you finish with something like this:
```dm
.../ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "FooBar", "Foo Bar UI", 600, 400)
ui.open()
```
## Update asset delivery code
Remove all asset code that injects stylesheets by modifying tgui's `basehtml`.
You no longer need to do that.
Find all occurences of `asset.send(user)` in `ui_interact`, and refactor those
snippets to the following proc:
```dm
.../ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/simple/foobar),
)
```
## Check `ui_act` for new bugs
Code behind `ui_act` was recently refactored to use JSON-encoded payloads
instead of just strings. Since it can now carry numbers and other complex
types, you should check that the code is type agnostic and does not break
due to an assumption that every parameter is a string.
One of such offenders is the personal crafting interface, where it needlessly
compares parameters to `""` and `"0"`. You can now replace this code with
simple assignments, because an empty category will now be properly `null`
instead of an empty string.
## Backend data changes
Interfaces that relied on `config.window.id`, must now use
`window.__windowId__`, which is a global constant unique for the page
the script is running on (so you can be sure it never changes).
In case of `ByondUi`, this parameter can be completely omitted, because
parent will always default to the current window id.
Affected interfaces:
- `CameraConsole`
- Any interface that uses the `ByondUi` component
---
That's all folks!
There is a lot of stuff that was refactored under the hood, but normal UI
stuff wouldn't and shouldn't touch it, so you should be good with just
going through the checklist above.
+13 -15
View File
@@ -4,11 +4,11 @@
Basic tgui backend code consists of the following vars and procs:
```
ui_interact(mob/user, ui_key, datum/tgui/ui, force_open,
datum/tgui/master_ui, datum/ui_state/state)
```dm
ui_interact(mob/user, datum/tgui/ui)
ui_data(mob/user)
ui_act(action, params)
ui_state()
```
- `src_object` - The atom, which UI corresponds to in the game world.
@@ -19,9 +19,9 @@ or set up a new instance of UI by calling the `SStgui` subsystem.
has into an associative list, which will then be sent to UI as a JSON string.
- `ui_act` - This proc receives user actions and reacts to them by changing
the state of the game.
- `ui_state` (set in `ui_interact`) - This var dictates under what conditions
a UI may be interacted with. This may be the standard checks that check if
you are in range and conscious, or more.
- `ui_state` - This proc dictates under what conditions a UI may be interacted
with. This may be the standard checks that check if you are in range and
conscious, or more.
Once backend is complete, you create an new interface component on the
frontend, which will receive this JSON data and render it on screen.
@@ -37,10 +37,10 @@ powerful interactions for embedded objects or remote access.
Let's start with a very basic hello world.
```dm
/obj/machinery/my_machine/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/my_machine/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "my_machine", name, 300, 300, master_ui, state)
ui = new(user, src, "MyMachine")
ui.open()
```
@@ -48,9 +48,7 @@ This is the proc that defines our interface. There's a bit going on here, so
let's break it down. First, we override the ui_interact proc on our object. This
will be called by `interact` for you, which is in turn called by `attack_hand`
(or `attack_self` for items). `ui_interact` is also called to update a UI (hence
the `try_update_ui`), so we accept an existing UI to update. The `state` is a
default argument so that a caller can overload it with named arguments
(`ui_interact(state = overloaded_state)`) if needed.
the `try_update_ui`), so we accept an existing UI to update.
Inside the `if(!ui)` block (which means we are creating a new UI), we choose our
template, title, and size; we can also set various options like `style` (for
@@ -294,10 +292,10 @@ here's what you need (note that you'll probably be forced to clean your shit up
upon code review):
```dm
/obj/copypasta/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state) // Remember to use the appropriate state.
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/copypasta/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "copypasta", name, 300, 300, master_ui, state)
ui = new(user, src, "copypasta")
ui.open()
/obj/copypasta/ui_data(mob/user)