airobot/ui/mainwindow.go
2022-12-26 14:10:19 +08:00

951 lines
24 KiB
Go

package ui
import (
"encoding/json"
"fmt"
"io/fs"
"io/ioutil"
"path/filepath"
"sort"
"strings"
"sync/atomic"
"time"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"github.com/dengsgo/math-engine/engine"
"github.com/sirupsen/logrus"
"github.com/spf13/cast"
"legu.airobot/lib"
"legu.airobot/storage"
)
var globalWindow *MainWindow
var _ IWindow = (*MainWindow)(nil)
type MainWindow struct {
UIImpl
ai *lib.MyAI
w fyne.Window
statusbar *statusBar //状态栏
mainMenu *mainMenu //菜单
progress *widget.ProgressBar //进度条
progressCounter int32 //进度条计数
endProgress chan interface{}
progressChan chan struct{}
tipLabel *widget.Label //提示Label
startBtn *widget.Button //开始按钮
robotCount int32
}
func NewMainWdindow(ui *UIImpl) IWindow {
mw := &MainWindow{
UIImpl: *ui,
progressChan: make(chan struct{}),
endProgress: make(chan interface{}, 1),
}
globalWindow = mw
return mw
}
func (mw *MainWindow) CreateWindow(_ string, width, height float32, visible bool) {
title := fmt.Sprintf(APP_WIN_TITLE, APP_NAME, mw.app.Metadata().Version, mw.app.Metadata().Build)
w := mw.app.NewWindow(title)
mw.w = w
// 状态栏
mw.statusbar = newStatusBar()
// 菜单
mw.mainMenu = newMainMenu()
mw.w.SetMainMenu(mw.mainMenu.MainMenu)
//content
content := container.NewBorder(nil, mw.statusbar.widget, nil, nil)
mw.w.SetContent(content)
// 默认
mw.startContainer()
w.Resize(fyne.NewSize(width, height))
w.SetMaster()
w.CenterOnScreen()
w.SetCloseIntercept(mw.quiteHandle)
w.Show()
}
func (mw *MainWindow) changeContent(content fyne.CanvasObject) {
mw.w.SetContent(content)
}
// 开始
func (mw *MainWindow) startContainer() {
mw.startBtn = widget.NewButton("启动", nil)
mw.startBtn.Disable()
config := mw.config
// 检查全局配置
if config.Global == nil {
dialog.ShowCustomConfirm("提示", "设置", "取消", widget.NewLabel("还没有任何配置"), func(b bool) {
if !b {
return
}
mw.configContainer()
}, mw.w)
return
}
// 检查场景配置
if config.Scenes == nil {
dialog.ShowCustomConfirm("提示", "选择", "取消", widget.NewLabel("还没有选择任何场景"), func(b bool) {
if !b {
return
}
mw.newSceneContainer()
}, mw.w)
return
}
mw.progress = widget.NewProgressBar()
mw.tipLabel = widget.NewLabel("")
mw.UIImpl.obs.AddListener(lib.EVENT_PROGRESS, lib.Listener{
OnNotify: mw.showProgress,
})
mw.UIImpl.obs.AddListener(lib.EVENT_ROBOT, lib.Listener{
OnNotify: mw.listenRobot,
})
mw.startBtn.Enable()
mw.startBtn.OnTapped = func() {
atomic.StoreInt32(&mw.robotCount, 0)
atomic.StoreInt32(&mw.progressCounter, 0)
mw.progress.SetValue(0)
mw.tipLabel.SetText("进行中...")
mw.startBtn.Disable()
param := lib.AIParam{
Scenes: mw.UIImpl.scenes,
Config: mw.UIImpl.config,
}
ai, err := lib.NewAI(param)
if err != nil {
dialog.ShowError(err, mw.w)
return
}
ai.Obs = mw.UIImpl.obs
mw.ai = ai
ai.Start()
mw.showReport()
}
content := container.NewBorder(mw.progress, nil, nil, nil,
container.NewCenter(container.NewVBox(mw.tipLabel, mw.startBtn)))
mw.changeContent(content)
}
func (mw *MainWindow) showReport() {
start := time.Now()
<-mw.progressChan
logrus.Debug("开始生成测试报告")
elipse := time.Since(start)
mw.ai.MergeResult()
mw.ai.GenReport(elipse)
mw.startBtn.Enable()
atomic.StoreInt32(&mw.progressCounter, 0)
mw.tipLabel.SetText("已生成报表")
}
func (mw *MainWindow) showProgress(data interface{}, args ...interface{}) {
count := data.(int32)
rc := atomic.LoadInt32(&mw.progressCounter)
atomic.StoreInt32(&mw.progressCounter, count+rc)
//计算进度
max := int(mw.config.Global.UserCountTotal) * len(mw.config.Scenes)
expr := fmt.Sprintf("%v/%v", atomic.LoadInt32(&mw.progressCounter), max)
logrus.Debug(expr)
r, err := engine.ParseAndExec(expr)
if err != nil {
logrus.Error(err)
return
}
mw.progress.SetValue(r)
if r >= 1 {
mw.tipLabel.SetText("正在处理结果...")
mw.progressChan <- struct{}{}
}
}
func (mw *MainWindow) listenRobot(data interface{}, args ...interface{}) {
count := data.(int32)
rc := atomic.LoadInt32(&mw.robotCount)
atomic.StoreInt32(&mw.robotCount, count+rc)
mw.tipLabel.SetText(fmt.Sprintf("投放用户数:%d/%d", atomic.LoadInt32(&mw.robotCount), mw.config.Global.UserCountTotal))
}
// 全局配置
func (mw *MainWindow) configContainer() {
config := mw.config.Global
wsAddrEntry := widget.NewEntry()
sidEntry := widget.NewEntry()
userCountEntry := widget.NewEntry()
userCountEntry.PlaceHolder = "每次压入的用户数"
userTotalEntry := widget.NewEntry()
userTotalEntry.PlaceHolder = "总共需要压入的最大用户数"
timeoutEntry := widget.NewEntry()
timeoutEntry.PlaceHolder = "请求超时时间"
intervalEntry := widget.NewEntry()
intervalEntry.PlaceHolder = "每次压入用户间隔时间"
form := widget.NewForm(
widget.NewFormItem("服务地址", wsAddrEntry),
widget.NewFormItem("区服编号", sidEntry),
widget.NewFormItem("用户数上限", userTotalEntry),
widget.NewFormItem("用户数", userCountEntry),
widget.NewFormItem("间隔时间(s)", intervalEntry),
widget.NewFormItem("超时时间(ms)", timeoutEntry),
)
loadForm := func() {
wsAddrEntry.Text = config.WsAddr
sidEntry.Text = config.SId
userTotalEntry.Text = cast.ToString(config.UserCountTotal)
userCountEntry.Text = cast.ToString(config.UserCount)
timeoutEntry.Text = cast.ToString(config.TimeoutMs)
intervalEntry.Text = cast.ToString(config.IntervalS)
}
if config != nil {
loadForm()
}
saveBtn := widget.NewButtonWithIcon("保存", theme.DocumentSaveIcon(), nil)
saveBtn.OnTapped = func() {
global := &storage.Global{
WsAddr: wsAddrEntry.Text,
SId: sidEntry.Text,
UserCountTotal: cast.ToUint32(userTotalEntry.Text),
UserCount: cast.ToUint32(userCountEntry.Text),
TimeoutMs: cast.ToInt32(timeoutEntry.Text),
IntervalS: cast.ToInt32(intervalEntry.Text),
}
mw.config.Global = global
if err := mw.storage.StoreConfig(mw.config); err != nil {
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
return
}
}
btns := container.NewHBox(layout.NewSpacer(), saveBtn)
content := container.NewVBox(form, btns)
mw.changeContent(content)
}
//旧场景
func (mw *MainWindow) sceneContainer() {
var selSceneName string
// 用例列表
callerItemList := *lib.NewItemList()
callerItemList.ListWidget = callerItemList.CreateList()
callerLoad := func(sceneId string) {
callerItemList.Reset()
for _, v := range mw.config.Scenes {
if v.ID == sceneId {
sort.SliceStable(v.Callers, func(i, j int) bool {
return v.Callers[i].Num < v.Callers[j].Num
})
for _, v2 := range v.Callers {
item := lib.Item{
Id: cast.ToString(v2.ID),
Text: fmt.Sprintf("%d. %v %v", v2.Num, v2.Name, v2.Key),
}
callerItemList.AddItem(item)
}
}
}
}
//场景列表
sceneItemList := *lib.NewItemList()
sceneItemList.OnSelFunc = func(id widget.ListItemID) {
selId := sceneItemList.CachedList.Items[id].Id
selSceneName = sceneItemList.CachedList.Items[id].Text
sceneItemList.SelItemId = selId
callerLoad(selId)
}
sceneItemList.ListWidget = sceneItemList.CreateList()
sceneLoad := func() {
sceneItemList.Reset()
logrus.WithField("场景", mw.config.Scenes).Debug("配置")
for _, v := range mw.config.Scenes {
txt := fmt.Sprintf("%v %s", v.Name, v.Desc)
if v.Status == lib.STATUS_ENABLE {
txt = fmt.Sprintf("* %s %s", v.Name, v.Desc)
}
item := lib.Item{
Id: cast.ToString(v.ID),
Text: txt,
}
sceneItemList.AddItem(item)
}
}
// 场景表单
sceneNameEntry := widget.NewEntry()
sceneDescEntry := widget.NewEntry()
sceneItems := []*widget.FormItem{
widget.NewFormItem("名称", sceneNameEntry),
widget.NewFormItem("描述", sceneDescEntry),
}
//重置场景表单
sceneFormReset := func() {
sceneNameEntry.Text = ""
sceneDescEntry.Text = ""
}
// 用例表单
callerNameEntry := widget.NewEntry()
callerKeyEntry := widget.NewEntry()
callerNumEntry := widget.NewEntry()
callerNumEntry.PlaceHolder = "0"
callerItems := []*widget.FormItem{
widget.NewFormItem("名称", callerNameEntry),
widget.NewFormItem("协议", callerKeyEntry),
widget.NewFormItem("序号", callerNumEntry),
}
//重置用例表单
callerFormReset := func() {
callerNameEntry.Text = ""
callerKeyEntry.Text = ""
}
// 场景按钮
newSceneBtn := widget.NewButtonWithIcon("新建场景", theme.FileIcon(), nil)
editSceneBtn := widget.NewButtonWithIcon("编辑场景", theme.DocumentCreateIcon(), nil)
deleSceneBtn := widget.NewButtonWithIcon("删除场景", theme.DeleteIcon(), nil)
enableSceneBtn := widget.NewButton("启用场景", nil)
// 添加用例按钮
newCallerBtn := widget.NewButtonWithIcon("添加用例", theme.FileIcon(), nil)
deleCallerBtn := widget.NewButtonWithIcon("删除用例", theme.DocumentCreateIcon(), nil)
// 刷新场景
refreshBtn := widget.NewButtonWithIcon("", theme.ViewRefreshIcon(), nil)
// 工具条
toolbar := container.NewHBox(newSceneBtn, editSceneBtn, deleSceneBtn, enableSceneBtn, widget.NewSeparator(),
newCallerBtn, deleCallerBtn, layout.NewSpacer(), refreshBtn)
//布局
var dynamic fyne.CanvasObject
contentRender := func() {
sceneLoad()
if len(sceneItemList.CachedList.Items) == 0 {
dynamic = container.NewCenter(widget.NewLabel("还没有创建任何场景"))
} else {
split := container.NewHSplit(sceneItemList.ListWidget, callerItemList.ListWidget)
split.Offset = 0.3
dynamic = split
}
content := container.NewBorder(toolbar, nil, nil, nil, dynamic)
mw.changeContent(content)
}
contentRender()
// 刷新场景
refreshBtn.OnTapped = func() {
sceneItemList.Reset()
callerItemList.Reset()
contentRender()
}
//新建场景事件
newSceneBtn.OnTapped = func() {
newSceneWin := dialog.NewForm("新建场景", "确定", "取消", sceneItems, func(b bool) {
if !b {
return
}
scenes_conf := mw.config.Scenes
scenes_conf = append(scenes_conf, &storage.Scene{
ID: cast.ToString(time.Now().Nanosecond()),
Name: sceneNameEntry.Text,
Desc: sceneDescEntry.Text,
})
mw.config.Scenes = scenes_conf
if err := mw.storage.StoreConfig(mw.config); err != nil {
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
return
}
sceneFormReset()
contentRender()
}, mw.w)
newSceneWin.Resize(fyne.NewSize(300, 200))
newSceneWin.Show()
}
// 编辑场景事件
editSceneBtn.OnTapped = func() {
selId := sceneItemList.SelItemId
if selId == "" {
ShowTip("请选择一个场景")
return
}
// 加载
var sceneConf *storage.Scene
for _, item := range mw.config.Scenes {
if item.ID == selId {
sceneConf = item
}
}
if sceneConf != nil {
sceneNameEntry.Text = sceneConf.Name
sceneDescEntry.Text = sceneConf.Desc
}
editSceneWin := dialog.NewForm("编辑场景", "确定", "取消", sceneItems, func(b bool) {
if !b {
return
}
for _, item := range mw.config.Scenes {
if item.ID == selId {
item.Name = sceneNameEntry.Text
item.Desc = sceneDescEntry.Text
}
}
if err := mw.storage.StoreConfig(mw.config); err != nil {
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
return
}
sceneFormReset()
// contentRender()
}, mw.w)
editSceneWin.Resize(fyne.NewSize(300, 200))
editSceneWin.Show()
}
// 删除场景事件
deleSceneBtn.OnTapped = func() {
selId := sceneItemList.SelectedId()
if selId == "" {
ShowTip("请选择一个场景")
return
}
scenes := mw.config.Scenes
for i, item := range scenes {
if item.ID == selId {
if len(item.Callers) > 0 {
dialog.ShowCustomConfirm("提示", "确定", "取消", widget.NewLabel("该场景下存在用例,确定删除场景【"+item.Name+"】吗?"), func(b bool) {
if !b {
return
}
for y, v := range scenes {
if v.ID == selId {
scenes = append(scenes[:y], scenes[y+1:]...)
}
}
mw.config.Scenes = scenes
callerItemList.Reset()
contentRender()
if err := mw.storage.StoreConfig(mw.config); err != nil {
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
return
}
}, mw.w)
} else {
scenes = append(scenes[:i], scenes[i+1:]...)
mw.config.Scenes = scenes
callerItemList.Reset()
contentRender()
}
if err := mw.storage.StoreConfig(mw.config); err != nil {
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
return
}
}
}
}
// 启用场景
enableSceneBtn.OnTapped = func() {
selId := sceneItemList.SelectedId()
if selId == "" {
ShowTip("请选择一个场景")
return
}
for _, item := range mw.config.Scenes {
if item.ID == selId {
if len(item.Callers) == 0 {
ShowTip("请至少添加一个用例")
return
}
item.Status = lib.STATUS_ENABLE
} else {
item.Status = lib.STATUS_DISENABLE
}
}
if err := mw.storage.StoreConfig(mw.config); err != nil {
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
return
}
contentRender()
}
//添加用例事件
newCallerBtn.OnTapped = func() {
selId := sceneItemList.SelectedId()
if selId == "" {
ShowTip("请选择一个场景")
return
}
//form
callerForm := widget.NewForm(callerItems...)
callerNameEntry.Disable()
callerKeyEntry.Disable()
callerForm.OnSubmit = func() {
scenes_conf := mw.config.Scenes
for _, v := range scenes_conf {
if selId == v.ID {
v.Callers = append(v.Callers, &storage.Caller{
ID: fmt.Sprintf("%s_%d", v.ID, time.Now().UnixNano()),
Name: callerNameEntry.Text,
Key: callerKeyEntry.Text,
Num: cast.ToInt(callerNumEntry.Text),
})
}
}
mw.config.Scenes = scenes_conf
if err := mw.storage.StoreConfig(mw.config); err != nil {
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
return
}
callerFormReset()
callerLoad(selId)
}
callerForm.SubmitText = "确定"
//list
registerCallerList := *lib.NewItemList()
registerCallerList.OnSelFunc = func(id widget.ListItemID) {
data := registerCallerList.CachedList.Items[id].Data
info, ok := data.(lib.SceneInfo)
if !ok {
return
}
callerNameEntry.Text = info.Desc
callerKeyEntry.Text = info.Name
callerForm.Refresh()
}
registerCallerList.ListWidget = registerCallerList.CreateList()
registerCallerReload := func() {
for _, v := range mw.UIImpl.scenes {
info := v.Info()
item := lib.Item{
Id: info.Name,
Text: fmt.Sprintf("%s (%s)", info.Desc, info.Name),
Data: info,
}
registerCallerList.AddItem(item)
}
registerCallerList.SearchItem = registerCallerList.CachedList.Items
}
registerCallerReload()
//search
searchEntry := widget.NewEntry()
searchEntry.PlaceHolder = "输入要搜索的用例"
searchEntry.OnChanged = func(s string) {
if s == "" {
registerCallerReload()
} else {
newList := []lib.Item{}
for _, v := range registerCallerList.SearchItem {
if strings.Contains(v.Text, s) {
newList = append(newList, v)
}
}
registerCallerList.CachedList.Items = newList
registerCallerList.ListWidget.Refresh()
}
}
// layout
contentSplit := container.NewHSplit(
container.NewBorder(container.NewBorder(nil, nil, nil, nil, searchEntry),
nil, nil, nil, registerCallerList.ListWidget),
callerForm,
)
contentSplit.Offset = 0.5
title := fmt.Sprintf("新建用例 - %s", selSceneName)
newCallerWin := dialog.NewCustom(title, "关闭", contentSplit, mw.w)
newCallerWin.Resize(fyne.NewSize(800, 600))
newCallerWin.Show()
}
// 删除用例事件
deleCallerBtn.OnTapped = func() {
selSceneId := sceneItemList.SelectedId()
if selSceneId == "" {
ShowTip("请选择一个场景")
return
}
selCallerId := callerItemList.SelectedId()
if selCallerId == "" {
ShowTip("请选择一个用例")
return
}
scenes := mw.config.Scenes
for _, item := range scenes {
if item.ID == selSceneId {
for y, c := range item.Callers {
if c.ID == selCallerId {
item.Callers = append(item.Callers[:y], item.Callers[y+1:]...)
}
}
}
}
mw.config.Scenes = scenes
if err := mw.storage.StoreConfig(mw.config); err != nil {
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
return
}
callerLoad(selSceneId)
}
}
// 新场景
func (mw *MainWindow) newSceneContainer() {
//注册的场景列表
registerSceneList := *lib.NewItemList()
// registerSceneList.OnSelFunc = func(id widget.ListItemID) {
// data := registerSceneList.CachedList.Items[id].Data
// info, ok := data.(lib.SceneInfo)
// if !ok {
// return
// }
// logrus.Debug(info)
// // callerNameEntry.Text = info.Desc
// // callerKeyEntry.Text = info.Name
// // callerForm.Refresh()
// }
registerSceneList.ListWidget = registerSceneList.CreateList()
registerSceneReload := func() {
registerSceneList.Reset()
for _, v := range mw.UIImpl.scenes {
info := v.Info()
item := lib.Item{
Id: info.Name,
Text: fmt.Sprintf("【%s】 %s", info.Name, info.Desc),
Data: info,
}
registerSceneList.AddItem(item)
}
registerSceneList.SearchItem = registerSceneList.CachedList.Items
}
// 选中的场景列表
selectedSceneList := *lib.NewItemList()
selectedSceneList.ListWidget = selectedSceneList.CreateList()
selectedSceneLoad := func() {
selectedSceneList.Reset()
scenes := mw.config.Scenes
sort.SliceStable(scenes, func(i, j int) bool {
return scenes[i].Num < scenes[j].Num
})
for _, v := range scenes {
item := lib.Item{
Id: v.ID,
Text: fmt.Sprintf("%d【%s】 %s", v.Num, v.Name, v.Desc),
}
selectedSceneList.AddItem(item)
}
}
//场景按钮
addSceneBtn := widget.NewButtonWithIcon("添加场景", theme.ContentAddIcon(), nil)
deleSceneBtn := widget.NewButtonWithIcon("删除场景", theme.DeleteIcon(), nil)
setBtn := widget.NewButtonWithIcon("场景配置", theme.ListIcon(), nil)
//search
searchEntry := widget.NewEntry()
searchEntry.PlaceHolder = "输入要搜索的用例"
searchEntry.OnChanged = func(s string) {
if s == "" {
registerSceneReload()
} else {
newList := []lib.Item{}
for _, v := range registerSceneList.SearchItem {
if strings.Contains(v.Text, s) {
newList = append(newList, v)
}
}
registerSceneList.CachedList.Items = newList
registerSceneList.ListWidget.Refresh()
}
}
//布局
var dynamic fyne.CanvasObject
contentRender := func() {
registerSceneReload()
if len(registerSceneList.CachedList.Items) == 0 {
dynamic = container.NewCenter(widget.NewLabel("还没有注册任何场景"))
} else {
selectedSceneLoad()
if len(selectedSceneList.CachedList.Items) == 0 {
dynamic = container.NewCenter(widget.NewLabel("还没有选择任何场景"))
} else {
dynamic = container.NewBorder(container.NewHBox(setBtn, deleSceneBtn, layout.NewSpacer()), nil, nil, nil, selectedSceneList.ListWidget)
}
}
split := container.NewHSplit(
container.NewBorder(
container.NewBorder(nil, nil, container.NewHBox(addSceneBtn), nil, searchEntry), nil, nil, nil,
registerSceneList.ListWidget), dynamic)
split.Offset = 0.5
mw.changeContent(split)
}
contentRender()
getMaxNum := func() int {
scenes := mw.config.Scenes
if len(scenes) == 0 {
return 1
}
// 降序
sort.SliceStable(scenes, func(i, j int) bool {
return scenes[i].Num > scenes[j].Num
})
return scenes[0].Num + 1
}
// 添加场景事件
addSceneBtn.OnTapped = func() {
selId := registerSceneList.SelectedId()
if selId == "" {
ShowTip("请选择一个场景")
return
}
for _, v := range mw.UIImpl.scenes {
si := v.Info()
if si.Name == "" {
break
}
if si.Name == selId {
item := lib.Item{
Id: si.Name,
Text: si.Name,
}
selectedSceneList.AddItem(item)
scenes_conf := mw.config.Scenes
scenes_conf = append(scenes_conf, &storage.Scene{
ID: cast.ToString(time.Now().Nanosecond()),
Name: si.Name,
Desc: si.Desc,
Num: getMaxNum(),
})
mw.config.Scenes = scenes_conf
if err := mw.storage.StoreConfig(mw.config); err != nil {
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
return
}
}
}
contentRender()
}
// 删除场景事件
deleSceneBtn.OnTapped = func() {
selId := selectedSceneList.SelectedId()
if selId == "" {
ShowTip("请选择一个场景")
return
}
scenes := mw.config.Scenes
for i, item := range scenes {
if item.ID == selId {
scenes = append(scenes[:i], scenes[i+1:]...)
break
}
}
mw.config.Scenes = scenes
selectedSceneLoad()
if err := mw.storage.StoreConfig(mw.config); err != nil {
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
return
}
}
// 场景配置事件
setBtn.OnTapped = func() {
selId := selectedSceneList.SelectedId()
if selId == "" {
ShowTip("请选择一个场景")
return
}
sceneNumEntry := widget.NewEntry()
sceneNumEntry.Text = "0"
sceneLoopEntry := widget.NewEntry()
sceneLoopEntry.Text = "1"
sceneItems := []*widget.FormItem{
widget.NewFormItem("顺序号", sceneNumEntry),
widget.NewFormItem("执行次数", sceneLoopEntry),
}
// 加载
var sceneConf *storage.Scene
for _, item := range mw.config.Scenes {
if item.ID == selId {
sceneConf = item
}
}
if sceneConf != nil {
sceneNumEntry.Text = cast.ToString(sceneConf.Num)
if sceneConf.Loop == 0 {
sceneLoopEntry.Text = "1"
} else {
sceneLoopEntry.Text = cast.ToString(sceneConf.Loop)
}
}
editSceneWin := dialog.NewForm("编辑场景序号", "确定", "取消", sceneItems, func(b bool) {
if !b {
return
}
if cast.ToInt(sceneNumEntry.Text) < 0 {
ShowTip("顺序号必须大于0")
return
}
for _, item := range mw.config.Scenes {
if item.ID == selId {
item.Num = cast.ToInt(sceneNumEntry.Text)
item.Loop = cast.ToInt32(sceneLoopEntry.Text)
}
}
if err := mw.storage.StoreConfig(mw.config); err != nil {
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
return
}
selectedSceneLoad()
}, mw.w)
editSceneWin.Resize(fyne.NewSize(300, 150))
editSceneWin.Show()
}
}
// 导出配置
func (mw *MainWindow) ExportConfigWindow() {
dirEntry := widget.NewEntry()
exportItems := []*widget.FormItem{
widget.NewFormItem("保存目录", container.NewBorder(nil, nil, nil, widget.NewButtonWithIcon("", theme.FolderIcon(), func() {
OpenFolder(dirEntry, mw.w)
}), dirEntry)),
}
exportWin := dialog.NewForm("导出配置", "确定", "取消", exportItems, func(b bool) {
if !b {
return
}
dirpath := dirEntry.Text
logrus.WithField("目录位置", dirpath).Debug("保存目录")
jsonByte, err := json.Marshal(mw.config)
if err != nil {
logrus.Errorln(err)
return
}
if err := ioutil.WriteFile(filepath.Join(dirpath, "config.json"), jsonByte, fs.ModePerm); err != nil {
logrus.Error(err)
return
}
}, mw.w)
exportWin.Resize(fyne.NewSize(500, 80))
exportWin.Show()
}
// 导入配置
func (mw *MainWindow) ImportConfigWindow() {
filepathEntry := widget.NewEntry()
importItems := []*widget.FormItem{
widget.NewFormItem("配置文件", container.NewBorder(nil, nil, nil, widget.NewButtonWithIcon("", theme.FileIcon(), func() {
OpenFile(filepathEntry, mw.w)
}), filepathEntry)),
}
importWin := dialog.NewForm("导入配置", "确定", "取消", importItems, func(b bool) {
if !b {
return
}
filepath := filepathEntry.Text
logrus.WithField("文件路径", filepath).Debug("导入文件")
byte, err := ioutil.ReadFile(filepath)
if err != nil {
logrus.Error(err)
return
}
if err := json.Unmarshal(byte, mw.config); err != nil {
logrus.Error(err)
return
}
if err := mw.storage.StoreConfig(mw.config); err != nil {
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
return
}
}, mw.w)
importWin.Resize(fyne.NewSize(500, 80))
importWin.Show()
}
// 清空数据
func (mw *MainWindow) ClearData() {
empty := &storage.Config{}
mw.config = empty
if err := mw.storage.StoreConfig(empty); err != nil {
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
return
}
mw.startContainer()
ShowTip("数据已清空")
}
// 退出
func (mw *MainWindow) quiteHandle() {
dialog.ShowCustomConfirm("提示", "确定", "取消", widget.NewLabel("确定退出吗"), func(b bool) {
if !b {
return
}
mw.app.Quit()
}, mw.w)
}