Simplify GUI settings and build flags

This commit is contained in:
every_holiday
2026-06-26 09:16:46 +09:00
parent 4d77e67870
commit ae426244e0
22 changed files with 846 additions and 237 deletions

View File

@@ -45,7 +45,8 @@ var runtimeTimePattern = regexp.MustCompile(`^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\
var vrcLogTimePattern = regexp.MustCompile(`^(\d{4}\.\d{2}\.\d{2} \d{2}:\d{2}:\d{2})`)
var vrcJoinPattern = regexp.MustCompile(`OnPlayerJoined\s+(.+?)\s+\(usr_[0-9a-fA-F-]+\)`)
var vrcLeftPattern = regexp.MustCompile(`OnPlayerLeft\s+(.+?)\s+\(usr_[0-9a-fA-F-]+\)`)
var hwndTopMostFlag uintptr = ^uintptr(0) - 1
var hwndTopMostFlag uintptr = ^uintptr(0)
var hwndNotTopMostFlag uintptr = ^uintptr(0) - 1
var hwndNoMove uintptr = 0x0002
var hwndNoSize uintptr = 0x0001
var hwndNoActivate uintptr = 0x0010
@@ -74,13 +75,10 @@ type guiApp struct {
tabJoin uintptr
tabTranslate uintptr
tabSettings uintptr
btnActiveWindow uintptr
btnTopMost uintptr
btnFontDown uintptr
btnFontUp uintptr
activeTab string
activeWindow bool
lastActiveWindow bool
topMost bool
lastTopMost bool
fontSize int
@@ -125,15 +123,12 @@ func runNativeGUI() error {
translateMessage := user32.NewProc("TranslateMessage")
dispatchMessage := user32.NewProc("DispatchMessageW")
postQuitMessage := user32.NewProc("PostQuitMessage")
setForegroundWindow := user32.NewProc("SetForegroundWindow")
bringWindowToTop := user32.NewProc("BringWindowToTop")
setTimer := user32.NewProc("SetTimer")
loadCursor := user32.NewProc("LoadCursorW")
setWindowText := user32.NewProc("SetWindowTextW")
getWindowRect := user32.NewProc("GetWindowRect")
isWindowVisible := user32.NewProc("IsWindowVisible")
isIconic := user32.NewProc("IsIconic")
getForegroundWindow := user32.NewProc("GetForegroundWindow")
getSystemMetrics := user32.NewProc("GetSystemMetrics")
getModuleHandle := kernel32.NewProc("GetModuleHandleW")
loadIcon := user32.NewProc("LoadIconW")
@@ -168,7 +163,6 @@ func runNativeGUI() error {
var app guiApp
guiCfg := loadGUISettings()
app.activeWindow = guiCfg.ActiveWindow
app.topMost = guiCfg.TopMost
if guiCfg.FontSize > 0 {
app.fontSize = guiCfg.FontSize
@@ -187,7 +181,6 @@ func runNativeGUI() error {
joinTitle, _ := syscall.UTF16PtrFromString("Join Log")
translateTitle, _ := syscall.UTF16PtrFromString("Translate")
settingsTitle, _ := syscall.UTF16PtrFromString("Settings")
activeWindowTitle, _ := syscall.UTF16PtrFromString("Active window")
topMostTitle, _ := syscall.UTF16PtrFromString("Top most")
fontDownTitle, _ := syscall.UTF16PtrFromString("A-")
fontUpTitle, _ := syscall.UTF16PtrFromString("A+")
@@ -198,35 +191,28 @@ func runNativeGUI() error {
app.rightHwnd, _, _ = createWindowEx.Call(0, uintptr(unsafe.Pointer(rightClass)), uintptr(unsafe.Pointer(rightTitle)), wsVisible|wsChild|wsClipChildren, 370, 60, 330, 260, hwnd, idLog, hInstance, 0)
settingsPaneTitle, _ := syscall.UTF16PtrFromString("")
app.settingsPaneHwnd, _, _ = createWindowEx.Call(0, uintptr(unsafe.Pointer(rightClass)), uintptr(unsafe.Pointer(settingsPaneTitle)), wsVisible|wsChild|wsClipChildren, 370, 60, 330, 260, hwnd, idLog+1, hInstance, 0)
app.btnActiveWindow, _, _ = createWindowEx.Call(0, uintptr(unsafe.Pointer(buttonClass)), uintptr(unsafe.Pointer(activeWindowTitle)), wsVisible|wsChild, 390, 90, 130, 30, hwnd, 3004, hInstance, 0)
app.btnTopMost, _, _ = createWindowEx.Call(0, uintptr(unsafe.Pointer(buttonClass)), uintptr(unsafe.Pointer(topMostTitle)), wsVisible|wsChild, 390, 130, 120, 30, hwnd, 3005, hInstance, 0)
app.btnFontDown, _, _ = createWindowEx.Call(0, uintptr(unsafe.Pointer(buttonClass)), uintptr(unsafe.Pointer(fontDownTitle)), wsVisible|wsChild, 390, 175, 50, 30, hwnd, 3006, hInstance, 0)
app.btnFontUp, _, _ = createWindowEx.Call(0, uintptr(unsafe.Pointer(buttonClass)), uintptr(unsafe.Pointer(fontUpTitle)), wsVisible|wsChild, 445, 175, 50, 30, hwnd, 3007, hInstance, 0)
app.btnTopMost, _, _ = createWindowEx.Call(0, uintptr(unsafe.Pointer(buttonClass)), uintptr(unsafe.Pointer(topMostTitle)), wsVisible|wsChild, 390, 90, 120, 30, hwnd, 3005, hInstance, 0)
app.btnFontDown, _, _ = createWindowEx.Call(0, uintptr(unsafe.Pointer(buttonClass)), uintptr(unsafe.Pointer(fontDownTitle)), wsVisible|wsChild, 390, 135, 50, 30, hwnd, 3006, hInstance, 0)
app.btnFontUp, _, _ = createWindowEx.Call(0, uintptr(unsafe.Pointer(buttonClass)), uintptr(unsafe.Pointer(fontUpTitle)), wsVisible|wsChild, 445, 135, 50, 30, hwnd, 3007, hInstance, 0)
app.activeTab = "join"
app.activeWindow = true
app.lastActiveWindow = false
setTimer.Call(hwnd, timerRefresh, 2000, 0)
applyFont(&app)
refreshGUI(setWindowText, &app)
applyActiveWindow(hwnd, &app, showWindowProc, setForegroundWindow, bringWindowToTop, setWindowPosProc, getForegroundWindow, getSystemMetrics, getWindowRect, isWindowVisible, isIconic)
applyTopMost(hwnd, &app)
ensureWindowVisible("startup", hwnd, showWindowProc, setWindowPosProc, getWindowRect, isWindowVisible, isIconic, getSystemMetrics)
logWindowState("after-ensure", hwnd, getWindowRect, isWindowVisible, isIconic)
return 0
case wmCommandGUI:
needsFullRefresh := false
switch uint16(wParam & 0xffff) {
case 3001:
app.activeTab = "join"
needsFullRefresh = true
case 3002:
app.activeTab = "translate"
needsFullRefresh = true
case 3003:
app.activeTab = "settings"
case 3004:
if !allowRapidSettingsAction(&app) {
return 0
}
app.activeWindow = !app.activeWindow
saveGUISettings(&app)
applyActiveWindow(hwnd, &app, showWindowProc, setForegroundWindow, bringWindowToTop, setWindowPosProc, getForegroundWindow, getSystemMetrics, getWindowRect, isWindowVisible, isIconic)
case 3005:
if !allowRapidSettingsAction(&app) {
return 0
@@ -263,8 +249,13 @@ func runNativeGUI() error {
saveGUISettings(&app)
}
}
refreshGUI(setWindowText, &app)
refreshSettingsControls(showWindowProc, setWindowPosProc, &app)
if needsFullRefresh {
refreshGUI(setWindowText, &app)
refreshSettingsControls(showWindowProc, setWindowPosProc, &app)
} else {
refreshCommandUI(setWindowText, &app)
refreshSettingsControls(showWindowProc, setWindowPosProc, &app)
}
return 0
case wmTimerGUI:
refreshGUI(setWindowText, &app)
@@ -364,14 +355,6 @@ func refreshGUI(setWindowText *syscall.LazyProc, app *guiApp) {
t, _ := syscall.UTF16PtrFromString(formatGuestPane("Join Log", current))
setWindowText.Call(app.leftHwnd, uintptr(unsafe.Pointer(t)))
}
if app.btnActiveWindow != 0 {
label := "Active window: OFF"
if app.activeWindow {
label = "Active window: ON"
}
t, _ := syscall.UTF16PtrFromString(label)
setWindowText.Call(app.btnActiveWindow, uintptr(unsafe.Pointer(t)))
}
if app.btnTopMost != 0 {
label := "Top most: OFF"
if app.topMost {
@@ -388,7 +371,7 @@ func refreshGUI(setWindowText *syscall.LazyProc, app *guiApp) {
showWindowProc.Call(app.settingsPaneHwnd, swShowControl)
setWindowPosProc.Call(app.settingsPaneHwnd, 0, 370, 60, 330, 260, swpVisibleFlags)
}
for _, hwnd := range []uintptr{app.btnActiveWindow, app.btnTopMost, app.btnFontDown, app.btnFontUp} {
for _, hwnd := range []uintptr{app.btnTopMost, app.btnFontDown, app.btnFontUp} {
if hwnd != 0 {
showWindowProc.Call(hwnd, swShowControl)
}
@@ -397,7 +380,6 @@ func refreshGUI(setWindowText *syscall.LazyProc, app *guiApp) {
}
if app.rightHwnd != 0 {
state := readRuntimeSnapshot()
state["active_window"] = app.activeWindow
state["top_most"] = app.topMost
state["font_size"] = app.fontSize
rightText := formatRightPane(app.activeTab, state, currentWorldLabel(), instanceCount)
@@ -408,13 +390,27 @@ func refreshGUI(setWindowText *syscall.LazyProc, app *guiApp) {
if app.settingsPaneHwnd != 0 {
showWindowProc.Call(app.settingsPaneHwnd, swHideControl)
}
for _, hwnd := range []uintptr{app.btnActiveWindow, app.btnTopMost, app.btnFontDown, app.btnFontUp} {
for _, hwnd := range []uintptr{app.btnTopMost, app.btnFontDown, app.btnFontUp} {
if hwnd != 0 {
showWindowProc.Call(hwnd, swHideControl)
}
}
}
func refreshCommandUI(setWindowText *syscall.LazyProc, app *guiApp) {
if app == nil || setWindowText == nil {
return
}
if app.btnTopMost != 0 {
label := "Top most: OFF"
if app.topMost {
label = "Top most: ON"
}
t, _ := syscall.UTF16PtrFromString(label)
setWindowText.Call(app.btnTopMost, uintptr(unsafe.Pointer(t)))
}
}
func refreshSettingsControls(showWindowProc, setWindowPosProc *syscall.LazyProc, app *guiApp) {
if showWindowProc == nil || setWindowPosProc == nil || app == nil {
return
@@ -424,7 +420,7 @@ func refreshSettingsControls(showWindowProc, setWindowPosProc *syscall.LazyProc,
showWindowProc.Call(app.settingsPaneHwnd, swShowControl)
setWindowPosProc.Call(app.settingsPaneHwnd, 0, 370, 60, 330, 260, swpVisibleFlags)
}
for _, hwnd := range []uintptr{app.btnActiveWindow, app.btnTopMost, app.btnFontDown, app.btnFontUp} {
for _, hwnd := range []uintptr{app.btnTopMost, app.btnFontDown, app.btnFontUp} {
if hwnd != 0 {
showWindowProc.Call(hwnd, swShowControl)
}
@@ -435,7 +431,7 @@ func refreshSettingsControls(showWindowProc, setWindowPosProc *syscall.LazyProc,
if app.settingsPaneHwnd != 0 {
showWindowProc.Call(app.settingsPaneHwnd, swHideControl)
}
for _, hwnd := range []uintptr{app.btnActiveWindow, app.btnTopMost, app.btnFontDown, app.btnFontUp} {
for _, hwnd := range []uintptr{app.btnTopMost, app.btnFontDown, app.btnFontUp} {
if hwnd != 0 {
showWindowProc.Call(hwnd, swHideControl)
}
@@ -443,24 +439,6 @@ func refreshSettingsControls(showWindowProc, setWindowPosProc *syscall.LazyProc,
guiLog("refreshSettingsControls hidden")
}
func applyActiveWindow(hwnd uintptr, app *guiApp, showWindowProc, setForegroundWindow, bringWindowToTop, setWindowPosProc, getForegroundWindow, getSystemMetrics, getWindowRect, isWindowVisible, isIconic *syscall.LazyProc) {
if hwnd == 0 || app.activeWindow == app.lastActiveWindow {
return
}
if app.activeWindow {
showWindowProc.Call(hwnd, swRestore)
setWindowPosProc.Call(hwnd, 0, 0, 0, 0, 0, swpShowFlags)
bringWindowToTop.Call(hwnd)
setForegroundWindow.Call(hwnd)
foreground, _, _ := getForegroundWindow.Call()
guiLog(fmt.Sprintf("applyActiveWindow on foreground=%d target=%d", foreground, hwnd))
ensureWindowVisible("active-window", hwnd, showWindowProc, setWindowPosProc, getWindowRect, isWindowVisible, isIconic, getSystemMetrics)
} else {
guiLog("applyActiveWindow off")
}
app.lastActiveWindow = app.activeWindow
}
func ensureWindowVisible(stage string, hwnd uintptr, showWindowProc, setWindowPosProc, getWindowRect, isWindowVisible, isIconic, getSystemMetrics *syscall.LazyProc) {
if hwnd == 0 || getSystemMetrics == nil {
return
@@ -524,7 +502,7 @@ func applyTopMost(hwnd uintptr, app *guiApp) {
if app.topMost {
setWindowPosProc.Call(hwnd, hwndTopMostFlag, 0, 0, 0, 0, swpFlags)
} else {
setWindowPosProc.Call(hwnd, 0, 0, 0, 0, 0, swpFlags)
setWindowPosProc.Call(hwnd, hwndNotTopMostFlag, 0, 0, 0, 0, swpFlags)
}
app.lastTopMost = app.topMost
}
@@ -814,7 +792,6 @@ func formatGuestPane(title string, items []userState) string {
for _, item := range present {
b.WriteString("・ ")
b.WriteString(item.Name)
b.WriteString(" [present]")
if !item.LastJoin.IsZero() {
b.WriteString(" ")
b.WriteString(item.LastJoin.Format("15:04:05"))
@@ -835,7 +812,6 @@ func formatGuestPane(title string, items []userState) string {
for _, item := range left {
b.WriteString("・ ")
b.WriteString(item.Name)
b.WriteString(" [gray]")
if !item.LastLeave.IsZero() {
b.WriteString(" ")
b.WriteString(timeAgo(item.LastLeave))
@@ -873,7 +849,7 @@ func currentSelfName() string {
func loadGUISettings() config.GUIConfig {
cfg, err := config.Load("")
if err != nil || cfg == nil {
return config.GUIConfig{ActiveWindow: true, FontSize: 18}
return config.GUIConfig{TopMost: false, FontSize: 18}
}
if cfg.GUI.FontSize <= 0 {
cfg.GUI.FontSize = 18
@@ -886,9 +862,8 @@ func saveGUISettings(app *guiApp) {
return
}
guiCfg := config.GUIConfig{
ActiveWindow: app.activeWindow,
TopMost: app.topMost,
FontSize: app.fontSize,
TopMost: app.topMost,
FontSize: app.fontSize,
}
if err := config.SaveGUI("", guiCfg); err != nil {
guiLog("saveGUISettings failed: " + err.Error())
@@ -941,13 +916,7 @@ func formatRightPane(tab string, state map[string]any, worldLabel string, curren
b.WriteString("\r\nWorld: ")
b.WriteString(worldLabel)
case "settings":
b.WriteString("Active window: ")
if stateBool(state, "active_window") {
b.WriteString("ON")
} else {
b.WriteString("OFF")
}
b.WriteString("\r\nTop most: ")
b.WriteString("Top most: ")
if stateBool(state, "top_most") {
b.WriteString("ON")
} else {