1
0
Fork 0
mirror of https://github.com/aclist/dztui.git synced 2025-04-05 12:03:00 +02:00

feat: resizable columns

This commit is contained in:
aclist 2024-03-13 21:24:56 +09:00
parent d0961fddb6
commit b9872fbb74
3 changed files with 146 additions and 28 deletions

View file

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -o pipefail set -o pipefail
version=5.2.0-rc.4 version=5.1.0-rc.4
#CONSTANTS #CONSTANTS
aid=221100 aid=221100
@ -537,10 +537,10 @@ fetch_helpers_by_sum(){
source "$config_file" source "$config_file"
declare -A sums declare -A sums
sums=( sums=(
["ui.py"]="44a88b196ea9d65b429525cf0bad66b6" ["ui.py"]="9b7fddbb8d40818b74c23b0f038ac613"
["query_v2.py"]="1822bd1769ce7d7cb0d686a60f9fa197" ["query_v2.py"]="1822bd1769ce7d7cb0d686a60f9fa197"
["vdf2json.py"]="2f49f6f5d3af919bebaab2e9c220f397" ["vdf2json.py"]="2f49f6f5d3af919bebaab2e9c220f397"
["funcs"]="e4bd26a95060e57582cda046b2302658" ["funcs"]="a03224d2085767d8531cacb2dfb21f03"
) )
local author="aclist" local author="aclist"
local repo="dztui" local repo="dztui"

View file

@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -o pipefail set -o pipefail
version=5.2.0-rc.4 version=5.1.0-rc.4
#CONSTANTS #CONSTANTS
aid=221100 aid=221100
@ -111,6 +111,7 @@ declare -A funcs=(
["list_mods"]="list_mods" ["list_mods"]="list_mods"
["delete"]="delete_local_mod" ["delete"]="delete_local_mod"
["show_server_modlist"]="show_server_modlist" ["show_server_modlist"]="show_server_modlist"
["test_ping"]="test_ping"
["is_in_favs"]="is_in_favs" ["is_in_favs"]="is_in_favs"
["show_log"]="show_log" ["show_log"]="show_log"
["gen_log"]="generate_log" ["gen_log"]="generate_log"
@ -560,13 +561,22 @@ dump_servers(){
filter_servers "$file" "$@" filter_servers "$file" "$@"
} }
logger(){ logger(){
local date="$(date "+%F %T,%3N")" local date="$(date "+%F %T,%3N")"
local tag="$1" local tag="$1"
local string="$2" local string="$2"
local self="${BASH_SOURCE[0]}" local self="${BASH_SOURCE[0]}"
local caller="${FUNCNAME[1]}" local caller="${FUNCNAME[1]}"
local line="${BASH_LINENO[0]}" local line="${BASH_LINENO[0]}"
printf "%s␞%s␞%s::%s()::%s␞%s\n" "$date" "$tag" "$self" "$caller" "$line" "$string" >> "$debug_log" printf "%s␞%s␞%s::%s()::%s␞%s\n" "$date" "$tag" "$self" "$caller" "$line" "$string" >> "$debug_log"
}
test_ping(){
shift
local ip="$1"
local qport="$2"
local res
res=$(ping -c1 -4 -W0.5 $1 | grep time= | awk -F= '{print $4}')
[[ ! $? -eq 0 ]] && res="Unreachable"
printf "%s" "$res"
} }
show_server_modlist(){ show_server_modlist(){
shift shift
@ -1023,6 +1033,7 @@ try_connect(){
if [[ -n $auto_install ]]; then if [[ -n $auto_install ]]; then
logger INFO "Merging modlists" logger INFO "Merging modlists"
diff=$(merge_modlists "$diff") diff=$(merge_modlists "$diff")
diff=$(query_defunct "$diff")
fi fi
if [[ -n $diff ]]; then if [[ -n $diff ]]; then
if [[ $(check_architecture) -eq 1 ]] && [[ $(test_display_mode) == "gm" ]]; then if [[ $(check_architecture) -eq 1 ]] && [[ $(test_display_mode) == "gm" ]]; then
@ -1031,7 +1042,7 @@ try_connect(){
fi fi
case $auto_install in case $auto_install in
"") manual_mod_install "$ip" "$gameport" "$diff" "$sanitized_mods";; "") manual_mod_install "$ip" "$gameport" "$diff" "$sanitized_mods";;
1|2) manual_mod_install "$ip" "$gameport" "$diff" "$sanitized_mods" ;; 1|2) manual_mod_install "$ip" "$gameport" "$diff" "$sanitized_mods" "auto" ;;
esac esac
else else
launch "$ip" "$gameport" "$sanitized_mods" launch "$ip" "$gameport" "$sanitized_mods"
@ -1113,9 +1124,8 @@ force_update(){
fi fi
rm "$versions_file" rm "$versions_file"
local update=$(check_timestamps) local update=$(check_timestamps)
console_dl "$update" && manual_mod_install "null" "null" "$update" "null" "force"
$steam_cmd steam://open/downloads echo "Finished requesting mod updates."
echo "Finished requesting mod updates. Steam may have some mods pending for download."
return 0 return 0
} }
console_dl(){ console_dl(){
@ -1279,6 +1289,7 @@ manual_mod_install(){
local gameport="$2" local gameport="$2"
local diff="$3" local diff="$3"
local sanitized_mods="$4" local sanitized_mods="$4"
local mode="$5"
local ex="$state_path/dzg.watcher" local ex="$state_path/dzg.watcher"
readarray -t stage_mods <<< "$diff" readarray -t stage_mods <<< "$diff"
@ -1289,8 +1300,13 @@ manual_mod_install(){
[[ -f $ex ]] && return 1 [[ -f $ex ]] && return 1
log ${stage_mods[$i]} log ${stage_mods[$i]}
$steam_cmd "steam://url/CommunityFilePage/${stage_mods[$i]}+workshop_download_item 221100 ${stage_mods[$i]}" if [[ $mode == "auto" ]] || [[ $mode == "force" ]]; then
echo "# Opening workshop page for ${stage_mods[$i]}" $steam_cmd "steam://url/CommunityFilePage/${stage_mods[$i]}+workshop_download_item $aid ${stage_mods[$i]}"
echo "# Opening workshop page for ${stage_mods[$i]}"
else
$steam_cmd "steam://url/CommunityFilePage/${stage_mods[$i]}"
echo "# Opening workshop page for ${stage_mods[$i]}. If you see no progress after subscribing, try unsubscribing and resubscribing again until the download commences."
fi
sleep 1s sleep 1s
foreground foreground
@ -1303,7 +1319,11 @@ manual_mod_install(){
done done
foreground foreground
echo "# Steam is downloading ${stage_mods[$i]} (mod $((i+1)) of ${#stage_mods[@]})" if [[ $mode == "auto" ]] || [[ $mode == "force" ]]; then
echo "# Steam is downloading ${stage_mods[$i]} (mod $((i+1)) of ${#stage_mods[@]}). You do not need to manually Subscribe."
else
echo "# Steam is downloading ${stage_mods[$i]} (mod $((i+1)) of ${#stage_mods[@]})"
fi
until [[ -d $workshop_dir/${stage_mods[$i]} ]]; do until [[ -d $workshop_dir/${stage_mods[$i]} ]]; do
[[ -f $ex ]] && return 1 [[ -f $ex ]] && return 1
sleep 0.1s sleep 0.1s
@ -1316,9 +1336,18 @@ manual_mod_install(){
} }
_watcher > >($steamsafe_zenity --pulsate --progress --auto-close --title="DZG Watcher" --width=500 2>/dev/null; rc=$?; [[ $rc -eq 1 ]] && touch $ex) _watcher > >($steamsafe_zenity --pulsate --progress --auto-close --title="DZG Watcher" --width=500 2>/dev/null; rc=$?; [[ $rc -eq 1 ]] && touch $ex)
# compare latest installed mods to modlist if [[ $mode == "force" ]]; then
rm "$versions_file"
check_timestamps
return 0
fi
local diff=$(compare "$sanitized_mods") local diff=$(compare "$sanitized_mods")
if [[ -z $diff ]]; then if [[ -z $diff ]]; then
if [[ $mode == "auto" ]]; then
rm "$versions_file"
check_timestamps
fi
launch "$ip" "$gameport" "$sanitized_mods" launch "$ip" "$gameport" "$sanitized_mods"
else else
printf "User aborted download process, or some mods may have failed to download. Try connecting again to resync." printf "User aborted download process, or some mods may have failed to download. Try connecting again to resync."

View file

@ -1,5 +1,6 @@
import csv import csv
import gi import gi
import json
import locale import locale
import logging import logging
import os import os
@ -16,7 +17,7 @@ locale.setlocale(locale.LC_ALL, '')
gi.require_version("Gtk", "3.0") gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Gdk, GObject, Pango from gi.repository import Gtk, GLib, Gdk, GObject, Pango
# 5.2.0.rc-4 # 5.1.0.rc-4
app_name = "DZGUI" app_name = "DZGUI"
cache = {} cache = {}
@ -47,6 +48,7 @@ state_path = '%s/.local/state/dzgui' %(user_path)
helpers_path = '%s/.local/share/dzgui/helpers' %(user_path) helpers_path = '%s/.local/share/dzgui/helpers' %(user_path)
log_path = '%s/logs' %(state_path) log_path = '%s/logs' %(state_path)
changelog_path = '%s/CHANGELOG.md' %(state_path) changelog_path = '%s/CHANGELOG.md' %(state_path)
geometry_path = '%s/dzg.cols.json' %(state_path)
funcs = '%s/funcs' %(helpers_path) funcs = '%s/funcs' %(helpers_path)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -147,7 +149,7 @@ status_tooltip = {
"Change player name": "Update your in-game name (required by some servers)", "Change player name": "Update your in-game name (required by some servers)",
"Change Steam API key": "Can be used if you revoked an old API key", "Change Steam API key": "Can be used if you revoked an old API key",
"Change Battlemetrics API key": "Can be used if you revoked an old API key", "Change Battlemetrics API key": "Can be used if you revoked an old API key",
"Force update local mods": "Attempts to update any local mods out of synch with remote versions (experimental)", "Force update local mods": "Synchronize the signatures of all local mods with remote versions (experimental)",
"Output system info to log file": "Generates a system log for troubleshooting", "Output system info to log file": "Generates a system log for troubleshooting",
"View changelog": "Opens the DZGUI changelog in a dialog window", "View changelog": "Opens the DZGUI changelog in a dialog window",
"Show debug log": "Read the DZGUI log generated since startup", "Show debug log": "Read the DZGUI log generated since startup",
@ -159,6 +161,10 @@ status_tooltip = {
} }
def format_ping(ping):
ms = " | Ping: %s" %(ping)
return ms
def format_distance(distance): def format_distance(distance):
if distance == "Unknown": if distance == "Unknown":
distance = "| Distance: %s" %(distance) distance = "| Distance: %s" %(distance)
@ -610,11 +616,13 @@ class CalcDist(multiprocessing.Process):
def run(self): def run(self):
if self.addr in cache: if self.addr in cache:
logger.info("Address '%s' already in cache" %(self.addr)) logger.info("Address '%s' already in cache" %(self.addr))
self.result_queue.put([self.addr, cache[self.addr]]) self.result_queue.put([self.addr, cache[self.addr][0], cache[self.addr][1]])
return return
proc = call_out(self.widget, "get_dist", self.ip) proc = call_out(self.widget, "get_dist", self.ip)
proc2 = call_out(self.widget, "test_ping", self.ip)
km = proc.stdout km = proc.stdout
self.result_queue.put([self.addr, km]) ping = proc2.stdout
self.result_queue.put([self.addr, km, ping])
class TreeView(Gtk.TreeView): class TreeView(Gtk.TreeView):
@ -784,9 +792,10 @@ class TreeView(Gtk.TreeView):
if addr is None: if addr is None:
return return
if addr in cache: if addr in cache:
dist = format_distance(cache[addr]) dist = format_distance(cache[addr][0])
ping = format_ping(cache[addr][1])
tooltip = server_tooltip[0] + dist tooltip = server_tooltip[0] + dist + ping
grid.update_statusbar(tooltip) grid.update_statusbar(tooltip)
return return
self.emit("on_distcalc_started") self.emit("on_distcalc_started")
@ -873,6 +882,8 @@ class TreeView(Gtk.TreeView):
right_panel.set_filter_visibility(True) right_panel.set_filter_visibility(True)
dialog.destroy() dialog.destroy()
self.grab_focus() self.grab_focus()
for column in self.get_columns():
column.connect("notify::width", self._on_col_width_changed)
grid = self.get_outer_grid() grid = self.get_outer_grid()
right_panel = grid.right_panel right_panel = grid.right_panel
@ -911,6 +922,33 @@ class TreeView(Gtk.TreeView):
total_mods = result[1] total_mods = result[1]
GLib.idle_add(load) GLib.idle_add(load)
def _on_col_width_changed(self, col, width):
def write_json(title, size):
data = {"cols": { title: size } }
j = json.dumps(data, indent=2)
with open(geometry_path, "w") as outfile:
outfile.write(j)
logger.info("Wrote initial column widths to '%s'" %(geometry_path))
title = col.get_title()
size = col.get_width()
if "Name" in title:
title = "Name"
if os.path.isfile(geometry_path):
with open(geometry_path, "r") as infile:
try:
data = json.load(infile)
data["cols"][title] = size
with open(geometry_path, "w") as outfile:
outfile.write(json.dumps(data, indent=2))
except json.decoder.JSONDecodeError:
logger.critical("JSON decode error in '%s'" %(geometry_path))
write_json(title, size)
else:
write_json(title, size)
def _update_multi_column(self, mode): def _update_multi_column(self, mode):
# Local server lists may have different filter toggles from remote list # Local server lists may have different filter toggles from remote list
# FIXME: tree selection updates twice here. attach signal later # FIXME: tree selection updates twice here. attach signal later
@ -919,14 +957,35 @@ class TreeView(Gtk.TreeView):
for column in self.get_columns(): for column in self.get_columns():
self.remove_column(column) self.remove_column(column)
row_store.clear() row_store.clear()
if os.path.isfile(geometry_path):
with open(geometry_path, "r") as infile:
try:
data = json.load(infile)
valid_json = True
except json.decoder.JSONDecodeError:
logger.critical("JSON decode error in '%s'" %(geometry_path))
valid_json = False
else:
valid_json = False
for i, column_title in enumerate(browser_cols): for i, column_title in enumerate(browser_cols):
renderer = Gtk.CellRendererText() renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(column_title, renderer, text=i) column = Gtk.TreeViewColumn(column_title, renderer, text=i)
column.set_resizable(True)
column.set_sort_column_id(i) column.set_sort_column_id(i)
if ("Name" in column_title):
column.set_fixed_width(800) if valid_json:
if (column_title == "Map"): if "Name" in column_title:
column.set_fixed_width(300) column_title = "Name"
saved_size = data["cols"][column_title]
column.set_fixed_width(saved_size)
else:
if ("Name" in column_title):
column.set_fixed_width(800)
if (column_title == "Map"):
column.set_fixed_width(300)
self.append_column(column) self.append_column(column)
self.update_first_col(mode) self.update_first_col(mode)
@ -1282,6 +1341,32 @@ def KeysDialog(parent, text, mode):
return dialog return dialog
class PingDialog(GenericDialog):
def __init__(self, parent, text, mode, record):
super().__init__(parent, text, mode)
dialogBox = self.get_content_area()
self.set_default_response(Gtk.ResponseType.OK)
self.set_size_request(500, 200)
wait_dialog = GenericDialog(parent, "Checking ping", "WAIT")
wait_dialog.show_all()
thread = threading.Thread(target=self._background, args=(wait_dialog, parent, record))
thread.start()
def _background(self, dialog, parent, record):
def _load():
dialog.destroy()
self.show_all()
ping = data.stdout
self.format_secondary_text("Ping to remote server: %s" %(ping))
res = self.run()
self.destroy()
addr = record.split(':')
ip = addr[0]
qport = addr[2]
data = call_out(parent, "test_ping", ip, qport)
GLib.idle_add(_load)
class ModDialog(GenericDialog): class ModDialog(GenericDialog):
def __init__(self, parent, text, mode, record): def __init__(self, parent, text, mode, record):
super().__init__(parent, text, mode) super().__init__(parent, text, mode)
@ -1453,9 +1538,13 @@ class Grid(Gtk.Grid):
if latest_result is not None: if latest_result is not None:
addr = latest_result[0] addr = latest_result[0]
km = latest_result[1] km = latest_result[1]
cache[addr] = km ping = latest_result[2]
cache[addr] = km, ping
ping = format_ping(ping)
dist = format_distance(km) dist = format_distance(km)
tooltip = server_tooltip[1] = server_tooltip[0] + dist tooltip = server_tooltip[1] = server_tooltip[0] + dist + ping
self.update_statusbar(tooltip) self.update_statusbar(tooltip)
return True return True