Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Widget Monitor #676

Merged
merged 4 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/product/widget.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ After adding a Widget, users can adjust its Name, Basic Config, Advanced Config,
Both the code of the Stage and the Sprite can interact with the Widgets in the current Stage through the following interfaces:

```go
scoreMonitor := getWidget("score").(Monitor)
usernameInput := getWidget("usernameInput").(Input)
scoreMonitor := getWidget(Monitor, "score")
usernameInput := getWidget(Input, "usernameInput")

// `show` & `setXYPos` are basic methods provided by all types of Widgets
scoreMonitor.show
Expand Down
4 changes: 2 additions & 2 deletions docs/product/widget.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ Widget 添加完成后,用户可以调整其 Name、Basic Config、Advanced Co
Stage 与 Sprite 的代码均可以通过以下接口与当前 Stage 中的 Widget 进行交互:

```go
scoreMonitor := getWidget("score").(Monitor)
usernameInput := getWidget("usernameInput").(Input)
scoreMonitor := getWidget(Monitor, "score")
usernameInput := getWidget(Input, "usernameInput")

// `show` & `setXYPos` 等是基础方法,所有类别的 Widget 都会提供
scoreMonitor.show
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
@click="handleAddFromLocalFile.fn"
>
<template #icon>
<img class="icon" :src="localFileImg" />
<img :src="localFileImg" />
</template>
{{ $t({ en: 'Select local file', zh: '选择本地文件' }) }}
</UIButton>
Expand All @@ -24,7 +24,7 @@
@click="handleAddFromAssetLibrary.fn"
>
<template #icon>
<img class="icon" :src="assetLibraryImg" />
<img :src="assetLibraryImg" />
</template>
{{ $t({ en: 'Choose from asset library', zh: '从素材库选择' }) }}
</UIButton>
Expand Down Expand Up @@ -55,10 +55,3 @@ const handleAddFromAssetLibrary = useMessageHandle(
{ en: 'Failed to add sprite from asset library', zh: '从素材库添加失败' }
)
</script>

<style scoped lang="scss">
.icon {
width: 24px;
height: 24px;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,9 @@ const config = computed<CustomTransformerConfig>(() => {
centeredScaling: true
}
}
if (project.stage.selectedWidget != null) {
return {
rotationStyle: 'none',
centeredScaling: false
}
}
return {
// rotationStyle: 'none',
// centeredScaling:
rotationStyle: 'none',
centeredScaling: false
}
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,9 @@ const valueRectConfig = computed<RectConfig>(() => {
})

const valueTextConfig = computed<TextConfig>(() => {
const { value } = props.monitor
const { variableName } = props.monitor
return {
text: value === '' ? ' ' : `{${value}}`,
text: variableName === '' ? ' ' : `{${variableName}}`,
x: paddingX[0] + labelTextWidth.value + labelValueGap + valuePaddingX,
y: paddingY,
lineHeight,
Expand Down
6 changes: 1 addition & 5 deletions spx-gui/src/components/editor/sprite/AnimationEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<template #op>
<UIButton type="boring" size="large" @click="handleGroupCostumes">
<template #icon>
<img class="icon" :src="galleryIcon" />
<img :src="galleryIcon" />
</template>
{{ $t({ en: 'Group costumes as animation', zh: '将造型合并为动画' }) }}
</UIButton>
Expand Down Expand Up @@ -98,10 +98,6 @@ const handleGroupCostumes = useMessageHandle(
).fn
</script>
<style scoped lang="scss">
.icon {
width: 24px;
height: 24px;
}
.background {
width: 100%;
height: 100%;
Expand Down
11 changes: 6 additions & 5 deletions spx-gui/src/components/editor/stage/StageEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,12 @@ watchEffect(() => {
const codeEditor = ref<InstanceType<typeof CodeEditor>>()
const code = computed(() => props.stage.code)

// We define `codeUpdateAction` outside of `handleCodeUpdate` to keep reference-equal for `mergeable`, see details in project history
const codeUpdateAction = {
name: { en: 'Update stage code', zh: '修改舞台代码' },
mergeable: true
}
function handleCodeUpdate(value: string) {
const action = {
name: { en: 'Update stage code', zh: '修改舞台代码' },
mergeable: true
}
editorCtx.project.history.doAction(action, () => props.stage.setCode(value))
editorCtx.project.history.doAction(codeUpdateAction, () => props.stage.setCode(value))
}
</script>
16 changes: 14 additions & 2 deletions spx-gui/src/components/editor/stage/widget/WidgetsEditor.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
<template>
<EditorList color="stage" :add-text="$t({ en: 'Add widget', zh: '添加控件' })">
<UIEmpty v-if="stage.widgets.length === 0" size="extra-large">
{{ $t({ en: 'No widgets', zh: '没有控件' }) }}
<template #op>
<UIButton type="boring" size="large" @click="handleAddMonitor">
<template #icon>
<img :src="monitorIcon" />
</template>
{{ $t({ en: 'Add widget Monitor', zh: '添加监视器控件' }) }}
</UIButton>
</template>
</UIEmpty>
<EditorList v-else color="stage" :add-text="$t({ en: 'Add widget', zh: '添加控件' })">
<WidgetItem
v-for="widget in stage.widgets"
:key="widget.name"
Expand All @@ -21,14 +32,15 @@

<script setup lang="ts">
import { computed, onMounted, onUnmounted } from 'vue'
import { UIMenu, UIMenuItem } from '@/components/ui'
import { UIMenu, UIMenuItem, UIEmpty, UIButton } from '@/components/ui'
import { useMessageHandle } from '@/utils/exception'
import { type Widget } from '@/models/widget'
import { Monitor } from '@/models/widget/monitor'
import { useEditorCtx } from '../../EditorContextProvider.vue'
import EditorList from '../../common/EditorList.vue'
import WidgetItem from './WidgetItem.vue'
import WidgetDetail from './detail/WidgetDetail.vue'
import monitorIcon from './monitor-gray.svg'

const editorCtx = useEditorCtx()
const stage = computed(() => editorCtx.project.stage)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
<UITextInput class="input" :value="monitor.label" @update:value="handleLabelUpdate">
<template #prefix>{{ $t({ en: 'Label', zh: '标签' }) }}:</template>
</UITextInput>
<UITextInput class="input" :value="monitor.value" @update:value="handleValueUpdate">
<UITextInput
class="input"
:value="monitor.variableName"
@update:value="handleValueUpdate"
>
<template #prefix>{{ $t({ en: 'Value', zh: '值' }) }}:</template>
</UITextInput>
</div>
Expand Down Expand Up @@ -94,7 +98,10 @@ const handleRename = useMessageHandle(
// 2. It's ok to omit the debounce for label / value update
// TODO: we should make the behaviors of different inputs (`UINumberInput`, `UITextInput`, ...) consistent. Then remove differences here.
const handleLabelUpdate = wrapUpdateHandler((label: string) => props.monitor.setLabel(label), false)
const handleValueUpdate = wrapUpdateHandler((value: string) => props.monitor.setValue(value), false)
const handleValueUpdate = wrapUpdateHandler(
(value: string) => props.monitor.setVariableName(value),
false
)

// TODO: common logic may be extracted when we have more widget types
const handleXUpdate = wrapUpdateHandler((x: number | null) => props.monitor.setX(x ?? 0))
Expand Down
17 changes: 17 additions & 0 deletions spx-gui/src/components/editor/stage/widget/monitor-gray.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion spx-gui/src/components/editor/stage/widget/monitor.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions spx-gui/src/components/ui/empty/UIEmpty.vue
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ const slots = useSlots()
margin-top: 24px;
display: flex;
gap: var(--ui-gap-large);

// TODO: more reliable approach?
:deep(.ui-button svg),
:deep(.ui-button img) {
width: 24px;
height: 24px;
}
}
}

Expand Down
56 changes: 37 additions & 19 deletions spx-gui/src/models/stage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('Stage', () => {
expect(stage.widgets.length).toBe(0)
const monitor1 = new Monitor('monitor', {
label: 'label1',
value: 'value1',
variableName: 'value1',
x: 10,
y: 20,
size: 2,
Expand All @@ -19,15 +19,15 @@ describe('Stage', () => {
expect(stage.widgets.length).toBe(1)
expect(stage.widgets[0].name).toBe('monitor')
expect(stage.widgets[0].label).toBe('label1')
expect(stage.widgets[0].value).toBe('value1')
expect(stage.widgets[0].variableName).toBe('value1')
expect(stage.widgets[0].x).toBe(10)
expect(stage.widgets[0].y).toBe(20)
expect(stage.widgets[0].size).toBe(2)
expect(stage.widgets[0].visible).toBe(true)

const monitor2 = new Monitor('monitor', {
label: 'label2',
value: 'value2',
variableName: 'value2',
x: 0,
y: 0,
size: 1,
Expand All @@ -37,7 +37,7 @@ describe('Stage', () => {
expect(stage.widgets.length).toBe(2)
expect(stage.widgets[1].name).toBe('monitor2')
expect(stage.widgets[1].label).toBe('label2')
expect(stage.widgets[1].value).toBe('value2')
expect(stage.widgets[1].variableName).toBe('value2')
expect(stage.widgets[1].x).toBe(0)
expect(stage.widgets[1].y).toBe(0)
expect(stage.widgets[1].size).toBe(1)
Expand All @@ -46,20 +46,26 @@ describe('Stage', () => {
const [stageConfig] = stage.export()
expect(stageConfig.widgets!.length).toBe(2)
expect(stageConfig.widgets![0]).toEqual({
type: 'MonitorWidget',
type: 'monitor',
name: 'monitor',
mode: 1,
target: '',
color: 15629590,
label: 'label1',
value: 'value1',
val: 'getVar:value1',
x: 10,
y: 20,
size: 2,
visible: true
})
expect(stageConfig.widgets![1]).toEqual({
type: 'MonitorWidget',
type: 'monitor',
name: 'monitor2',
mode: 1,
target: '',
color: 15629590,
label: 'label2',
value: 'value2',
val: 'getVar:value2',
x: 0,
y: 0,
size: 1,
Expand All @@ -71,7 +77,7 @@ describe('Stage', () => {
const stage = new Stage()
const monitor1 = new Monitor('monitor', {
label: 'label1',
value: 'value1',
variableName: 'value1',
x: 10,
y: 20,
size: 2,
Expand All @@ -80,7 +86,7 @@ describe('Stage', () => {
stage.addWidget(monitor1)
const monitor2 = new Monitor('monitor2', {
label: 'label2',
value: 'value2',
variableName: 'value2',
x: 0,
y: 0,
size: 1,
Expand Down Expand Up @@ -120,20 +126,26 @@ describe('Stage', () => {
{
widgets: [
{
type: 'MonitorWidget',
type: 'monitor',
name: 'monitor',
mode: 1,
target: '',
color: 15629590,
label: 'label1',
value: 'value1',
val: 'getVar:value1',
x: 10,
y: 20,
size: 2,
visible: true
},
{
type: 'MonitorWidget',
type: 'monitor',
name: 'monitor2',
mode: 1,
target: '',
color: 15629590,
label: 'label2',
value: 'value2',
val: 'getVar:value2',
x: 0,
y: 0,
size: 1,
Expand All @@ -146,7 +158,7 @@ describe('Stage', () => {
expect(stage.widgets.length).toBe(2)
expect(stage.widgets[0].name).toBe('monitor')
expect(stage.widgets[0].label).toBe('label1')
expect(stage.widgets[0].value).toBe('value1')
expect(stage.widgets[0].variableName).toBe('value1')
expect(stage.widgets[0].x).toBe(10)
expect(stage.widgets[0].y).toBe(20)
expect(stage.widgets[0].size).toBe(2)
Expand All @@ -156,20 +168,26 @@ describe('Stage', () => {
const [stageConfig] = stage.export()
expect(stageConfig.widgets!.length).toBe(2)
expect(stageConfig.widgets![0]).toEqual({
type: 'MonitorWidget',
type: 'monitor',
name: 'monitor',
mode: 1,
target: '',
color: 15629590,
label: 'label1',
value: 'value1',
val: 'getVar:value1',
x: 10,
y: 20,
size: 2,
visible: true
})
expect(stageConfig.widgets![1]).toEqual({
type: 'MonitorWidget',
type: 'monitor',
name: 'monitor2',
mode: 1,
target: '',
color: 15629590,
label: 'label2',
value: 'value2',
val: 'getVar:value2',
x: 0,
y: 0,
size: 1,
Expand Down
6 changes: 4 additions & 2 deletions spx-gui/src/models/stage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ export const stageCodeFilePaths = ['main.spx', 'index.spx', 'main.gmx', 'index.g
const stageCodeFilePath = stageCodeFilePaths[0]
const stageCodeFileName = filename(stageCodeFilePath)

export const defaultMapSize: MapSize = { width: 480, height: 360 }

export class Stage {
code: string
setCode(code: string) {
Expand Down Expand Up @@ -199,8 +201,8 @@ export class Stage {
this.backdropIndex = inits?.backdropIndex ?? 0
this.widgets = []
this.widgetsZorder = []
this.mapWidth = inits?.mapWidth ?? 480
this.mapHeight = inits?.mapHeight ?? 360
this.mapWidth = inits?.mapWidth ?? defaultMapSize.width
this.mapHeight = inits?.mapHeight ?? defaultMapSize.height
this.mapMode = getMapMode(inits?.mapMode)
return reactive(this) as this
}
Expand Down
Loading
Loading