Skip to content

Commit 4e6ecc2

Browse files
committed
⏸️ Add Text Alignment Option to Text Displays
1 parent b752f6f commit 4e6ecc2

File tree

6 files changed

+125
-19
lines changed

6 files changed

+125
-19
lines changed

src/components/textDisplayElementPanel.svelte

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
TEXT_DISPLAY_WIDTH_SLIDER,
88
TEXT_DISPLAY_BACKGROUND_COLOR_PICKER,
99
TEXT_DISPLAY_SHADOW_TOGGLE,
10+
TEXT_DISPLAY_ALIGNMENT_SELECT,
1011
} from '../interface/textDisplayElementPanel'
1112
import { floatToHex } from '../util/misc'
1213
import { translate } from '../util/translation'
@@ -28,6 +29,7 @@
2829
let lineWidthSlot: HTMLDivElement
2930
let backgroundColorSlot: HTMLDivElement
3031
let shadowSlot: HTMLDivElement
32+
let alignmentSlot: HTMLDivElement
3133
let codeJar: CodeJar
3234
3335
events.UPDATE_SELECTION.subscribe(() => {
@@ -43,12 +45,14 @@
4345
const color = selected.backgroundColor + floatToHex(selected.backgroundAlpha)
4446
TEXT_DISPLAY_BACKGROUND_COLOR_PICKER.set(color)
4547
TEXT_DISPLAY_SHADOW_TOGGLE.set(selected.shadow)
48+
TEXT_DISPLAY_ALIGNMENT_SELECT.set(selected.align)
4649
})
4750
4851
requestAnimationFrame(() => {
4952
lineWidthSlot.appendChild(TEXT_DISPLAY_WIDTH_SLIDER.node)
5053
backgroundColorSlot.appendChild(TEXT_DISPLAY_BACKGROUND_COLOR_PICKER.node)
5154
shadowSlot.appendChild(TEXT_DISPLAY_SHADOW_TOGGLE.node)
55+
alignmentSlot.appendChild(TEXT_DISPLAY_ALIGNMENT_SELECT.node)
5256
forceNoWrap()
5357
})
5458
@@ -67,6 +71,7 @@
6771
<div class="content" bind:this={lineWidthSlot}></div>
6872
<div class="content" bind:this={backgroundColorSlot}></div>
6973
<div class="content" bind:this={shadowSlot}></div>
74+
<div class="content" bind:this={alignmentSlot}></div>
7075
</div>
7176

7277
<div
@@ -127,6 +132,19 @@
127132
.custom-toolbar :global(.sp-replacer) {
128133
padding: 4px 18px !important;
129134
height: 28px !important;
130-
margin: 1px 0px !important;
135+
margin: 2px 0px !important;
136+
}
137+
.custom-toolbar :global([toolbar_item='animated_java:textDisplayShadowToggle']) {
138+
margin-right: 2px !important;
139+
}
140+
.custom-toolbar :global(.bar_select) {
141+
height: 28px !important;
142+
margin: 2px 0px !important;
143+
}
144+
.custom-toolbar :global(bb-select) {
145+
height: 28px !important;
146+
display: flex;
147+
align-items: center;
148+
padding-top: 0;
131149
}
132150
</style>

src/interface/textDisplayElementPanel.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { isCurrentFormat } from '../blueprintFormat'
22
import TextDisplayElementPanel from '../components/textDisplayElementPanel.svelte'
33
import { PACKAGE } from '../constants'
4-
import { TextDisplay } from '../outliner/textDisplay'
4+
import { Alignment, TextDisplay } from '../outliner/textDisplay'
55
import { injectSvelteCompomponentMod } from '../util/injectSvelte'
66
import { floatToHex } from '../util/misc'
77
import { translate } from '../util/translation'
@@ -98,3 +98,37 @@ TEXT_DISPLAY_SHADOW_TOGGLE.set = function (value) {
9898
this.click()
9999
return this
100100
}
101+
102+
export const TEXT_DISPLAY_ALIGNMENT_SELECT = new BarSelect(
103+
`${PACKAGE.name}:textDisplayAlignmentSelect`,
104+
{
105+
name: translate('tool.text_display.text_alignment.title'),
106+
icon: 'format_align_left',
107+
description: translate('tool.text_display.text_alignment.description'),
108+
condition: () => isCurrentFormat() && !!TextDisplay.selected.length,
109+
options: {
110+
left: translate('tool.text_display.text_alignment.options.left'),
111+
center: translate('tool.text_display.text_alignment.options.center'),
112+
right: translate('tool.text_display.text_alignment.options.right'),
113+
},
114+
}
115+
)
116+
TEXT_DISPLAY_ALIGNMENT_SELECT.get = function () {
117+
const selected = TextDisplay.selected[0]
118+
if (!selected) return 'left'
119+
return selected.align
120+
}
121+
TEXT_DISPLAY_ALIGNMENT_SELECT.set = function (this: BarSelect<Alignment>, value: Alignment) {
122+
const selected = TextDisplay.selected[0]
123+
if (!selected) return this
124+
this.value = value
125+
const name = this.getNameFor(value)
126+
this.nodes.forEach(node => {
127+
$(node).find('bb-select').text(name)
128+
})
129+
if (!this.nodes.includes(this.node)) {
130+
$(this.node).find('bb-select').text(name)
131+
}
132+
selected.align = value
133+
return this
134+
}

src/lang/en.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,12 @@ animated_java.tool.text_display.background_color.description: The color of the b
404404
animated_java.tool.text_display.text_shadow.title: Text Shadow
405405
animated_java.tool.text_display.text_shadow.description: Whether or not to display a shadow behind the text.
406406

407+
animated_java.tool.text_display.text_alignment.title: Text Alignment
408+
animated_java.tool.text_display.text_alignment.description: The alignment of the text.
409+
animated_java.tool.text_display.text_alignment.options.left: Left
410+
animated_java.tool.text_display.text_alignment.options.center: Center
411+
animated_java.tool.text_display.text_alignment.options.right: Right
412+
407413
# Vanilla Item Display Panel
408414
animated_java.panel.vanilla_item_display.title: Displayed Item
409415
animated_java.panel.vanilla_item_display.description: The item to display.

src/outliner/textDisplay.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ interface TextDisplayOptions {
3030
align?: Alignment
3131
visibility?: boolean
3232
}
33-
type Alignment = 'left' | 'center' | 'right'
33+
export type Alignment = 'left' | 'center' | 'right'
3434

3535
export class TextDisplay extends ResizableOutlinerElement {
3636
static type = `${PACKAGE.name}:text_display`
@@ -42,7 +42,6 @@ export class TextDisplay extends ResizableOutlinerElement {
4242
public needsUniqueName = true
4343

4444
// Properties
45-
public align: Alignment
4645
public config: IBlueprintTextDisplayConfigJSON
4746

4847
public menu = new Menu([
@@ -70,6 +69,8 @@ export class TextDisplay extends ResizableOutlinerElement {
7069
private _newBackgroundAlpha: number | undefined
7170
private _shadow = new Valuable(false)
7271
private _newShadow: boolean | undefined
72+
private _align = new Valuable<Alignment>('center')
73+
private _newAlign: Alignment | undefined
7374

7475
constructor(data: TextDisplayOptions, uuid = guid()) {
7576
super(data, uuid)
@@ -112,6 +113,10 @@ export class TextDisplay extends ResizableOutlinerElement {
112113
this._newShadow = v
113114
void this.updateText()
114115
})
116+
this._align.subscribe(v => {
117+
this._newAlign = v
118+
void this.updateText()
119+
})
115120
}
116121

117122
public sanitizeName(): string {
@@ -202,6 +207,16 @@ export class TextDisplay extends ResizableOutlinerElement {
202207
this._shadow.set(value)
203208
}
204209

210+
get align() {
211+
if (this._align === undefined) return TextDisplay.properties['align'].default as Alignment
212+
return this._align.get()
213+
}
214+
215+
set align(value) {
216+
if (this._align === undefined) return
217+
this._align.set(value)
218+
}
219+
205220
getUndoCopy() {
206221
const copy = new TextDisplay(this)
207222

@@ -275,7 +290,8 @@ export class TextDisplay extends ResizableOutlinerElement {
275290
this._newLineWidth !== undefined ||
276291
this._newBackgroundColor !== undefined ||
277292
this._newBackgroundAlpha !== undefined ||
278-
this._newShadow !== undefined
293+
this._newShadow !== undefined ||
294+
this._newAlign !== undefined
279295
) {
280296
let text: JsonText | undefined
281297
this.textError.set('')
@@ -291,6 +307,7 @@ export class TextDisplay extends ResizableOutlinerElement {
291307
this._newBackgroundColor = undefined
292308
this._newBackgroundAlpha = undefined
293309
this._newShadow = undefined
310+
this._newAlign = undefined
294311
if (!text) continue
295312
latestMesh = await this.setText(text)
296313
}
@@ -315,6 +332,7 @@ export class TextDisplay extends ResizableOutlinerElement {
315332
backgroundColor: this.backgroundColor,
316333
backgroundAlpha: this.backgroundAlpha,
317334
shadow: this.shadow,
335+
alignment: this.align,
318336
})
319337
mesh.name = this.uuid + '_text'
320338
const previousMesh = this.mesh.children.find(v => v.name === mesh.name)

src/systems/minecraft/fontManager.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
import { createHash } from 'crypto'
1414
import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils'
1515
import { UnicodeString } from '../../util/unicodeString'
16+
import { type Alignment } from '../../outliner/textDisplay'
1617

1718
interface IFontProviderBitmap {
1819
type: 'bitmap'
@@ -359,12 +360,14 @@ export class MinecraftFont {
359360
backgroundColor,
360361
backgroundAlpha,
361362
shadow,
363+
alignment,
362364
}: {
363365
jsonText: JsonText
364366
maxLineWidth: number
365367
backgroundColor: string
366368
backgroundAlpha: number
367369
shadow?: boolean
370+
alignment?: Alignment
368371
}): Promise<{ mesh: THREE.Mesh; outline: THREE.LineSegments }> {
369372
console.time('drawTextToMesh')
370373
const mesh = new THREE.Mesh()
@@ -425,8 +428,17 @@ export class MinecraftFont {
425428
const geos: THREE.BufferGeometry[] = []
426429
const cursor = { x: 0, y: height - 9 }
427430
for (const line of lines) {
431+
switch (alignment) {
432+
case 'center':
433+
cursor.x = -width / 2 + Math.ceil((width - line.width) / 2)
434+
break
435+
case 'right':
436+
cursor.x = -width / 2 + width - line.width
437+
break
438+
default:
439+
cursor.x = -width / 2 + 1
440+
}
428441
// center the line
429-
cursor.x = -width / 2 + Math.ceil((width - line.width) / 2)
430442
for (const word of line.words) {
431443
for (const span of word.styles) {
432444
const text = word.text.slice(span.start, span.end)

test_blueprints/empty.ajblueprint

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"meta": {
33
"format": "animated_java_blueprint",
4-
"format_version": "0.5.0",
4+
"format_version": "0.5.2",
55
"uuid": "a8205f23-18ae-5c38-fc3c-ad4397b0ed09",
66
"save_location": "D:\\github-repos\\animated-java\\animated-java\\test_blueprints\\empty.ajblueprint",
77
"last_used_export_namespace": "blueprint"
@@ -69,18 +69,18 @@
6969
},
7070
{
7171
"name": "wow",
72-
"position": [0, 23, 0],
72+
"position": [0, 23, -13],
7373
"rotation": [0, 0, 0],
7474
"scale": [1, 1, 1],
7575
"visibility": true,
7676
"item": "minecraft:diamond",
7777
"config": {},
7878
"block": "minecraft:stone",
79-
"text": "\"Wow!\"",
79+
"text": "\"Wow!\\nMultiple very different\\nLines!\"",
8080
"lineWidth": 200,
8181
"backgroundColor": "#000000",
8282
"backgroundAlpha": 0.25098,
83-
"align": "center",
83+
"align": "right",
8484
"uuid": "7edf27c8-19bd-8a1a-6c23-888d95c417d8",
8585
"type": "animated_java:text_display"
8686
},
@@ -202,7 +202,9 @@
202202
"uuid": "58eeab35-0b05-ed23-f696-b41f98f5c4f0",
203203
"time": 0,
204204
"color": -1,
205-
"interpolation": "linear"
205+
"interpolation": "linear",
206+
"easing": "linear",
207+
"easingArgs": []
206208
}
207209
]
208210
},
@@ -222,7 +224,9 @@
222224
"uuid": "42510118-620c-d795-55bb-c1f8e0841c81",
223225
"time": 0,
224226
"color": -1,
225-
"interpolation": "linear"
227+
"interpolation": "linear",
228+
"easing": "linear",
229+
"easingArgs": []
226230
}
227231
]
228232
}
@@ -260,7 +264,9 @@
260264
"uuid": "2369d2a5-0350-c288-393d-cfa8d4faf67a",
261265
"time": 0,
262266
"color": -1,
263-
"interpolation": "linear"
267+
"interpolation": "linear",
268+
"easing": "linear",
269+
"easingArgs": []
264270
}
265271
]
266272
},
@@ -280,7 +286,9 @@
280286
"uuid": "7da6acee-57cf-e294-35af-bb74485260bc",
281287
"time": 0,
282288
"color": -1,
283-
"interpolation": "linear"
289+
"interpolation": "linear",
290+
"easing": "linear",
291+
"easingArgs": []
284292
}
285293
]
286294
},
@@ -300,7 +308,9 @@
300308
"uuid": "bf25404d-a16c-4bde-ccca-04f3611385e4",
301309
"time": 0,
302310
"color": -1,
303-
"interpolation": "linear"
311+
"interpolation": "linear",
312+
"easing": "linear",
313+
"easingArgs": []
304314
}
305315
]
306316
}
@@ -339,7 +349,9 @@
339349
"time": 0,
340350
"color": -1,
341351
"uniform": false,
342-
"interpolation": "linear"
352+
"interpolation": "linear",
353+
"easing": "linear",
354+
"easingArgs": []
343355
}
344356
]
345357
},
@@ -360,7 +372,9 @@
360372
"time": 0,
361373
"color": -1,
362374
"uniform": false,
363-
"interpolation": "linear"
375+
"interpolation": "linear",
376+
"easing": "linear",
377+
"easingArgs": []
364378
}
365379
]
366380
},
@@ -380,7 +394,9 @@
380394
"uuid": "da69b774-9cfa-d2f4-03b1-2cf48551f7b1",
381395
"time": 0,
382396
"color": -1,
383-
"interpolation": "linear"
397+
"interpolation": "linear",
398+
"easing": "linear",
399+
"easingArgs": []
384400
},
385401
{
386402
"channel": "scale",
@@ -395,7 +411,9 @@
395411
"time": 0,
396412
"color": -1,
397413
"uniform": false,
398-
"interpolation": "linear"
414+
"interpolation": "linear",
415+
"easing": "linear",
416+
"easingArgs": []
399417
}
400418
]
401419
}

0 commit comments

Comments
 (0)