173 lines
5.3 KiB
Go
173 lines
5.3 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package preferences
|
|
|
|
/*
|
|
#include <stdlib.h>
|
|
#include "native.h"
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
"unsafe"
|
|
|
|
"git.stormux.org/storm/cthulhu/internal/config"
|
|
)
|
|
|
|
func echoChecks(values *Values) []struct {
|
|
id string
|
|
value *bool
|
|
} {
|
|
return []struct {
|
|
id string
|
|
value *bool
|
|
}{
|
|
{"keyEchoCheckButton", &values.EnableKeyEcho},
|
|
{"enableAlphabeticKeysCheckButton", &values.EnableAlphabeticKeys},
|
|
{"enableNumericKeysCheckButton", &values.EnableNumericKeys},
|
|
{"enablePunctuationKeysCheckButton", &values.EnablePunctuationKeys},
|
|
{"enableSpaceCheckButton", &values.EnableSpace},
|
|
{"enableModifierKeysCheckButton", &values.EnableModifierKeys},
|
|
{"enableFunctionKeysCheckButton", &values.EnableFunctionKeys},
|
|
{"enableActionKeysCheckButton", &values.EnableActionKeys},
|
|
{"enableNavigationKeysCheckButton", &values.EnableNavigationKeys},
|
|
{"enableDiacriticalKeysCheckButton", &values.EnableDiacriticalKeys},
|
|
{"enableEchoByCharacterCheckButton", &values.EnableEchoByCharacter},
|
|
{"enableEchoByWordCheckButton", &values.EnableEchoByWord},
|
|
{"enableEchoBySentenceCheckButton", &values.EnableEchoBySentence},
|
|
{"useCustomEchoVoiceCheckButton", &values.UseCustomEchoVoice},
|
|
{"useCustomEchoSpeechServerCheckButton", &values.UseCustomEchoSpeechServer},
|
|
{"useCustomEchoForKeyCheckButton", &values.UseCustomEchoForKey},
|
|
{"useCustomEchoForCharacterCheckButton", &values.UseCustomEchoForCharacter},
|
|
{"useCustomEchoForWordCheckButton", &values.UseCustomEchoForWord},
|
|
{"useCustomEchoForSentenceCheckButton", &values.UseCustomEchoForSentence},
|
|
}
|
|
}
|
|
|
|
func (session *uiSession) setEchoVoice(values Values) {
|
|
session.echoModules = []string{""}
|
|
for module := range session.catalog {
|
|
if module != "" {
|
|
session.echoModules = append(session.echoModules, module)
|
|
}
|
|
}
|
|
sort.Strings(session.echoModules[1:])
|
|
selected := 0
|
|
if values.EchoSpeechServer != "" {
|
|
selected = -1
|
|
for i, module := range session.echoModules {
|
|
if module == values.EchoSpeechServer {
|
|
selected = i
|
|
}
|
|
}
|
|
if selected < 0 {
|
|
selected = len(session.echoModules)
|
|
session.echoModules = append(session.echoModules, values.EchoSpeechServer)
|
|
}
|
|
}
|
|
labels := append([]string(nil), session.echoModules...)
|
|
labels[0] = "Default"
|
|
comboItems("echoSpeechServers", labels, selected)
|
|
// The toggle state is installed by setValues before the next GTK iteration.
|
|
module := ""
|
|
if values.UseCustomEchoSpeechServer {
|
|
module = values.EchoSpeechServer
|
|
}
|
|
session.populateEchoFamilies(module, values.EchoVoice.Family)
|
|
for _, item := range []struct {
|
|
id string
|
|
value *float64
|
|
fallback float64
|
|
}{
|
|
{"echoRateScale", values.EchoVoice.Rate, voiceFallback(values.Rate, 50)},
|
|
{"echoPitchScale", values.EchoVoice.AveragePitch, voiceFallback(values.Pitch, 5)},
|
|
{"echoVolumeScale", values.EchoVoice.Gain, voiceFallback(values.Volume, 10)},
|
|
} {
|
|
id := C.CString(item.id)
|
|
C.prefs_range_set(id, C.double(voiceFallback(item.value, item.fallback)))
|
|
C.free(unsafe.Pointer(id))
|
|
}
|
|
}
|
|
|
|
func voiceFallback(value *float64, fallback float64) float64 {
|
|
if value != nil {
|
|
return *value
|
|
}
|
|
return fallback
|
|
}
|
|
|
|
func (session *uiSession) populateEchoFamilies(module string, selected *config.VoiceFamily) {
|
|
session.activeEchoModule = module
|
|
session.echoFamilies = []*config.VoiceFamily{nil}
|
|
labels := []string{"Default"}
|
|
index := 0
|
|
for _, voice := range session.default_voices(module) {
|
|
family := &config.VoiceFamily{Name: voice.Name, Lang: voice.Language, Variant: voice.Variant}
|
|
session.echoFamilies = append(session.echoFamilies, family)
|
|
labels = append(labels, voice.Name+" ("+voice.Language+")")
|
|
if selected != nil && selected.Name == voice.Name && strings.EqualFold(strings.TrimSuffix(selected.Lang+"-"+selected.Dialect, "-"), voice.Language) {
|
|
index = len(labels) - 1
|
|
}
|
|
}
|
|
if selected != nil && index == 0 {
|
|
index = len(labels)
|
|
session.echoFamilies = append(session.echoFamilies, selected)
|
|
labels = append(labels, selected.Name+" ("+selected.Lang+")")
|
|
}
|
|
comboItems("echoSpeechFamilies", labels, index)
|
|
}
|
|
|
|
func (session *uiSession) selectedEchoModule() string {
|
|
i := getCombo("echoSpeechServers")
|
|
if i >= 0 && i < len(session.echoModules) {
|
|
return session.echoModules[i]
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (session *uiSession) refreshEchoVoices() {
|
|
module := ""
|
|
if getCheck("useCustomEchoSpeechServerCheckButton") {
|
|
module = session.selectedEchoModule()
|
|
}
|
|
if module != session.activeEchoModule {
|
|
session.populateEchoFamilies(module, nil)
|
|
}
|
|
}
|
|
|
|
func (session *uiSession) getEchoVoice() (config.Voice, string) {
|
|
var voice config.Voice
|
|
for _, item := range []struct {
|
|
id string
|
|
target **float64
|
|
}{
|
|
{"echoRateScale", &voice.Rate}, {"echoPitchScale", &voice.AveragePitch}, {"echoVolumeScale", &voice.Gain},
|
|
} {
|
|
id := C.CString(item.id)
|
|
value := float64(C.prefs_number_value(id))
|
|
C.free(unsafe.Pointer(id))
|
|
*item.target = &value
|
|
}
|
|
i := getCombo("echoSpeechFamilies")
|
|
if i >= 0 && i < len(session.echoFamilies) {
|
|
voice.Family = session.echoFamilies[i]
|
|
}
|
|
return voice, session.selectedEchoModule()
|
|
}
|
|
|
|
func set_echo_checks(values Values) {
|
|
for _, check := range echoChecks(&values) {
|
|
setCheck(check.id, *check.value)
|
|
}
|
|
}
|
|
|
|
func get_echo_checks(values *Values) {
|
|
for _, check := range echoChecks(values) {
|
|
*check.value = getCheck(check.id)
|
|
}
|
|
}
|