diff --git a/NEWS.md b/NEWS.md
index 0d5fa05..a5420b2 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,20 @@
# Cozy Catalog news
+## [0.8] - 2024-02-04
+
+### Added
+
+* Toolbar icons
+
+### Changed
+
+* Modify (Ctrl-M) is now Update (Ctrl-U).
+* File dialogs now use Zenity under X11 if available.
+
+### Removed
+
+* Shorcut keys from toolbar buttons
+
## [0.7] - 2023-01-26
### Added
diff --git a/README.md b/README.md
index c53150c..684ee97 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ Cozy Catalog is a little personal database, mainly for media libraries and the l
The user interface should be fairly obvious.
-As of 26 January 2023, the code has been used in production for a week or two without issues. Please back up your data.
+As of early 2024, the code has been used in production for almost a year with no new issues. Please back up your data anyway.
## System requirements
@@ -22,4 +22,4 @@ Recommended screen resolution: 1024x768.
Cozy Catalog is open source under the MIT license. See source code for details.
-You can usually find me on IRC, in the #ctrl-c channel of tilde.chat, or else as @notimetoplay on the elekk.xyz Mastodon instance. Would love to hear from you.
+You can find native builds on itch.io, and the source code on tildegit. Feedback is welcome in either place.
diff --git a/catalog.tcl b/catalog.tcl
index cffffef..f4052fb 100644
--- a/catalog.tcl
+++ b/catalog.tcl
@@ -1,7 +1,7 @@
#!/usr/bin/env tclsh
#
# Cozy Catalog: a little personal database for media libraries.
-# Copyright 2023 Felix Pleșoianu
+# Copyright 2023, 2024 Felix Pleșoianu
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -27,7 +27,7 @@ package require Tk 8.5
package require try
package require csv
-set about_text "A personal database\nVersion 0.7a (9 Mar 2023)\nMIT License"
+set about_text "A personal database\nVersion 0.8 (4 Feb 2024)\nMIT License"
set credits_text "Made by No Time To Play\nbased on knowledge\nfrom TkDocs.com"
set site_link "https://ctrl-c.club/~nttp/toys/catalog/"
@@ -116,20 +116,19 @@ wm title . "Cozy Catalog"
option add *tearOff 0
. configure -padx 4
-set icon_data "
+image create photo app_icon -data "
R0lGODdhIAAgALEAAAAAAP8AAMzMAP/MzCH5BAEAAAEALAAAAAAgACAAAAKFjI+py+0Po5y0VoCz
xjYAAYYiCFzjGZbSdw4Dqj7s6LqwfGL1gOXOlxGwNCRhL7aYFWEjZGLYE+ZIUedBicqmGFht1mro
en3J8RjsyXWjInQ6tVwq3W95Oy78NddYN4BnlsPD5SKm9TeYVGMoWEi4aIboqLizYSk5qWAJsdnh
+QkaKmpQAAA7
"
-image create photo app_icon -data $icon_data
wm iconphoto . app_icon
if {[tk windowingsystem] eq "x11"} {
ttk::style theme use "clam"
}
-pack [ttk::frame .toolbar] -side top -pady 4
+pack [ttk::frame .tools] -side top -pady 4
ttk::frame .status
ttk::label .status.line -relief sunken -textvar status
@@ -173,35 +172,68 @@ ttk::treeview .tabs.search.results -selectmode browse -height 20 \
.tabs.search.results heading "tags" -text "Tags"
tk_util::pack_scrolled .tabs.search.results
-ttk::button .toolbar.new -text "New" -width 8 -under 0 -command do_new
-ttk::button .toolbar.bOpen -text "Open" -width 8 -under 0 -command do_open
-ttk::button .toolbar.save -text "Save" -width 8 -under 0 -command do_save
+image create photo i_new -data "
+R0lGODdhEAAQALEAAAAAAP8AAP//////ACH5BAEAAAEALAAAAAAQABAAAAItjI+JwK0romDPADkH
+qFeCoT1d1FDJiE0Kim1n6q0wKc8uZNfwfbDxWQpWhoYCADs=
+"
+image create photo i_open -data "
+R0lGODdhEAAQALEAAAAAAP8AAP//////ACH5BAEAAAEALAAAAAAQABAAAAIwjI+pu+CMgJiuKjlz
+Bgnr3W3VyBkYMKSqWp7r2wroyx7STA9l4OTpbiKNIMSikVgAADs=
+"
+image create photo i_props -data "
+R0lGODdhEAAQALEAAAAAAP8AAP//////ACH5BAEAAAEALAAAAAAQABAAAAIzjI9pwO0KhJwSQOEY
+vnTaFGUh122gF1UcMAwis3jtPH8pRtN21b57dfsgbh3hwQdTKJUFADs=
+"
+image create photo i_rev -data "
+R0lGODdhEAAQALEAAAAAAP8AAP//////ACH5BAEAAAEALAAAAAAQABAAAAI2jI9pwK0IhBTsrUkH
+sHGCoT2d1FTJiFEKOm6np5VO0H3gfbs1zuuwDPJ5PDZhilJayJKW5qEAADs=
+"
+image create photo i_save -data "
+R0lGODdhEAAQALEAAAAAAP8AAP//////ACH5BAEAAAEALAAAAAAQABAAAAI+jI95wOLOEhvgVUAR
+plZssAzc44lZsFHMZIKoCcduuq6t8ZGQOPN6ecrpPjjfkFfE1CZKXCrGc6GWVIU1UQAAOw==
+"
+image create photo i_ch -data "
+R0lGODdhEAAQALEAAAAAAP8AAP//////ACH5BAEAAAEALAAAAAAQABAAAAIsjI+pywrfDhgDtlnr
+pRiwzn1cuIBaOZ5O6pXCQ7qvWgLCG1C6bjyQD2xFFAUAOw==
+"
+image create photo i_del -data "
+R0lGODdhEAAQALEAAAAAAP8AAP////+A/yH5BAEAAAEALAAAAAAQABAAAAI4jI+pMT17nHzKiStc
+arhnanBANzbRgI2C+oVoyrbMewGxOac1hudxCcp5Lj0X7RM8TZIbDeSJKAAAOw==
+"
+image create photo i_ins -data "
+R0lGODdhEAAQALEAAAAAAP8AAP//////ACH5BAEAAAEALAAAAAAQABAAAAIvjI+pAe29zJh0rgej
+rENjp3GUxmQJtnUKIAhACSJs+wbcMbv11bqMRyMZYsLioQAAOw==
+"
-ttk::separator .toolbar.sep1 -orient vertical
+ttk::button .tools.new -text "New" -w 7 -im i_new -comp left -comm do_new
+ttk::button .tools.bOpen -text "Open" -w 7 -im i_open -comp left -comm do_open
+ttk::button .tools.save -text "Save" -w 7 -im i_save -comp left -comm do_save
-ttk::button .toolbar.reload -text "Reload" -width 8 -under 0 -command do_reload
-ttk::button .toolbar.stats -text "Stats" -width 8 -under 1 -command show_stats
+ttk::separator .tools.sep1 -orient vertical
-ttk::separator .toolbar.sep2 -orient vertical
+ttk::button .tools.reload -text "Reload" -w 7 -im i_rev -comp left -comm do_rev
+ttk::button .tools.stat -text "Stats" -w 7 -im i_props -comp left -comm do_stat
-ttk::button .toolbar.ins -text "Insert" -width 8 -under 3 -command do_insert
-ttk::button .toolbar.ren -text "Modify" -width 8 -under 0 -command do_modify
-ttk::button .toolbar.del -text "Delete" -width 8 -under 0 -command do_delete
+ttk::separator .tools.sep2 -orient vertical
-pack .toolbar.new -side left
-pack .toolbar.bOpen -side left
-pack .toolbar.save -side left
+ttk::button .tools.ins -text "Insert" -w 7 -im i_ins -comp left -comm do_insert
+ttk::button .tools.ren -text "Update" -w 7 -im i_ch -comp left -comm do_modify
+ttk::button .tools.del -text "Delete" -w 7 -im i_del -comp left -comm do_delete
-pack .toolbar.sep1 -side left -padx 4 -pady 4 -fill y
+pack .tools.new -side left
+pack .tools.bOpen -side left
+pack .tools.save -side left
-pack .toolbar.reload -side left
-pack .toolbar.stats -side left
+pack .tools.sep1 -side left -padx 4 -pady 4 -fill y
-pack .toolbar.sep2 -side left -padx 4 -pady 4 -fill y
+pack .tools.reload -side left
+pack .tools.stat -side left
-pack .toolbar.ins -side left
-pack .toolbar.ren -side left
-pack .toolbar.del -side left
+pack .tools.sep2 -side left -padx 4 -pady 4 -fill y
+
+pack .tools.ins -side left
+pack .tools.ren -side left
+pack .tools.del -side left
. configure -menu [menu .menubar]
@@ -211,15 +243,15 @@ $m add command -label "Open..." -command do_open -under 0 -accel "Ctrl-O"
$m add command -label "Save" -command do_save -under 0 -accel "Ctrl-S"
$m add separator
$m add command -label "Save as..." -command do_save_as -under 5
-$m add command -label "Reload" -command do_reload -under 0 -accel "Ctrl-R"
-$m add command -label "Statistics" -command show_stats -under 1 -accel "Ctrl-T"
+$m add command -label "Reload" -command do_rev -under 0 -accel "Ctrl-R"
+$m add command -label "Statistics" -command do_stat -under 1 -accel "Ctrl-T"
$m add separator
$m add command -label "Quit" -command do_quit -under 0 -accel "Ctrl-Q"
.menubar add cascade -menu .menubar.mFile -label "File" -underline 0
set m [menu .menubar.item]
$m add command -label "Insert" -command do_insert -under 0 -accel "Ctrl-I"
-$m add command -label "Modify" -command do_modify -under 4 -accel "Ctrl-M"
+$m add command -label "Update" -command do_modify -under 4 -accel "Ctrl-U"
$m add command -label "Delete" -command do_delete -under 4 -accel "Ctrl-D"
$m add separator
$m add command -label "Copy details" -under 0 -accel "Ctrl-C" \
@@ -253,15 +285,15 @@ bind .tabs.search.term {search_for $search_term}
bind . do_new
bind . do_open
bind . do_save
-bind . do_reload
-bind . show_stats
+bind . do_rev
+bind . do_stat
bind . do_quit
bind . do_new
bind . do_open
bind . do_save
-bind . do_reload
-bind . show_stats
+bind . do_rev
+bind . do_stat
bind . do_quit
bind . do_insert
@@ -406,10 +438,16 @@ proc do_open {} {
return
}
}
- set choice [tk_getOpenFile -parent . \
- -title "Open existing database" \
- -initialdir [file_dir $file_name] \
- -filetypes $file_types]
+
+ if {[tk windowingsystem] == "x11" && [auto_execok "zenity"] ne ""} {
+ set choice [open_with_zenity $file_name]
+ } else {
+ set choice [tk_getOpenFile -parent . \
+ -title "Open existing database" \
+ -initialdir [file_dir $file_name] \
+ -filetypes $file_types]
+ }
+
if {[string length $choice] == 0} {
set status "Opening canceled."
} elseif {![file isfile $choice]} {
@@ -423,6 +461,25 @@ proc do_open {} {
}
}
+proc open_with_zenity file_name {
+ try {
+ if {$file_name ne ""} {
+ return [exec zenity --file-selection \
+ --title "Open existing database" \
+ --filename $file_name \
+ --file-filter "All files | *" \
+ --file-filter "CSV files | *.csv"]
+ } else {
+ return [exec zenity --file-selection \
+ --title "Open existing database" \
+ --file-filter "All files | *" \
+ --file-filter "CSV files | *.csv"]
+ }
+ } trap CHILDSTATUS {results options} {
+ return ""
+ }
+}
+
proc load_file full_path {
global status modified
@@ -496,10 +553,15 @@ proc do_save {} {
proc do_save_as {} {
global file_name file_types status
- set choice [tk_getSaveFile -parent . \
- -title "Save file as..." \
- -initialdir [file_dir $file_name] \
- -filetypes $file_types]
+ if {[tk windowingsystem] == "x11" && [auto_execok "zenity"] ne ""} {
+ set choice [save_with_zenity $file_name]
+ } else {
+ set choice [tk_getSaveFile -parent . \
+ -title "Save database as..." \
+ -initialdir [file_dir $file_name] \
+ -filetypes $file_types]
+ }
+
if {[string length $choice] == 0} {
set status "Save canceled."
} elseif {[save_file $choice]} {
@@ -507,6 +569,27 @@ proc do_save_as {} {
}
}
+proc save_with_zenity file_name {
+ try {
+ if {$file_name ne ""} {
+ return [exec zenity --file-selection \
+ --title "Save database as..." \
+ --save --confirm-overwrite \
+ --filename $file_name \
+ --file-filter "All files | *" \
+ --file-filter "CSV files | *.csv"]
+ } else {
+ return [exec zenity --file-selection \
+ --title "Save database as..." \
+ --save --confirm-overwrite \
+ --file-filter "All files | *" \
+ --file-filter "CSV files | *.csv"]
+ }
+ } trap CHILDSTATUS {results options} {
+ return ""
+ }
+}
+
proc save_file full_path {
global columns modified status
@@ -532,7 +615,7 @@ proc save_file full_path {
}
}
-proc do_reload {} {
+proc do_rev {} {
global file_name status
if {$file_name eq ""} {
tk_messageBox -parent . \
@@ -554,7 +637,7 @@ proc do_reload {} {
}
}
-proc show_stats {} {
+proc do_stat {} {
set cats [llength [dict keys $db::index]]
set items [llength $db::records]
set average [expr {$items / $cats}]