git-commit-vandalism/lib/class.tcl
Pat Thoyts c80d7be5e1 git-gui: use themed tk widgets with Tk 8.5
This patch enables the use of themed Tk widgets with Tk 8.5 and above.
These make a significant difference on Windows in making the
application appear native. On Windows and MacOSX ttk defaults to the
native look as much as possible. On X11 the user may select a theme
using the TkTheme XRDB resource class by adding an line to the
.Xresources file. The set of installed theme names is available using
the Tk command 'ttk::themes'. The default on X11 is similar to the current
un-themed style - a kind of thin bordered motif look.

A new git config variable 'gui.usettk' may be set to disable this if
the user prefers the classic Tk look. Using Tk 8.4 will also avoid the
use of themed widgets as these are only available since 8.5.

Some support is included for Tk 8.6 features (themed spinbox and native
font chooser for MacOSX and Windows).

Signed-off-by: Pat Thoyts <patthoyts@users.sourceforge.net>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-01-27 17:13:52 -08:00

194 lines
4.4 KiB
Tcl

# git-gui simple class/object fake-alike
# Copyright (C) 2007 Shawn Pearce
proc class {class body} {
if {[namespace exists $class]} {
error "class $class already declared"
}
namespace eval $class "
variable __nextid 0
variable __sealed 0
variable __field_list {}
variable __field_array
proc cb {name args} {
upvar this this
concat \[list ${class}::\$name \$this\] \$args
}
"
namespace eval $class $body
}
proc field {name args} {
set class [uplevel {namespace current}]
variable ${class}::__sealed
variable ${class}::__field_array
switch [llength $args] {
0 { set new [list $name] }
1 { set new [list $name [lindex $args 0]] }
default { error "wrong # args: field name value?" }
}
if {$__sealed} {
error "class $class is sealed (cannot add new fields)"
}
if {[catch {set old $__field_array($name)}]} {
variable ${class}::__field_list
lappend __field_list $new
set __field_array($name) 1
} else {
error "field $name already declared"
}
}
proc constructor {name params body} {
set class [uplevel {namespace current}]
set ${class}::__sealed 1
variable ${class}::__field_list
set mbodyc {}
append mbodyc {set this } $class
append mbodyc {::__o[incr } $class {::__nextid]::__d} \;
append mbodyc {create_this } $class \;
append mbodyc {set __this [namespace qualifiers $this]} \;
if {$__field_list ne {}} {
append mbodyc {upvar #0}
foreach n $__field_list {
set n [lindex $n 0]
append mbodyc { ${__this}::} $n { } $n
regsub -all @$n\\M $body "\${__this}::$n" body
}
append mbodyc \;
foreach n $__field_list {
if {[llength $n] == 2} {
append mbodyc \
{set } [lindex $n 0] { } [list [lindex $n 1]] \;
}
}
}
append mbodyc $body
namespace eval $class [list proc $name $params $mbodyc]
}
proc method {name params body {deleted {}} {del_body {}}} {
set class [uplevel {namespace current}]
set ${class}::__sealed 1
variable ${class}::__field_list
set params [linsert $params 0 this]
set mbodyc {}
append mbodyc {set __this [namespace qualifiers $this]} \;
switch $deleted {
{} {}
ifdeleted {
append mbodyc {if {![namespace exists $__this]} }
append mbodyc \{ $del_body \; return \} \;
}
default {
error "wrong # args: method name args body (ifdeleted body)?"
}
}
set decl {}
foreach n $__field_list {
set n [lindex $n 0]
if {[regexp -- $n\\M $body]} {
if { [regexp -all -- $n\\M $body] == 1
&& [regexp -all -- \\\$$n\\M $body] == 1
&& [regexp -all -- \\\$$n\\( $body] == 0} {
regsub -all \
\\\$$n\\M $body \
"\[set \${__this}::$n\]" body
} else {
append decl { ${__this}::} $n { } $n
regsub -all @$n\\M $body "\${__this}::$n" body
}
}
}
if {$decl ne {}} {
append mbodyc {upvar #0} $decl \;
}
append mbodyc $body
namespace eval $class [list proc $name $params $mbodyc]
}
proc create_this {class} {
upvar this this
namespace eval [namespace qualifiers $this] [list proc \
[namespace tail $this] \
[list name args] \
"eval \[list ${class}::\$name $this\] \$args" \
]
}
proc delete_this {{t {}}} {
if {$t eq {}} {
upvar this this
set t $this
}
set t [namespace qualifiers $t]
if {[namespace exists $t]} {namespace delete $t}
}
proc make_dialog {t w args} {
upvar $t top $w pfx this this
global use_ttk
uplevel [linsert $args 0 make_toplevel $t $w]
pave_toplevel $pfx
}
proc make_toplevel {t w args} {
upvar $t top $w pfx this this
if {[llength $args] % 2} {
error "make_toplevel topvar winvar {options}"
}
set autodelete 1
foreach {name value} $args {
switch -exact -- $name {
-autodelete {set autodelete $value}
default {error "unsupported option $name"}
}
}
if {$::root_exists || [winfo ismapped .]} {
regsub -all {::} $this {__} w
set top .$w
set pfx $top
toplevel $top
set ::root_exists 1
} else {
set top .
set pfx {}
}
if {$autodelete} {
wm protocol $top WM_DELETE_WINDOW "
[list delete_this $this]
[list destroy $top]
"
}
}
## auto_mkindex support for class/constructor/method
##
auto_mkindex_parser::command class {name body} {
variable parser
variable contextStack
set contextStack [linsert $contextStack 0 $name]
$parser eval [list _%@namespace eval $name] $body
set contextStack [lrange $contextStack 1 end]
}
auto_mkindex_parser::command constructor {name args} {
variable index
variable scriptFile
append index [list set auto_index([fullname $name])] \
[format { [list source [file join $dir %s]]} \
[file split $scriptFile]] "\n"
}