Implemented basic GUI config in Tcl/Tk
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
SRC = src
|
||||
DIST = out
|
||||
CONFIGBINNAME = streamgoose-config
|
||||
TCLDIR = tcldep
|
||||
CROSSPREFIX=x86_64-w64-mingw32
|
||||
CROSSCC = $(CROSSPREFIX)-gcc
|
||||
CROSSCXX = $(CROSSPREFIX)-g++
|
||||
@@ -31,6 +33,30 @@ win64-headless:
|
||||
$(MAKE) $(MFLAGS) win64-headless
|
||||
$(MAKE) dist
|
||||
|
||||
config-linux:
|
||||
cp $(SRC)/conf.tcl $(TCLDIR)/conf.tcl
|
||||
cp $(TCLDIR)/tclkit-linux64 $(TCLDIR)/tclruntime
|
||||
cd $(TCLDIR) && ./tclkit-linux64 ./sdx.kit qwrap conf.tcl -runtime tclruntime
|
||||
mkdir -p $(DIST)
|
||||
mv $(TCLDIR)/conf $(DIST)/$(CONFIGBINNAME)
|
||||
rm $(TCLDIR)/tclruntime
|
||||
|
||||
config-win64:
|
||||
cp $(SRC)/conf.tcl $(TCLDIR)/conf.tcl
|
||||
cp $(TCLDIR)/tclkit-win64.exe $(TCLDIR)/tclruntime.exe
|
||||
cd $(TCLDIR) && ./tclkit-win64.exe ./sdx.kit qwrap conf.tcl -runtime tclruntime.exe
|
||||
mkdir -p $(DIST)
|
||||
mv $(TCLDIR)/conf $(DIST)/$(CONFIGBINNAME).exe
|
||||
rm $(TCLDIR)/tclruntime.exe
|
||||
|
||||
config-win64-cross:
|
||||
cp $(SRC)/conf.tcl $(TCLDIR)/conf.tcl
|
||||
cp $(TCLDIR)/tclkit-win64.exe $(TCLDIR)/tclruntime.exe
|
||||
cd $(TCLDIR) && ./tclkit-linux64 ./sdx.kit qwrap conf.tcl -runtime tclruntime.exe
|
||||
mkdir -p $(DIST)
|
||||
mv $(TCLDIR)/conf $(DIST)/$(CONFIGBINNAME).exe
|
||||
rm $(TCLDIR)/tclruntime.exe
|
||||
|
||||
dist:
|
||||
mkdir -p $(DIST)
|
||||
mv $(SRC)/streamgoose* $(DIST)/
|
||||
@@ -38,6 +64,7 @@ dist:
|
||||
cp -r auth $(DIST)/
|
||||
cp -r external $(DIST)/
|
||||
cp config.json $(DIST)/
|
||||
cp labels.ini $(DIST)/
|
||||
|
||||
clean:
|
||||
rm -rf $(DIST)
|
||||
|
||||
@@ -23,11 +23,11 @@ Nevertheless, the following features are already implemented:
|
||||
- YouTube avatar icon support
|
||||
- Twitch system message support (needs more testing)
|
||||
- [Noto Color Emoji](https://fonts.google.com/noto/specimen/Noto+Color+Emoji) font bundled for universal Unicode emoji support
|
||||
- GUI configuration utility (for now, only 64-bit Linux and Windows versions are supported)
|
||||
|
||||
|
||||
## Planned features
|
||||
|
||||
- Reward redemption message support for Twitch
|
||||
- "Deleted message" support for YouTube
|
||||
- Badge support for Kick
|
||||
- Internal chat ranking system by username
|
||||
@@ -98,12 +98,16 @@ For Linux, you also need to have the `webkit2gtk-4.1` dev package installed.
|
||||
|
||||
Just run `make` and get all the resulting files in the `out` directory.
|
||||
|
||||
To compile the GUI configuration utility (x64 Linux only), run `make config-linux`.
|
||||
|
||||
### Windows x64 (native)
|
||||
|
||||
You need to have Go 1.23.1 and above and a POSIX-compatible "make" in your %PATH%.
|
||||
|
||||
Just run `make win64` and get all the resulting files in the `out` directory.
|
||||
|
||||
To compile the GUI configuration utility (x64 Windows only), run `make config-win64`.
|
||||
|
||||
### Windows x64 (cross-compiling from Linux)
|
||||
|
||||
You need to have Go 1.23.1 and above and a POSIX-compatible "make".
|
||||
@@ -121,6 +125,8 @@ Then rerun the command from step 2.
|
||||
|
||||
**Note**: When testing the cross-compiled build under Wine, you must have Microsoft Edge WebView2 Runtime installed in order for the GUI to work at all. You can [download](https://developer.microsoft.com/en-us/microsoft-edge/webview2) this engine directly from the Microsoft website (select "Evergreen Standalone Installer") and install it into your Wine profile. Be sure to enable at least Windows 7 emulation in winecfg.
|
||||
|
||||
To compile the GUI configuration utility (for x64 Windows and from x64 Linux only), run `make config-win64-cross`.
|
||||
|
||||
### Headless builds
|
||||
|
||||
In case you don't want to build the GUI, you can run `make headless` or `make win64-headless` depending on the platform. In this case, a binary will be built where you'll be required to point any JS-enabled Web browser of your choice to `http://127.0.0.1:60053` to see the chat window. This can be useful when building StreamGoose on more exotic platforms not supported by the `webview_go` library.
|
||||
@@ -135,6 +141,7 @@ Enter the distribution directory and run the `./streamgoose` or `streamgoose.exe
|
||||
### Configuration
|
||||
|
||||
StreamGoose is mostly configured through the `config.json` file distributed in the same directory as the main binary.
|
||||
Alternatively, if you run Linux or Windows on an x86_64 machine, you can compile a GUI configuration utility (see the previous section) that modifies this file. If you run another OS or have another architecture but happen to have a Tcl/Tk distribution installed, you can directly copy the `src/conf.tcl` file into the output directory and run it with the Wish shell instead.
|
||||
|
||||
The following fields in the `config.json` are backend-agnostic:
|
||||
|
||||
@@ -324,6 +331,10 @@ Sure, anything can happen. The problem with adding a new platform support, as al
|
||||
|
||||
Besides the main four, anyway, your best bet would be to create an **external** backend for the platform you're interested in (again, you could use any programming language you want), and then incorporate it into this repo in the `/external` directory. When the backend is mature enough, we can always sit and think about how to convert it into an internal one to be distributed inside the StreamGoose binary.
|
||||
|
||||
### What is the `labels.ini` file in the distribution directory?
|
||||
|
||||
This file is now only used by the GUI configuration program but is planned to be used for the main StreamGoose binary as well, for the user to be able to customize or localize all the labels and internal messages of the application.
|
||||
|
||||
### Why is there a `twitch-cid.txt` file in the `auth/` directory?
|
||||
|
||||
This is the Twitch client ID corresponding to the [Twitch Chat OAuth Password Generator](https://twitchapps.com/tmi/) website. If you generate a Twitch token through it, you'll need this ID for external Twitch API such as badges to work correctly.
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
[general]
|
||||
backends = general tw yt oc kk
|
||||
|
||||
[config.gui.general]
|
||||
windowtitle = StreamGoose config
|
||||
tabtitle = General
|
||||
server_port = Server port
|
||||
server_listen_ip = Server IP
|
||||
debug = Debug
|
||||
useragent = User agent (for unofficial APIs)
|
||||
reset = Reset
|
||||
save = Save
|
||||
exit = Exit
|
||||
credits = Created by Luxferre in 2024 / Public domain
|
||||
savemodal = Save the configuration file?
|
||||
resetmodal = Reset the configuration without saving?
|
||||
|
||||
[config.gui.tw]
|
||||
tabtitle = Twitch
|
||||
tw_backend_enabled = Enable Twitch backend
|
||||
tw_nickname = Your Twitch nickname
|
||||
tw_channel = Twitch channel (starts with #)
|
||||
|
||||
[config.gui.yt]
|
||||
tabtitle = YouTube
|
||||
yt_backend_enabled = Enable YouTube backend
|
||||
yt_channel = YouTube channel (starts with @)
|
||||
yt_api_poll_timeout = API poll timeout (s)
|
||||
|
||||
[config.gui.oc]
|
||||
tabtitle = Owncast
|
||||
oc_backend_enabled = Enable Owncast backend
|
||||
oc_server = Owncast server URL
|
||||
oc_api_poll_timeout = API poll timeout (s)
|
||||
|
||||
[config.gui.kk]
|
||||
tabtitle = Kick
|
||||
kk_backend_enabled = Enable Kick backend
|
||||
kk_channel = Kick channel name
|
||||
kk_api_poll_timeout = API poll timeout (s)
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
#!/usr/bin/env tclsh
|
||||
package require Tk
|
||||
package require json
|
||||
package require json::write
|
||||
package require inifile
|
||||
|
||||
# overall vars
|
||||
set appdir [ file dirname [ file normalize [ info script ] ] ]
|
||||
# check if we're running from a starpack
|
||||
if [string match *app-conf $appdir] {
|
||||
set appdir [ file normalize [ file join $appdir ".." ".." ".." ] ]
|
||||
}
|
||||
puts "Working directory: $appdir"
|
||||
|
||||
set conffile [ file join $appdir "config.json" ]
|
||||
set labelfile [ file join $appdir "labels.ini" ]
|
||||
|
||||
# main configuration read/write procedures
|
||||
|
||||
proc readrawjson {fname} {
|
||||
# read the JSON contents
|
||||
set fp [open $fname r]
|
||||
set rawdata [read $fp]
|
||||
close $fp
|
||||
# parse the JSON contents
|
||||
set confdict [::json::json2dict $rawdata]
|
||||
return $confdict
|
||||
}
|
||||
|
||||
proc readjson {fname} {
|
||||
set confdict [readrawjson $fname]
|
||||
# update the controls according to the configuration
|
||||
dict for {vname vval} $confdict {
|
||||
global conf_$vname
|
||||
set conf_$vname $vval
|
||||
}
|
||||
return $confdict
|
||||
}
|
||||
|
||||
proc dict2json {dictToEncode} {
|
||||
::json::write object {*}[dict map {k v} $dictToEncode {
|
||||
if [string is boolean -strict $v] {
|
||||
set v $v
|
||||
} elseif [string is integer -strict $v] {
|
||||
set v $v
|
||||
} else {
|
||||
set v [::json::write string $v]
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
proc writejson {fname} {
|
||||
set confdict [readrawjson $fname]
|
||||
dict for {vname vval} $confdict {
|
||||
global conf_$vname
|
||||
dict set confdict $vname [set conf_$vname]
|
||||
}
|
||||
set fdata [dict2json $confdict]
|
||||
set fp [open $fname w]
|
||||
puts $fp $fdata
|
||||
close $fp
|
||||
}
|
||||
|
||||
# dialog button helpers
|
||||
|
||||
proc rereadconfig {fname msg} {
|
||||
set answer [tk_messageBox -message $msg -icon question -type yesno]
|
||||
switch -- $answer {
|
||||
yes {readjson $fname}
|
||||
no {}
|
||||
}
|
||||
}
|
||||
|
||||
proc saveconfig {fname msg} {
|
||||
set answer [tk_messageBox -message $msg -icon question -type yesno]
|
||||
switch -- $answer {
|
||||
yes {writejson $fname}
|
||||
no {}
|
||||
}
|
||||
}
|
||||
|
||||
proc exitapp {fname msg} {
|
||||
saveconfig $fname $msg
|
||||
exit
|
||||
}
|
||||
|
||||
# read GUI labels ini file
|
||||
set lbls [::ini::open $labelfile r]
|
||||
set backends [::ini::value $lbls general backends]
|
||||
|
||||
# overall provider tab layout
|
||||
ttk::notebook .prov
|
||||
foreach back $backends {
|
||||
set framename .prov.$back
|
||||
set tabname [::ini::value $lbls config.gui.$back tabtitle]
|
||||
ttk::frame $framename
|
||||
.prov add $framename -text $tabname
|
||||
}
|
||||
|
||||
# General controls (need to be hardcoded)
|
||||
|
||||
set dbglbl [::ini::value $lbls config.gui.general debug]
|
||||
set iplbl [::ini::value $lbls config.gui.general server_listen_ip]
|
||||
set portlbl [::ini::value $lbls config.gui.general server_port]
|
||||
set ualbl [::ini::value $lbls config.gui.general useragent]
|
||||
ttk::checkbutton .prov.general.debugchk -text $dbglbl -variable conf_debug -onvalue true -offvalue false
|
||||
ttk::label .prov.general.serviplbl -text $iplbl
|
||||
ttk::entry .prov.general.serviptxt -textvariable conf_server_listen_ip -width 16
|
||||
ttk::label .prov.general.servportlbl -text $portlbl
|
||||
ttk::entry .prov.general.servporttxt -textvariable conf_server_port -width 5
|
||||
ttk::label .prov.general.ualbl -text $ualbl
|
||||
ttk::entry .prov.general.uatxt -textvariable conf_useragent -width 60
|
||||
|
||||
grid .prov.general.debugchk -column 0 -row 0 -sticky ne -ipadx 5 -ipady 5
|
||||
grid .prov.general.serviplbl -column 1 -row 0 -sticky ne -ipadx 5 -ipady 5
|
||||
grid .prov.general.serviptxt -column 2 -row 0 -sticky ew -padx 5 -pady 5
|
||||
grid .prov.general.servportlbl -column 3 -row 0 -sticky ne -ipadx 5 -ipady 5
|
||||
grid .prov.general.servporttxt -column 4 -row 0 -sticky ew -padx 5 -pady 5
|
||||
grid .prov.general.ualbl -column 0 -row 2 -sticky ne -ipadx 5 -ipady 5
|
||||
grid .prov.general.uatxt -column 1 -row 2 -sticky ew -columnspan 4 -padx 5 -pady 5
|
||||
|
||||
# backend config controls
|
||||
|
||||
foreach back $backends {
|
||||
if {$back ne "general"} {
|
||||
set section config.gui.$back
|
||||
set params [::ini::keys $lbls $section]
|
||||
set rowidx 1
|
||||
foreach key $params {
|
||||
if {$key ne "tabtitle"} {
|
||||
set lbltext [::ini::value $lbls $section $key]
|
||||
set cvarname [string cat conf_ $key]
|
||||
set guiname .prov.$back.$key
|
||||
if {$key eq [string cat $back _backend_enabled]} {
|
||||
set chkname [string cat $guiname chk]
|
||||
ttk::checkbutton $chkname -text $lbltext \
|
||||
-variable $cvarname -onvalue true -offvalue false
|
||||
grid $chkname -column 0 -row 0 -sticky ne -ipadx 5 -ipady 5
|
||||
} else {
|
||||
set ewidth 40
|
||||
set lblname [string cat $guiname lbl]
|
||||
set txtname [string cat $guiname txt]
|
||||
ttk::label $lblname -text $lbltext
|
||||
ttk::entry $txtname -textvariable $cvarname -width $ewidth
|
||||
grid $lblname -column 0 -row $rowidx -sticky ne -ipadx 5 -ipady 5
|
||||
grid $txtname -column 1 -row $rowidx -sticky ew -padx 5 -pady 5
|
||||
}
|
||||
incr rowidx
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# lower button row
|
||||
foreach lname {reset exit save credits savemodal resetmodal} {
|
||||
set vname [string cat $lname lbl]
|
||||
set $vname [::ini::value $lbls config.gui.general $lname]
|
||||
}
|
||||
ttk::frame .btns -padding 4
|
||||
ttk::button .btns.reset -text $resetlbl -command {rereadconfig $conffile $resetmodallbl}
|
||||
ttk::button .btns.exit -text $exitlbl -command {exitapp $conffile $savemodallbl}
|
||||
ttk::button .btns.save -text $savelbl -command {saveconfig $conffile $savemodallbl}
|
||||
ttk::label .btns.lbl -text $creditslbl
|
||||
pack .btns.save -side right -padx 3 -pady 3
|
||||
pack .btns.exit -side right -padx 3 -pady 3
|
||||
pack .btns.reset -side right -padx 3 -pady 3
|
||||
pack .btns.lbl -side left -padx 3 -pady 3
|
||||
|
||||
# place the tabs and buttons
|
||||
grid .prov -column 0 -row 0 -sticky nsew
|
||||
grid .btns -column 0 -row 1 -sticky sew
|
||||
|
||||
# root grid geometry: don't resize the button row
|
||||
grid columnconfigure . 0 -weight 1
|
||||
grid rowconfigure . 0 -weight 1
|
||||
grid rowconfigure . 1 -weight 0
|
||||
|
||||
# iterate over available platform-dependent themes, apply "clam" if none found
|
||||
ttk::style theme use clam
|
||||
catch {ttk::style theme use gtkTtk}
|
||||
catch {ttk::style theme use aqua}
|
||||
catch {ttk::style theme use winnative}
|
||||
catch {ttk::style theme use vista}
|
||||
|
||||
wm title . "StreamGoose config"
|
||||
catch {wm title . [::ini::value $lbls config.gui.general windowtitle]}
|
||||
|
||||
# stop working with the labels file
|
||||
::ini::close $lbls
|
||||
|
||||
# read the initial config
|
||||
readjson $conffile
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
#!/usr/bin/env tclsh
|
||||
package require Tk
|
||||
package require json
|
||||
package require json::write
|
||||
package require inifile
|
||||
|
||||
# overall vars
|
||||
set appdir [ file dirname [ file normalize [ info script ] ] ]
|
||||
# check if we're running from a starpack
|
||||
if [string match *app-conf $appdir] {
|
||||
set appdir [ file normalize [ file join $appdir ".." ".." ".." ] ]
|
||||
}
|
||||
puts "Working directory: $appdir"
|
||||
|
||||
set conffile [ file join $appdir "config.json" ]
|
||||
set labelfile [ file join $appdir "labels.ini" ]
|
||||
|
||||
# main configuration read/write procedures
|
||||
|
||||
proc readrawjson {fname} {
|
||||
# read the JSON contents
|
||||
set fp [open $fname r]
|
||||
set rawdata [read $fp]
|
||||
close $fp
|
||||
# parse the JSON contents
|
||||
set confdict [::json::json2dict $rawdata]
|
||||
return $confdict
|
||||
}
|
||||
|
||||
proc readjson {fname} {
|
||||
set confdict [readrawjson $fname]
|
||||
# update the controls according to the configuration
|
||||
dict for {vname vval} $confdict {
|
||||
global conf_$vname
|
||||
set conf_$vname $vval
|
||||
}
|
||||
return $confdict
|
||||
}
|
||||
|
||||
proc dict2json {dictToEncode} {
|
||||
::json::write object {*}[dict map {k v} $dictToEncode {
|
||||
if [string is boolean -strict $v] {
|
||||
set v $v
|
||||
} elseif [string is integer -strict $v] {
|
||||
set v $v
|
||||
} else {
|
||||
set v [::json::write string $v]
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
proc writejson {fname} {
|
||||
set confdict [readrawjson $fname]
|
||||
dict for {vname vval} $confdict {
|
||||
global conf_$vname
|
||||
dict set confdict $vname [set conf_$vname]
|
||||
}
|
||||
set fdata [dict2json $confdict]
|
||||
set fp [open $fname w]
|
||||
puts $fp $fdata
|
||||
close $fp
|
||||
}
|
||||
|
||||
# dialog button helpers
|
||||
|
||||
proc rereadconfig {fname msg} {
|
||||
set answer [tk_messageBox -message $msg -icon question -type yesno]
|
||||
switch -- $answer {
|
||||
yes {readjson $fname}
|
||||
no {}
|
||||
}
|
||||
}
|
||||
|
||||
proc saveconfig {fname msg} {
|
||||
set answer [tk_messageBox -message $msg -icon question -type yesno]
|
||||
switch -- $answer {
|
||||
yes {writejson $fname}
|
||||
no {}
|
||||
}
|
||||
}
|
||||
|
||||
proc exitapp {fname msg} {
|
||||
saveconfig $fname $msg
|
||||
exit
|
||||
}
|
||||
|
||||
# read GUI labels ini file
|
||||
set lbls [::ini::open $labelfile r]
|
||||
set backends [::ini::value $lbls general backends]
|
||||
|
||||
# overall provider tab layout
|
||||
ttk::notebook .prov
|
||||
foreach back $backends {
|
||||
set framename .prov.$back
|
||||
set tabname [::ini::value $lbls config.gui.$back tabtitle]
|
||||
ttk::frame $framename
|
||||
.prov add $framename -text $tabname
|
||||
}
|
||||
|
||||
# General controls (need to be hardcoded)
|
||||
|
||||
set dbglbl [::ini::value $lbls config.gui.general debug]
|
||||
set iplbl [::ini::value $lbls config.gui.general server_listen_ip]
|
||||
set portlbl [::ini::value $lbls config.gui.general server_port]
|
||||
set ualbl [::ini::value $lbls config.gui.general useragent]
|
||||
ttk::checkbutton .prov.general.debugchk -text $dbglbl -variable conf_debug -onvalue true -offvalue false
|
||||
ttk::label .prov.general.serviplbl -text $iplbl
|
||||
ttk::entry .prov.general.serviptxt -textvariable conf_server_listen_ip -width 16
|
||||
ttk::label .prov.general.servportlbl -text $portlbl
|
||||
ttk::entry .prov.general.servporttxt -textvariable conf_server_port -width 5
|
||||
ttk::label .prov.general.ualbl -text $ualbl
|
||||
ttk::entry .prov.general.uatxt -textvariable conf_useragent -width 60
|
||||
|
||||
grid .prov.general.debugchk -column 0 -row 0 -sticky ne -ipadx 5 -ipady 5
|
||||
grid .prov.general.serviplbl -column 1 -row 0 -sticky ne -ipadx 5 -ipady 5
|
||||
grid .prov.general.serviptxt -column 2 -row 0 -sticky ew -padx 5 -pady 5
|
||||
grid .prov.general.servportlbl -column 3 -row 0 -sticky ne -ipadx 5 -ipady 5
|
||||
grid .prov.general.servporttxt -column 4 -row 0 -sticky ew -padx 5 -pady 5
|
||||
grid .prov.general.ualbl -column 0 -row 2 -sticky ne -ipadx 5 -ipady 5
|
||||
grid .prov.general.uatxt -column 1 -row 2 -sticky ew -columnspan 4 -padx 5 -pady 5
|
||||
|
||||
# backend config controls
|
||||
|
||||
foreach back $backends {
|
||||
if {$back ne "general"} {
|
||||
set section config.gui.$back
|
||||
set params [::ini::keys $lbls $section]
|
||||
set rowidx 1
|
||||
foreach key $params {
|
||||
if {$key ne "tabtitle"} {
|
||||
set lbltext [::ini::value $lbls $section $key]
|
||||
set cvarname [string cat conf_ $key]
|
||||
set guiname .prov.$back.$key
|
||||
if {$key eq [string cat $back _backend_enabled]} {
|
||||
set chkname [string cat $guiname chk]
|
||||
ttk::checkbutton $chkname -text $lbltext \
|
||||
-variable $cvarname -onvalue true -offvalue false
|
||||
grid $chkname -column 0 -row 0 -sticky ne -ipadx 5 -ipady 5
|
||||
} else {
|
||||
set ewidth 40
|
||||
set lblname [string cat $guiname lbl]
|
||||
set txtname [string cat $guiname txt]
|
||||
ttk::label $lblname -text $lbltext
|
||||
ttk::entry $txtname -textvariable $cvarname -width $ewidth
|
||||
grid $lblname -column 0 -row $rowidx -sticky ne -ipadx 5 -ipady 5
|
||||
grid $txtname -column 1 -row $rowidx -sticky ew -padx 5 -pady 5
|
||||
}
|
||||
incr rowidx
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# lower button row
|
||||
foreach lname {reset exit save credits savemodal resetmodal} {
|
||||
set vname [string cat $lname lbl]
|
||||
set $vname [::ini::value $lbls config.gui.general $lname]
|
||||
}
|
||||
ttk::frame .btns -padding 4
|
||||
ttk::button .btns.reset -text $resetlbl -command {rereadconfig $conffile $resetmodallbl}
|
||||
ttk::button .btns.exit -text $exitlbl -command {exitapp $conffile $savemodallbl}
|
||||
ttk::button .btns.save -text $savelbl -command {saveconfig $conffile $savemodallbl}
|
||||
ttk::label .btns.lbl -text $creditslbl
|
||||
pack .btns.save -side right -padx 3 -pady 3
|
||||
pack .btns.exit -side right -padx 3 -pady 3
|
||||
pack .btns.reset -side right -padx 3 -pady 3
|
||||
pack .btns.lbl -side left -padx 3 -pady 3
|
||||
|
||||
# place the tabs and buttons
|
||||
grid .prov -column 0 -row 0 -sticky nsew
|
||||
grid .btns -column 0 -row 1 -sticky sew
|
||||
|
||||
# root grid geometry: don't resize the button row
|
||||
grid columnconfigure . 0 -weight 1
|
||||
grid rowconfigure . 0 -weight 1
|
||||
grid rowconfigure . 1 -weight 0
|
||||
|
||||
# iterate over available platform-dependent themes, apply "clam" if none found
|
||||
ttk::style theme use clam
|
||||
catch {ttk::style theme use gtkTtk}
|
||||
catch {ttk::style theme use aqua}
|
||||
catch {ttk::style theme use winnative}
|
||||
catch {ttk::style theme use vista}
|
||||
|
||||
wm title . "StreamGoose config"
|
||||
catch {wm title . [::ini::value $lbls config.gui.general windowtitle]}
|
||||
|
||||
# stop working with the labels file
|
||||
::ini::close $lbls
|
||||
|
||||
# read the initial config
|
||||
readjson $conffile
|
||||
Binary file not shown.
Executable
BIN
Binary file not shown.
Reference in New Issue
Block a user