|
|
|
@ -50,7 +50,12 @@ namespace eval textblock {
|
|
|
|
|
bottomleft {} bottominner {} bottomright {} bottomsolo {}\ |
|
|
|
|
onlyleft {} onlyinner {} onlyright {} onlysolo {}\ |
|
|
|
|
]\ |
|
|
|
|
-framemap_header [list headerleft {} headerinner {} headerright {} headersolo {}]\ |
|
|
|
|
-framemap_header [list\ |
|
|
|
|
topleft {} topinner {} topright {} topsolo {}\ |
|
|
|
|
middleleft {} middleinner {} middleright {} middlesolo {}\ |
|
|
|
|
bottomleft {} bottominner {} bottomright {} bottomsolo {}\ |
|
|
|
|
onlyleft {} onlyinner {} onlyright {} onlysolo {}\ |
|
|
|
|
]\ |
|
|
|
|
-show_edge 1\ |
|
|
|
|
-show_seps 1\ |
|
|
|
|
-show_hseps ""\ |
|
|
|
@ -58,25 +63,64 @@ namespace eval textblock {
|
|
|
|
|
-show_header ""\ |
|
|
|
|
-show_footer ""\ |
|
|
|
|
] |
|
|
|
|
variable table_border_parts |
|
|
|
|
#for 'L' shaped table building pattern |
|
|
|
|
set table_border_parts [dict create\ |
|
|
|
|
topleft [list hlt vll tlc blc]\ |
|
|
|
|
topinner [list hlt tlc]\ |
|
|
|
|
topright [list hlt tlc vlr trc brc]\ |
|
|
|
|
topsolo [list hlt tlc trc blc brc vl]\ |
|
|
|
|
middleleft [list vll blc]\ |
|
|
|
|
midleinner [list]\ |
|
|
|
|
middleright [list vlr brc]\ |
|
|
|
|
middlesolo [list vl blc brc]\ |
|
|
|
|
bottomleft [list vll blc hlb]\ |
|
|
|
|
bottominner [list hlb blc]\ |
|
|
|
|
bottomright [list hlb blc brc vlr]\ |
|
|
|
|
bottomsolo [list hlb blc brc tlc trc vl]\ |
|
|
|
|
onlyleft [list hlt hlb vll tlc blc]\ |
|
|
|
|
onlyinner [list hlt hlb tlc blc]\ |
|
|
|
|
onlyright [list hlt hlb tlc blc brc trc vlr]\ |
|
|
|
|
onlysolo [list hlt hlb vll vlr blc brc trc brc]\ |
|
|
|
|
#for 'L' shaped table building pattern (tables bigger than 4x4 will be mostly 'L' patterns) |
|
|
|
|
#ie only vll,blc,hlb used for cells except top row and right column |
|
|
|
|
#top right cell uses all 'O' shape, other top cells use 'C' shape (hlt,tlc,vll,blc,hlb) |
|
|
|
|
#right cells use 'U' shape (vll,blc,hlb,brc,vlr) |
|
|
|
|
#e.g for 4x4 |
|
|
|
|
# C C C O |
|
|
|
|
# L L L U |
|
|
|
|
# L L L U |
|
|
|
|
#anti-clockwise elements |
|
|
|
|
set C [list hlt tlc vll blc hlb] |
|
|
|
|
set O [list trc hlt tlc vll blc hlb brc vlr] |
|
|
|
|
set L [list vll blc hlb] |
|
|
|
|
set U [list vll blc hlb brc vlr] |
|
|
|
|
set tops [list trc hlt tlc] |
|
|
|
|
set lefts [list tlc vll blc] |
|
|
|
|
set bottoms [list blc hlb brc] |
|
|
|
|
set rights [list trc brc vlr] |
|
|
|
|
|
|
|
|
|
variable table_edge_parts |
|
|
|
|
set table_edge_parts [dict create\ |
|
|
|
|
topleft [struct::set intersect $C [concat $tops $lefts]]\ |
|
|
|
|
topinner [struct::set intersect $C [concat $tops]]\ |
|
|
|
|
topright [struct::set intersect $O [concat $tops $rights]]\ |
|
|
|
|
topsolo [struct::set intersect $O [concat $tops $lefts $rights]]\ |
|
|
|
|
middleleft [struct::set intersect $L $lefts]\ |
|
|
|
|
middleinner [list]\ |
|
|
|
|
middleright [struct::set intersect $U $rights]\ |
|
|
|
|
middlesolo [struct::set intersect $U [concat $lefts $bottoms $rights]]\ |
|
|
|
|
bottomleft [struct::set intersect $L [concat $lefts]]\ |
|
|
|
|
bottominner [list]\ |
|
|
|
|
bottomright [struct::set intersect $U $rights]\ |
|
|
|
|
bottomsolo [struct::set intersect $U [concat $lefts $rights]]\ |
|
|
|
|
onlyleft [struct::set intersect $C [concat $tops $lefts $bottoms]]\ |
|
|
|
|
onlyinner [struct::set intersect $C [concat $tops $bottoms]]\ |
|
|
|
|
onlyright [struct::set intersect $O [concat $tops $bottoms $rights]]\ |
|
|
|
|
onlysolo [struct::set intersect $O [concat $tops $lefts $bottoms $rights]]\ |
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
#for header rows - we don't consider the bottom border as part of the edge - even if table body has no rows |
|
|
|
|
#The usual-case of a single header line is the 'onlyleft,onlyinner,onlyright,onlysolo' set. |
|
|
|
|
variable header_edge_parts |
|
|
|
|
set header_edge_parts [dict create\ |
|
|
|
|
topleft [struct::set intersect $C [concat $tops $lefts]]\ |
|
|
|
|
topinner [struct::set intersect $C [concat $tops]]\ |
|
|
|
|
topright [struct::set intersect $O [concat $tops $rights]]\ |
|
|
|
|
topsolo [struct::set intersect $O [concat $tops $lefts $rights]]\ |
|
|
|
|
middleleft [struct::set intersect $L $lefts]\ |
|
|
|
|
middleinner [list]\ |
|
|
|
|
middleright [struct::set intersect $U $rights]\ |
|
|
|
|
middlesolo [struct::set intersect $U [concat $lefts $bottoms $rights]]\ |
|
|
|
|
bottomleft [struct::set intersect $L [concat $lefts]]\ |
|
|
|
|
bottominner [list]\ |
|
|
|
|
bottomright [struct::set intersect $U $rights]\ |
|
|
|
|
bottomsolo [struct::set intersect $U [concat $lefts $rights]]\ |
|
|
|
|
onlyleft [struct::set intersect $C [concat $tops $lefts]]\ |
|
|
|
|
onlyinner [struct::set intersect $C $tops]\ |
|
|
|
|
onlyright [struct::set intersect $O [concat $tops $rights]]\ |
|
|
|
|
onlysolo [struct::set intersect $O [concat $tops $lefts $rights]]\ |
|
|
|
|
] |
|
|
|
|
variable table_hseps |
|
|
|
|
set table_hseps [dict create\ |
|
|
|
@ -99,10 +143,6 @@ namespace eval textblock {
|
|
|
|
|
] |
|
|
|
|
variable table_vseps |
|
|
|
|
set table_vseps [dict create\ |
|
|
|
|
headerleft [list]\ |
|
|
|
|
headerinner [list vll tlc blc]\ |
|
|
|
|
headerright [list vll tlc blc]\ |
|
|
|
|
headersolo [list]\ |
|
|
|
|
topleft [list]\ |
|
|
|
|
topinner [list vll tlc blc]\ |
|
|
|
|
topright [list vll tlc blc]\ |
|
|
|
@ -122,19 +162,12 @@ namespace eval textblock {
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
variable header_border_parts |
|
|
|
|
set header_border_parts [dict create\ |
|
|
|
|
headerleft [list vll tlc blc hlt]\ |
|
|
|
|
headerinner [list tlc hlt]\ |
|
|
|
|
headerright [list tlc hlt trc vlr brc]\ |
|
|
|
|
headersolo [list tlc vlr blc hlt trc brc]\ |
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
#e.g $t configure -framemap_body [table_border_map " "] |
|
|
|
|
proc table_border_map {char} { |
|
|
|
|
variable table_border_parts |
|
|
|
|
#e.g $t configure -framemap_body [table_edge_map " "] |
|
|
|
|
proc table_edge_map {char} { |
|
|
|
|
variable table_edge_parts |
|
|
|
|
set map [list] |
|
|
|
|
dict for {celltype parts} $table_border_parts { |
|
|
|
|
dict for {celltype parts} $table_edge_parts { |
|
|
|
|
set tmap [list] |
|
|
|
|
foreach p $parts { |
|
|
|
|
dict set tmap $p $char |
|
|
|
@ -155,10 +188,10 @@ namespace eval textblock {
|
|
|
|
|
} |
|
|
|
|
return $map |
|
|
|
|
} |
|
|
|
|
proc header_border_map {char} { |
|
|
|
|
variable header_border_parts |
|
|
|
|
proc header_edge_map {char} { |
|
|
|
|
variable header_edge_parts |
|
|
|
|
set map [list] |
|
|
|
|
dict for {celltype parts} $header_border_parts { |
|
|
|
|
dict for {celltype parts} $header_edge_parts { |
|
|
|
|
set tmap [list] |
|
|
|
|
foreach p $parts { |
|
|
|
|
dict set tmap $p $char |
|
|
|
@ -181,7 +214,9 @@ namespace eval textblock {
|
|
|
|
|
#[enum] CLASS [class interface_caphandler.registry] |
|
|
|
|
#[list_begin definitions] |
|
|
|
|
# [para] [emph METHODS] |
|
|
|
|
variable o_opts_table |
|
|
|
|
variable o_opts_table ;#options as configured by user (with exception of -ansireset) |
|
|
|
|
variable o_opts_table_effective; #options in effect - e.g with defaults merged in. |
|
|
|
|
|
|
|
|
|
variable o_columndefs |
|
|
|
|
variable o_columndata |
|
|
|
|
variable o_rowdefs |
|
|
|
@ -208,6 +243,7 @@ namespace eval textblock {
|
|
|
|
|
} |
|
|
|
|
#set o_opts_table [dict merge $o_opts_table_defaults $args] |
|
|
|
|
set o_opts_table $o_opts_table_defaults |
|
|
|
|
set o_opts_table_effective $o_opts_table_defaults |
|
|
|
|
my configure {*}[dict merge $o_opts_table_defaults $args] |
|
|
|
|
set o_columndefs [dict create] |
|
|
|
|
set o_columndata [dict create] ;#we store data by column even though it is often added row by row |
|
|
|
@ -266,21 +302,92 @@ namespace eval textblock {
|
|
|
|
|
} |
|
|
|
|
return [dict create header $ft_header body $ft_body] |
|
|
|
|
} |
|
|
|
|
method Set_effective_framelimits {} { |
|
|
|
|
upvar ::textblock::class::opts_table_defaults tdefaults |
|
|
|
|
set default_blims [dict get $tdefaults -framelimits_body] |
|
|
|
|
set default_hlims [dict get $tdefaults -framelimits_header] |
|
|
|
|
set eff_blims [dict get $o_opts_table_effective -framelimits_body] |
|
|
|
|
set eff_hlims [dict get $o_opts_table_effective -framelimits_header] |
|
|
|
|
|
|
|
|
|
set requested_blims [dict get $o_opts_table -framelimits_body] |
|
|
|
|
set requested_hlims [dict get $o_opts_table -framelimits_header] |
|
|
|
|
set blims $eff_blims |
|
|
|
|
set hlims $eff_hlims |
|
|
|
|
switch -- $requested_blims { |
|
|
|
|
"default" { |
|
|
|
|
set blims $default_blims |
|
|
|
|
} |
|
|
|
|
default { |
|
|
|
|
#set blims $requested_blims |
|
|
|
|
set blims [list] |
|
|
|
|
foreach lim $requested_blims { |
|
|
|
|
switch -- $lim { |
|
|
|
|
hl { |
|
|
|
|
lappend blims hlt hlb |
|
|
|
|
} |
|
|
|
|
vl { |
|
|
|
|
lappend blims vll vlr |
|
|
|
|
} |
|
|
|
|
default { |
|
|
|
|
lappend blims $lim |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
set blims [lsort -unique $blims] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
dict set o_opts_table_effective -framelimits_body $blims |
|
|
|
|
switch -- $requested_hlims { |
|
|
|
|
"default" { |
|
|
|
|
set hlims $default_hlims |
|
|
|
|
} |
|
|
|
|
default { |
|
|
|
|
#set hlims $requested_hlims |
|
|
|
|
set hlims [list] |
|
|
|
|
foreach lim $requested_hlims { |
|
|
|
|
switch -- $lim { |
|
|
|
|
hl { |
|
|
|
|
lappend hlims hlt hlb |
|
|
|
|
} |
|
|
|
|
vl { |
|
|
|
|
lappend hlims vll vlr |
|
|
|
|
} |
|
|
|
|
default { |
|
|
|
|
lappend hlims $lim |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
set hlims [lsort -unique $hlims] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
dict set o_opts_table_effective -framelimits_header $hlims |
|
|
|
|
return [dict create body $blims header $hlims] |
|
|
|
|
} |
|
|
|
|
method configure args { |
|
|
|
|
if {![llength $args]} { |
|
|
|
|
return $o_opts_table |
|
|
|
|
} |
|
|
|
|
if {[llength $args] == 1 && [lindex $args 0] in [dict keys $o_opts_table_defaults]} { |
|
|
|
|
if {[llength $args] == 1} { |
|
|
|
|
if {[lindex $args 0] in [dict keys $o_opts_table_defaults]} { |
|
|
|
|
#query single option |
|
|
|
|
set k [lindex $args 0] |
|
|
|
|
set val [dict get $o_opts_table $k] |
|
|
|
|
set returndict [dict create option $k value $val ansireset "\x1b\[m"] |
|
|
|
|
set infodict [dict create] |
|
|
|
|
switch -- $k { |
|
|
|
|
-ansibase_header - -ansibase_body - -ansiborder_header - -ansiborder_body - -ansiborder_footer { |
|
|
|
|
dict set infodict debug [ansistring VIEW $val] |
|
|
|
|
} |
|
|
|
|
-framemap_body - -framemap_header - -framelimits_body - -framelimits_header { |
|
|
|
|
dict set returndict effective [dict get $o_opts_table_effective $k] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
dict set returndict info $infodict |
|
|
|
|
return $returndict |
|
|
|
|
#return [dict create option $k value $val ansireset "\x1b\[m" info $infodict] |
|
|
|
|
} else { |
|
|
|
|
error "textblock::table configure - unrecognised option '[lindex $args 0]'. Known values [dict keys $o_opts_table_defaults]" |
|
|
|
|
} |
|
|
|
|
return [dict create option $k value $val ansireset "\x1b\[m" info $infodict] |
|
|
|
|
} |
|
|
|
|
if {[llength $args] %2 != 0} { |
|
|
|
|
error "[namespace current]::table configure - unexpected argument count. Require name value pairs" |
|
|
|
@ -308,9 +415,72 @@ namespace eval textblock {
|
|
|
|
|
set ansival [punk::ansi::codetype::sgr_merge $ansi_codes] |
|
|
|
|
lappend checked_opts $k $ansival |
|
|
|
|
} |
|
|
|
|
-frametype - -frametype_header - -frametype_body { |
|
|
|
|
#frametype will raise an error if v is not a valid custom dict or one of the known predefined types such as light,heavy,double etc |
|
|
|
|
lassign [textblock::frametype $v] _cat category _type ftype |
|
|
|
|
lappend checked_opts $k $v |
|
|
|
|
} |
|
|
|
|
-framemap_body - -framemap_header { |
|
|
|
|
#upvar ::textblock::class::opts_table_defaults tdefaults |
|
|
|
|
#set default_bmap [dict get $tdefaults -framemap_body] |
|
|
|
|
#todo - check keys and map |
|
|
|
|
if {[llength $v] == 1} { |
|
|
|
|
if {$v eq "default"} { |
|
|
|
|
upvar ::textblock::class::opts_table_defaults tdefaults |
|
|
|
|
set default_map [dict get $tdefaults $k] |
|
|
|
|
lappend checked_opts $k $default_map |
|
|
|
|
} else { |
|
|
|
|
error "textblock::table::configure invalid $k value $v. Expected the value 'default' or a dict e.g topleft {hl *}" |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
dict for {subk subv} $v { |
|
|
|
|
switch -- $subk { |
|
|
|
|
topleft - topinner - topright - topsolo - middleleft - middleinner - middleright - middlesolo - bottomleft - bottominner - bottomright - bottomsolo - onlyleft - onlyinner - onlyright - onlysolo {} |
|
|
|
|
default { |
|
|
|
|
error "textblock::table::configure invalid $subk. Known values {topleft topinner topright topsolo middleleft middleinner middleright middlesolo bottomleft bottominner bottomright bottomsolo onlyleft onlyinner onlyright onlysolo}" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
dict for {seg subst} $subv { |
|
|
|
|
switch -- $seg { |
|
|
|
|
hl - hlt - hlb - vl - vll - vlr - trc - tlc - blc - brc {} |
|
|
|
|
default { |
|
|
|
|
error "textblock::table::configure invalid $subk value $seg. Known values {hl hlt hlb vl vll vlr trc tlc blc brc}" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
lappend checked_opts $k $v |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
-framelimits_body - -framelimits_header { |
|
|
|
|
set specific_framelimits [list] |
|
|
|
|
foreach fl $v { |
|
|
|
|
switch -- $fl { |
|
|
|
|
"default" { |
|
|
|
|
lappend specific_framelimits trc hlt tlc vll blc hlb brc vlr |
|
|
|
|
} |
|
|
|
|
hl { |
|
|
|
|
lappend specific_framelimits hlt hlb |
|
|
|
|
} |
|
|
|
|
vl { |
|
|
|
|
lappend specific_framelimits vll vlr |
|
|
|
|
} |
|
|
|
|
hlt - hlb - vll - vlr - trc - tlc - blc - brc { |
|
|
|
|
lappend specific_framelimits $fl |
|
|
|
|
} |
|
|
|
|
default { |
|
|
|
|
error "textblock::table::configure invalid $k '$fl'. Known values {hl hlb hlt vl vll vlr trc tlc blc brc} (or default for all)" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
lappend checked_opts $k $specific_framelimits |
|
|
|
|
} |
|
|
|
|
-ansireset { |
|
|
|
|
if {$v eq "\uFFEF"} { |
|
|
|
|
lappend checked_opts $k "\x1b\[m" ;# [a] |
|
|
|
|
set RST "\x1b\[m" ;#[a] |
|
|
|
|
lappend checked_opts $k $RST |
|
|
|
|
} else { |
|
|
|
|
error "textblock::table::configure -ansireset is read-only. It is present only to prevent unwanted colourised output in configure commands" |
|
|
|
|
} |
|
|
|
@ -320,7 +490,51 @@ namespace eval textblock {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
set o_opts_table [dict merge $o_opts_table $checked_opts] |
|
|
|
|
#all options checked - ok to update o_opts_table and o_opts_table_effective |
|
|
|
|
|
|
|
|
|
#set o_opts_table [dict merge $o_opts_table $checked_opts] |
|
|
|
|
dict for {k v} $args { |
|
|
|
|
switch -- $k { |
|
|
|
|
-framemap_header - -framemap_body { |
|
|
|
|
#framemaps don't require setting every key to update. |
|
|
|
|
#e.g configure -framemaps {topleft <map>} |
|
|
|
|
#needs to merge with existing unspecified keys such as topright middleleft etc. |
|
|
|
|
if {$v eq "default"} { |
|
|
|
|
dict set o_opts_table $k default |
|
|
|
|
} else { |
|
|
|
|
if {[dict get $o_opts_table $k] eq "default"} { |
|
|
|
|
dict set o_opts_table $k $v |
|
|
|
|
} else { |
|
|
|
|
dict set o_opts_table $k [dict merge [dict get $o_opts_table $k] $v] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
default { |
|
|
|
|
dict set o_opts_table $k $v |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#use values from checked_opts for the effective opts |
|
|
|
|
dict for {k v} $checked_opts { |
|
|
|
|
switch -- $k { |
|
|
|
|
-framemap_body - -framemap_header { |
|
|
|
|
set existing [dict get $o_opts_table_effective $k] |
|
|
|
|
set updated $existing |
|
|
|
|
dict for {subk subv} $v { |
|
|
|
|
dict set updated $subk $subv |
|
|
|
|
} |
|
|
|
|
dict set o_opts_table_effective $k $updated |
|
|
|
|
} |
|
|
|
|
-framelimits_body - -framelimits_header { |
|
|
|
|
#my Set_effective_framelimits |
|
|
|
|
dict set o_opts_table_effective $k $v |
|
|
|
|
} |
|
|
|
|
default { |
|
|
|
|
dict set o_opts_table_effective $k $v |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return $o_opts_table |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#integrate with struct::matrix - allows ::m format 2string $table |
|
|
|
@ -671,46 +885,66 @@ namespace eval textblock {
|
|
|
|
|
} |
|
|
|
|
switch -- $opt_posn { |
|
|
|
|
left { |
|
|
|
|
set header_boxlimits {hl tlc blc vll} |
|
|
|
|
set header_boxlimits {hlb hlt tlc blc vll} |
|
|
|
|
set header_joins [list down-$ftype_body] |
|
|
|
|
set boxlimits_position {hlb blc vll} |
|
|
|
|
set boxlimits_headerless {hlb hlt blc vll tlc} |
|
|
|
|
set boxlimits_headerless [concat $boxlimits_position {hlt tlc}] |
|
|
|
|
set joins {down} |
|
|
|
|
} |
|
|
|
|
inner { |
|
|
|
|
set header_boxlimits {hl tlc blc vll} |
|
|
|
|
set header_boxlimits {hlb hlt tlc blc vll} |
|
|
|
|
set header_joins [list left down-$ftype_body] |
|
|
|
|
set boxlimits_position {hlb blc vll} |
|
|
|
|
set boxlimits_headerless {hlb hlt blc vll tlc} |
|
|
|
|
set boxlimits_headerless [concat $boxlimits_position {hlt tlc}] |
|
|
|
|
set joins {down left} |
|
|
|
|
} |
|
|
|
|
right { |
|
|
|
|
set header_boxlimits {hl tlc blc vll vlr trc brc} |
|
|
|
|
set header_boxlimits {hlb hlt tlc blc vll vlr trc brc} |
|
|
|
|
set header_joins [list left down-$ftype_body] |
|
|
|
|
set boxlimits_position {hlb blc vll vlr brc} |
|
|
|
|
set boxlimits_headerless {hlb hlt blc vll vlr brc tlc trc} |
|
|
|
|
set boxlimits_headerless [concat $boxlimits_position {hlt tlc trc}] |
|
|
|
|
set joins {down left} |
|
|
|
|
} |
|
|
|
|
solo { |
|
|
|
|
set header_boxlimits {hl tlc blc vll vlr trc brc} |
|
|
|
|
set header_boxlimits {hlb hlt tlc blc vll vlr trc brc} |
|
|
|
|
set header_joins [list down-$ftype_body] |
|
|
|
|
set boxlimits_position {hlb blc vll vlr brc} |
|
|
|
|
set boxlimits_headerless {hlb hlt blc vll vlr brc tlc trc} |
|
|
|
|
set boxlimits_headerless [concat $boxlimits_position {hlt tlc trc}] |
|
|
|
|
set joins {down} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#use struct::set instead of simple for loop - will be faster at least when critcl available |
|
|
|
|
set boxlimits [struct::set intersect [dict get $o_opts_table -framelimits_body] $boxlimits_position] |
|
|
|
|
set boxlimits [struct::set intersect [dict get $o_opts_table_effective -framelimits_body] $boxlimits_position] |
|
|
|
|
set boxlimits_headerless [struct::set intersect [dict get $o_opts_table_effective -framelimits_body] $boxlimits_headerless] |
|
|
|
|
set header_boxlimits [struct::set intersect [dict get $o_opts_table_effective -framelimits_header] $header_boxlimits] |
|
|
|
|
|
|
|
|
|
#upvar ::textblock::class::opts_table_defaults tdefaults |
|
|
|
|
#set default_bmap [dict get $tdefaults -framemap_body] |
|
|
|
|
#set default_hmap [dict get $tdefaults -framemap_header] |
|
|
|
|
#set fmap $default_bmap |
|
|
|
|
#set hmap $default_hmap |
|
|
|
|
#dict for {k v} $fmap { |
|
|
|
|
# if {[dict exists $o_opts_table -framemap_body $k]} { |
|
|
|
|
# dict set fmap $k [dict merge $v [dict get $o_opts_table -framemap_body $k]] |
|
|
|
|
# } |
|
|
|
|
#} |
|
|
|
|
#dict for {k v} $hmap { |
|
|
|
|
# if {[dict exists $o_opts_table -framemap_header $k]} { |
|
|
|
|
# dict set hmap $k [dict merge $v [dict get $o_opts_table -framemap_header $k]] |
|
|
|
|
# } |
|
|
|
|
#} |
|
|
|
|
set fmap [dict get $o_opts_table_effective -framemap_body] |
|
|
|
|
set hmap [dict get $o_opts_table_effective -framemap_header] |
|
|
|
|
|
|
|
|
|
upvar ::textblock::class::opts_table_defaults tdefaults |
|
|
|
|
set defaultmap [dict get $tdefaults -framemap_body] |
|
|
|
|
set default_hmap [dict get $tdefaults -framemap_header] |
|
|
|
|
if {![dict get $o_opts_table -show_edge]} { |
|
|
|
|
set fmap [dict merge $defaultmap [textblock::class::table_border_map ""]] |
|
|
|
|
set hmap [dict merge $default_hmap [textblock::class::header_border_map ""]] |
|
|
|
|
} else { |
|
|
|
|
set fmap [dict merge $defaultmap [dict get $o_opts_table -framemap_body]] |
|
|
|
|
set hmap [dict merge $default_hmap [dict get $o_opts_table -framemap_header]] |
|
|
|
|
set body_edgemap [textblock::class::table_edge_map ""] |
|
|
|
|
dict for {k v} $fmap { |
|
|
|
|
dict set fmap $k [dict merge $v [dict get $body_edgemap $k]] |
|
|
|
|
} |
|
|
|
|
set header_edgemap [textblock::class::header_edge_map ""] |
|
|
|
|
dict for {k v} $hmap { |
|
|
|
|
dict set hmap $k [dict merge $v [dict get $header_edgemap $k]] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
set sep_elements_horizontal $::textblock::class::table_hseps |
|
|
|
|
set sep_elements_vertical $::textblock::class::table_vseps |
|
|
|
@ -719,14 +953,17 @@ namespace eval textblock {
|
|
|
|
|
set botmap [dict get $fmap bottom$opt_posn] |
|
|
|
|
set midmap [dict get $fmap middle$opt_posn] |
|
|
|
|
set onlymap [dict get $fmap only$opt_posn] |
|
|
|
|
set hdrmap [dict get $hmap header$opt_posn] |
|
|
|
|
|
|
|
|
|
set hdrmap [dict get $hmap only${opt_posn}] |
|
|
|
|
|
|
|
|
|
set topseps_h [dict get $sep_elements_horizontal top$opt_posn] |
|
|
|
|
set topseps_v [dict get $sep_elements_vertical top$opt_posn] |
|
|
|
|
set midseps_h [dict get $sep_elements_horizontal middle$opt_posn] |
|
|
|
|
set midseps_v [dict get $sep_elements_vertical middle$opt_posn] |
|
|
|
|
set botseps_v [dict get $sep_elements_vertical bottom$opt_posn] |
|
|
|
|
set onlyseps_v [dict get $sep_elements_vertical only$opt_posn] |
|
|
|
|
|
|
|
|
|
set headerseps_v [dict get $sep_elements_vertical header$opt_posn] |
|
|
|
|
set headerseps_v [dict get $sep_elements_vertical top$opt_posn] |
|
|
|
|
|
|
|
|
|
lassign [my Get_seps] _h show_seps_h _v show_seps_v |
|
|
|
|
|
|
|
|
@ -758,7 +995,7 @@ namespace eval textblock {
|
|
|
|
|
if {!$show_seps_v} { |
|
|
|
|
set hlims [struct::set difference $header_boxlimits $headerseps_v] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#todo - multiline header cells + multiple header lines (will be more useful when colspans implemented) |
|
|
|
|
set header_frame [textblock::frame -width [expr {$colwidth+2}] -type [dict get $ftypes header]\ |
|
|
|
|
-ansibase $ansibase_header -ansiborder $ansiborder_final\ |
|
|
|
|
-boxlimits $hlims -boxmap $hdrmap -joins $header_joins $hval\ |
|
|
|
@ -776,6 +1013,8 @@ namespace eval textblock {
|
|
|
|
|
set blims_top $boxlimits |
|
|
|
|
set blims_bot $boxlimits |
|
|
|
|
set blims_top_headerless $boxlimits_headerless |
|
|
|
|
set blims_only $boxlimits |
|
|
|
|
set blims_only_headerless $boxlimits_headerless |
|
|
|
|
if {!$show_seps_h} { |
|
|
|
|
set blims_mid [struct::set difference $blims_mid $midseps_h] |
|
|
|
|
set blims_top [struct::set difference $blims_top $topseps_h] |
|
|
|
@ -786,6 +1025,8 @@ namespace eval textblock {
|
|
|
|
|
set blims_top [struct::set difference $blims_top $topseps_v] |
|
|
|
|
set blims_top_headerless [struct::set difference $blims_top_headerless $topseps_v] |
|
|
|
|
set blims_bot [struct::set difference $blims_bot $botseps_v] |
|
|
|
|
set blims_only [struct::set difference $blims_only $onlyseps_v] |
|
|
|
|
set blims_only_headerless [struct::set difference $blims_only_headerless $onlyseps_v] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
set colidx [lindex [dict keys $o_columndefs] $index_expression] ;#convert possible end-1,2+2 etc expression to >= 0 integer in dict range |
|
|
|
@ -823,9 +1064,9 @@ namespace eval textblock {
|
|
|
|
|
set joins [lremove $joins [lsearch $joins down*]] |
|
|
|
|
set bmap $onlymap |
|
|
|
|
if {$do_show_header} { |
|
|
|
|
set blims $boxlimits |
|
|
|
|
set blims $blims_only |
|
|
|
|
} else { |
|
|
|
|
set blims $boxlimits_headerless |
|
|
|
|
set blims $blims_only_headerless |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
set bmap $topmap |
|
|
|
@ -859,9 +1100,9 @@ namespace eval textblock {
|
|
|
|
|
#note that if show_edge is 0 - then for this empty line - we will not see any vertical bars |
|
|
|
|
#This is because the frame with no data is made entirely of corner elements |
|
|
|
|
if {$do_show_header} { |
|
|
|
|
append output [textblock::frame -width [expr {$colwidth + 2}] -type [dict get $ftypes body] -boxlimits $boxlimits -boxmap $onlymap -joins $joins]\n |
|
|
|
|
append output [textblock::frame -width [expr {$colwidth + 2}] -type [dict get $ftypes body] -boxlimits $blims_only -boxmap $onlymap -joins $joins]\n |
|
|
|
|
} else { |
|
|
|
|
append output [textblock::frame -width [expr {$colwidth + 2}] -type [dict get $ftypes body] -boxlimits $boxlimits_headerless -boxmap $onlymap -joins $joins] \n |
|
|
|
|
append output [textblock::frame -width [expr {$colwidth + 2}] -type [dict get $ftypes body] -boxlimits $blims_only_headerless -boxmap $onlymap -joins $joins] \n |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return [string trimright $output \n] |
|
|
|
@ -881,6 +1122,7 @@ namespace eval textblock {
|
|
|
|
|
#assert cidx is integer >=0 |
|
|
|
|
set cdef [dict get $o_columndefs $cidx] |
|
|
|
|
set t [dict get $cdef -header] ;#may be empty string |
|
|
|
|
set t_maxdataheight 1 |
|
|
|
|
set items [dict get $o_columndata $cidx] |
|
|
|
|
|
|
|
|
|
set ansibase_body [dict get $o_opts_table -ansibase_body] |
|
|
|
@ -1625,8 +1867,45 @@ namespace eval textblock {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
variable frametypes |
|
|
|
|
set frametypes [list light heavy arc double block block1 ascii altg] |
|
|
|
|
#class::table needs to be able to determine valid frametypes |
|
|
|
|
proc frametypes {} { |
|
|
|
|
variable frametypes |
|
|
|
|
return $frametypes |
|
|
|
|
} |
|
|
|
|
proc frametype {f} { |
|
|
|
|
variable frametypes |
|
|
|
|
set default_custom [dict create hl " " vl " " tlc " " trc " " blc " " brc " "] |
|
|
|
|
set custom_keys [list hl hlt hlb vl vll vlr tlc trc blc brc] |
|
|
|
|
if {$f ni $frametypes} { |
|
|
|
|
set is_custom_dict_ok 1 |
|
|
|
|
if {[llength $f] %2 == 0} { |
|
|
|
|
#custom dict may leave out keys - but cannot have unknown keys |
|
|
|
|
dict for {k v} $f { |
|
|
|
|
switch -- $k { |
|
|
|
|
hl - hlt - hlb - vl - vll - vlr - tlc - trc - blc - brc {} |
|
|
|
|
default { |
|
|
|
|
#k not in custom_keys |
|
|
|
|
set is_custom_dict_ok 0 |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
set is_custom_dict_ok 0 |
|
|
|
|
} |
|
|
|
|
if {!$is_custom_dict_ok} { |
|
|
|
|
error "frame option -type must be one of known types: $frametypes or a dictionary with any of keys hl,hlt,hlb,vl,vll,vlr,tlc,trc,blc,brc" |
|
|
|
|
} |
|
|
|
|
set custom_frame [dict merge $default_custom $f] |
|
|
|
|
return [dict create category custom type $custom_frame] |
|
|
|
|
} else { |
|
|
|
|
return [dict create category predefined type $f] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
proc frame {args} { |
|
|
|
|
|
|
|
|
|
variable frametypes |
|
|
|
|
set expect_optval 0 |
|
|
|
|
set argposn 0 |
|
|
|
|
set pmax [expr {[llength $args]-1}] |
|
|
|
@ -1690,34 +1969,20 @@ namespace eval textblock {
|
|
|
|
|
set opt_boxlimits [dict get $opts -boxlimits] |
|
|
|
|
set opt_joins [dict get $opts -joins] |
|
|
|
|
set opt_boxmap [dict get $opts -boxmap] |
|
|
|
|
set known_types [list light heavy arc double block block1 ascii altg] |
|
|
|
|
set default_custom [dict create hl " " vl " " tlc " " trc " " blc " " brc " "] |
|
|
|
|
set custom_keys [list hl hlt hlb vl vll vlr tlc trc blc brc] |
|
|
|
|
if {$opt_type ni $known_types} { |
|
|
|
|
set is_custom_dict_ok 1 |
|
|
|
|
if {[llength $opt_type] %2 == 0} { |
|
|
|
|
#custom dict may leave out keys - but cannot have unknown keys |
|
|
|
|
dict for {k v} $opt_type { |
|
|
|
|
switch -- $k { |
|
|
|
|
hl - hlt - hlb - vl - vll - vlr - tlc - trc - blc - brc {} |
|
|
|
|
default { |
|
|
|
|
#k not in custom_keys |
|
|
|
|
set is_custom_dict_ok 0 |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
set is_custom_dict_ok 0 |
|
|
|
|
} |
|
|
|
|
if {!$is_custom_dict_ok} { |
|
|
|
|
error "frame option -type must be one of known types: $known_types or a dictionary with any of keys hl,hlt,hlb,vl,vll,vlr,tlc,trc,blc,brc" |
|
|
|
|
} |
|
|
|
|
set custom_frame [dict merge $default_custom $opt_type] |
|
|
|
|
set frame_type custom |
|
|
|
|
|
|
|
|
|
set known_frametypes $frametypes ;# light, heavey etc as defined in textblock::frametypes variable |
|
|
|
|
set default_custom [dict create hl " " vl " " tlc " " trc " " blc " " brc " "] |
|
|
|
|
|
|
|
|
|
lassign [textblock::frametype $opt_type] _cat category _type ftype |
|
|
|
|
if {$category eq "custom"} { |
|
|
|
|
set custom_frame $ftype |
|
|
|
|
set frameset "custom" |
|
|
|
|
} else { |
|
|
|
|
set frame_type $opt_type |
|
|
|
|
#category = predefined |
|
|
|
|
set frameset $ftype ;# light,heavy etc |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
set is_boxlimits_ok 1 |
|
|
|
|
set exact_boxlimits [list] |
|
|
|
|
foreach v $opt_boxlimits { |
|
|
|
@ -1877,7 +2142,7 @@ namespace eval textblock {
|
|
|
|
|
#the double glyphs in box drawing can do a limited set of joins to light lines - but not enough for seamless table layouts. |
|
|
|
|
#the arc set can't even join to itself e.g with curved equivalents of T-like shapes |
|
|
|
|
#I guess |
|
|
|
|
switch -- $frame_type { |
|
|
|
|
switch -- $frameset { |
|
|
|
|
"altg" { |
|
|
|
|
#old style ansi escape sequences with alternate graphics page G0 |
|
|
|
|
set hl [cd::hl] |
|
|
|
@ -2050,7 +2315,7 @@ namespace eval textblock {
|
|
|
|
|
set brc \u2527 ;#boxd_dhlul down heavy and left up light (rtj) |
|
|
|
|
} |
|
|
|
|
light { |
|
|
|
|
set blc [punk::char::charshort boxd_lvr] ;#light vertical and right (ltj) |
|
|
|
|
set blc \u251c ;#[punk::char::charshort boxd_lvr] light vertical and right (ltj) |
|
|
|
|
set brc [punk::char::charshort boxd_lvl] ;#light vertical and left (rtj) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -2088,9 +2353,56 @@ namespace eval textblock {
|
|
|
|
|
} |
|
|
|
|
down_left { |
|
|
|
|
#5 |
|
|
|
|
set blc [punk::char::charshort boxd_lvhz] ;#light vertical and horizontal (fwj) |
|
|
|
|
set tlc [punk::char::charshort boxd_ldhz] ;#T shape (ttj) |
|
|
|
|
set brc [punk::char::charshort boxd_lvl] ;#light vertical and left (rtj) |
|
|
|
|
switch -- $targetdown-$targetleft { |
|
|
|
|
other-light { |
|
|
|
|
set blc \u2534 ;#(btj) |
|
|
|
|
set tlc \u252c ;#(ttj) |
|
|
|
|
#brc - default corner |
|
|
|
|
} |
|
|
|
|
other-other { |
|
|
|
|
#default corners |
|
|
|
|
} |
|
|
|
|
other-heavy { |
|
|
|
|
set blc \u2535 ;# heavy left (btj) |
|
|
|
|
set tlc \u252d ;#heavy left (ttj) |
|
|
|
|
#brc default corner |
|
|
|
|
} |
|
|
|
|
heavy-light { |
|
|
|
|
set blc \u2541 ;# heavy down (fwj) |
|
|
|
|
set tlc \u252c ;# light (ttj) |
|
|
|
|
set brc \u2527 ;# heavy down (rtj) |
|
|
|
|
} |
|
|
|
|
heavy-other { |
|
|
|
|
set blc \u251f ;#heavy down (ltj) |
|
|
|
|
#tlc - default corner |
|
|
|
|
set brc \u2527 ;#heavy down (rtj) |
|
|
|
|
} |
|
|
|
|
heavy-heavy { |
|
|
|
|
set blc \u2545 ;#heavy down and left (fwj) |
|
|
|
|
set tlc \u252d ;#heavy left (ttj) |
|
|
|
|
set brc \u2527 ;#heavy down (rtj) |
|
|
|
|
} |
|
|
|
|
light-light { |
|
|
|
|
set blc \u253c ;# [punk::char::charshort boxd_lvhz] ;#light vertical and horizontal (fwj) |
|
|
|
|
set tlc \u252c ;# boxd_ldhz (ttj) |
|
|
|
|
set brc \u2524 ;# boxd_lvl light vertical and left(rtj) |
|
|
|
|
} |
|
|
|
|
light-other { |
|
|
|
|
set blc \u251c ;# (ltj) |
|
|
|
|
#tlc - default corner |
|
|
|
|
set brc \u2524 ;# boxd_lvl (rtj) |
|
|
|
|
} |
|
|
|
|
light-heavy { |
|
|
|
|
set blc \u253d ;# heavy left (fwj) |
|
|
|
|
set tlc \u252d ;# heavy left (ttj) |
|
|
|
|
set brc \u2524 ;# light (rtj) |
|
|
|
|
} |
|
|
|
|
default { |
|
|
|
|
set blc \u253c ;# [punk::char::charshort boxd_lvhz] ;#light vertical and horizontal (fwj) |
|
|
|
|
set tlc \u252c ;# [punk::char::charshort boxd_ldhz] ;#T shape (ttj) |
|
|
|
|
set brc \u2524 ;# [punk::char::charshort boxd_lvl] ;#light vertical and left (rtj) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
down_right { |
|
|
|
|
#6 |
|
|
|
@ -2727,7 +3039,7 @@ namespace eval textblock {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
switch -- $frame_type { |
|
|
|
|
switch -- $frameset { |
|
|
|
|
custom { |
|
|
|
|
|
|
|
|
|
set vll_width [punk::ansi::printing_length $vll] |
|
|
|
@ -2859,7 +3171,7 @@ namespace eval textblock {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#boxlimits used for partial borders in table generation |
|
|
|
|
set all_exact_boxlimits [list vll vlr hlt hlb tlc blc trc blc] |
|
|
|
|
set all_exact_boxlimits [list vll vlr hlt hlb tlc blc trc brc] |
|
|
|
|
set unspecified_limits [struct::set difference $all_exact_boxlimits $exact_boxlimits] |
|
|
|
|
foreach lim $unspecified_limits { |
|
|
|
|
switch -- $lim { |
|
|
|
|