Browse Source

textblock frame/table fixes

master
Julian Noble 7 months ago
parent
commit
af178f0f21
  1. 530
      src/bootsupport/modules/textblock-0.1.1.tm
  2. 530
      src/modules/textblock-999999.0a1.0.tm

530
src/bootsupport/modules/textblock-0.1.1.tm

@ -50,7 +50,12 @@ namespace eval textblock {
bottomleft {} bottominner {} bottomright {} bottomsolo {}\ bottomleft {} bottominner {} bottomright {} bottomsolo {}\
onlyleft {} onlyinner {} onlyright {} onlysolo {}\ 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_edge 1\
-show_seps 1\ -show_seps 1\
-show_hseps ""\ -show_hseps ""\
@ -58,25 +63,64 @@ namespace eval textblock {
-show_header ""\ -show_header ""\
-show_footer ""\ -show_footer ""\
] ]
variable table_border_parts #for 'L' shaped table building pattern (tables bigger than 4x4 will be mostly 'L' patterns)
#for 'L' shaped table building pattern #ie only vll,blc,hlb used for cells except top row and right column
set table_border_parts [dict create\ #top right cell uses all 'O' shape, other top cells use 'C' shape (hlt,tlc,vll,blc,hlb)
topleft [list hlt vll tlc blc]\ #right cells use 'U' shape (vll,blc,hlb,brc,vlr)
topinner [list hlt tlc]\ #e.g for 4x4
topright [list hlt tlc vlr trc brc]\ # C C C O
topsolo [list hlt tlc trc blc brc vl]\ # L L L U
middleleft [list vll blc]\ # L L L U
midleinner [list]\ #anti-clockwise elements
middleright [list vlr brc]\ set C [list hlt tlc vll blc hlb]
middlesolo [list vl blc brc]\ set O [list trc hlt tlc vll blc hlb brc vlr]
bottomleft [list vll blc hlb]\ set L [list vll blc hlb]
bottominner [list hlb blc]\ set U [list vll blc hlb brc vlr]
bottomright [list hlb blc brc vlr]\ set tops [list trc hlt tlc]
bottomsolo [list hlb blc brc tlc trc vl]\ set lefts [list tlc vll blc]
onlyleft [list hlt hlb vll tlc blc]\ set bottoms [list blc hlb brc]
onlyinner [list hlt hlb tlc blc]\ set rights [list trc brc vlr]
onlyright [list hlt hlb tlc blc brc trc vlr]\
onlysolo [list hlt hlb vll vlr blc brc trc brc]\ 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 variable table_hseps
set table_hseps [dict create\ set table_hseps [dict create\
@ -99,10 +143,6 @@ namespace eval textblock {
] ]
variable table_vseps variable table_vseps
set table_vseps [dict create\ set table_vseps [dict create\
headerleft [list]\
headerinner [list vll tlc blc]\
headerright [list vll tlc blc]\
headersolo [list]\
topleft [list]\ topleft [list]\
topinner [list vll tlc blc]\ topinner [list vll tlc blc]\
topright [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 " "] #e.g $t configure -framemap_body [table_edge_map " "]
proc table_border_map {char} { proc table_edge_map {char} {
variable table_border_parts variable table_edge_parts
set map [list] set map [list]
dict for {celltype parts} $table_border_parts { dict for {celltype parts} $table_edge_parts {
set tmap [list] set tmap [list]
foreach p $parts { foreach p $parts {
dict set tmap $p $char dict set tmap $p $char
@ -155,10 +188,10 @@ namespace eval textblock {
} }
return $map return $map
} }
proc header_border_map {char} { proc header_edge_map {char} {
variable header_border_parts variable header_edge_parts
set map [list] set map [list]
dict for {celltype parts} $header_border_parts { dict for {celltype parts} $header_edge_parts {
set tmap [list] set tmap [list]
foreach p $parts { foreach p $parts {
dict set tmap $p $char dict set tmap $p $char
@ -181,7 +214,9 @@ namespace eval textblock {
#[enum] CLASS [class interface_caphandler.registry] #[enum] CLASS [class interface_caphandler.registry]
#[list_begin definitions] #[list_begin definitions]
# [para] [emph METHODS] # [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_columndefs
variable o_columndata variable o_columndata
variable o_rowdefs variable o_rowdefs
@ -207,7 +242,8 @@ namespace eval textblock {
} }
} }
#set o_opts_table [dict merge $o_opts_table_defaults $args] #set o_opts_table [dict merge $o_opts_table_defaults $args]
set o_opts_table $o_opts_table_defaults 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] my configure {*}[dict merge $o_opts_table_defaults $args]
set o_columndefs [dict create] set o_columndefs [dict create]
set o_columndata [dict create] ;#we store data by column even though it is often added row by row 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] 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 { method configure args {
if {![llength $args]} { if {![llength $args]} {
return $o_opts_table return $o_opts_table
} }
if {[llength $args] == 1 && [lindex $args 0] in [dict keys $o_opts_table_defaults]} { if {[llength $args] == 1} {
#query single option if {[lindex $args 0] in [dict keys $o_opts_table_defaults]} {
set k [lindex $args 0] #query single option
set val [dict get $o_opts_table $k] set k [lindex $args 0]
set infodict [dict create] set val [dict get $o_opts_table $k]
switch -- $k { set returndict [dict create option $k value $val ansireset "\x1b\[m"]
-ansibase_header - -ansibase_body - -ansiborder_header - -ansiborder_body - -ansiborder_footer { set infodict [dict create]
dict set infodict debug [ansistring VIEW $val] 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} { if {[llength $args] %2 != 0} {
error "[namespace current]::table configure - unexpected argument count. Require name value pairs" 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] set ansival [punk::ansi::codetype::sgr_merge $ansi_codes]
lappend checked_opts $k $ansival 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 { -ansireset {
if {$v eq "\uFFEF"} { if {$v eq "\uFFEF"} {
lappend checked_opts $k "\x1b\[m" ;# [a] set RST "\x1b\[m" ;#[a]
lappend checked_opts $k $RST
} else { } else {
error "textblock::table::configure -ansireset is read-only. It is present only to prevent unwanted colourised output in configure commands" 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 #integrate with struct::matrix - allows ::m format 2string $table
@ -671,46 +885,66 @@ namespace eval textblock {
} }
switch -- $opt_posn { switch -- $opt_posn {
left { left {
set header_boxlimits {hl tlc blc vll} set header_boxlimits {hlb hlt tlc blc vll}
set header_joins [list down-$ftype_body] set header_joins [list down-$ftype_body]
set boxlimits_position {hlb blc vll} 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} set joins {down}
} }
inner { 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 header_joins [list left down-$ftype_body]
set boxlimits_position {hlb blc vll} 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} set joins {down left}
} }
right { 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 header_joins [list left down-$ftype_body]
set boxlimits_position {hlb blc vll vlr brc} 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} set joins {down left}
} }
solo { 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 header_joins [list down-$ftype_body]
set boxlimits_position {hlb blc vll vlr brc} 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} set joins {down}
} }
} }
#use struct::set instead of simple for loop - will be faster at least when critcl available #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]} { if {![dict get $o_opts_table -show_edge]} {
set fmap [dict merge $defaultmap [textblock::class::table_border_map ""]] set body_edgemap [textblock::class::table_edge_map ""]
set hmap [dict merge $default_hmap [textblock::class::header_border_map ""]] dict for {k v} $fmap {
} else { dict set fmap $k [dict merge $v [dict get $body_edgemap $k]]
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 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_horizontal $::textblock::class::table_hseps
set sep_elements_vertical $::textblock::class::table_vseps set sep_elements_vertical $::textblock::class::table_vseps
@ -719,14 +953,17 @@ namespace eval textblock {
set botmap [dict get $fmap bottom$opt_posn] set botmap [dict get $fmap bottom$opt_posn]
set midmap [dict get $fmap middle$opt_posn] set midmap [dict get $fmap middle$opt_posn]
set onlymap [dict get $fmap only$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_h [dict get $sep_elements_horizontal top$opt_posn]
set topseps_v [dict get $sep_elements_vertical 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_h [dict get $sep_elements_horizontal middle$opt_posn]
set midseps_v [dict get $sep_elements_vertical 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 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 lassign [my Get_seps] _h show_seps_h _v show_seps_v
@ -758,7 +995,7 @@ namespace eval textblock {
if {!$show_seps_v} { if {!$show_seps_v} {
set hlims [struct::set difference $header_boxlimits $headerseps_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]\ set header_frame [textblock::frame -width [expr {$colwidth+2}] -type [dict get $ftypes header]\
-ansibase $ansibase_header -ansiborder $ansiborder_final\ -ansibase $ansibase_header -ansiborder $ansiborder_final\
-boxlimits $hlims -boxmap $hdrmap -joins $header_joins $hval\ -boxlimits $hlims -boxmap $hdrmap -joins $header_joins $hval\
@ -776,6 +1013,8 @@ namespace eval textblock {
set blims_top $boxlimits set blims_top $boxlimits
set blims_bot $boxlimits set blims_bot $boxlimits
set blims_top_headerless $boxlimits_headerless set blims_top_headerless $boxlimits_headerless
set blims_only $boxlimits
set blims_only_headerless $boxlimits_headerless
if {!$show_seps_h} { if {!$show_seps_h} {
set blims_mid [struct::set difference $blims_mid $midseps_h] set blims_mid [struct::set difference $blims_mid $midseps_h]
set blims_top [struct::set difference $blims_top $topseps_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 [struct::set difference $blims_top $topseps_v]
set blims_top_headerless [struct::set difference $blims_top_headerless $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_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 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 joins [lremove $joins [lsearch $joins down*]]
set bmap $onlymap set bmap $onlymap
if {$do_show_header} { if {$do_show_header} {
set blims $boxlimits set blims $blims_only
} else { } else {
set blims $boxlimits_headerless set blims $blims_only_headerless
} }
} else { } else {
set bmap $topmap 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 #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 #This is because the frame with no data is made entirely of corner elements
if {$do_show_header} { 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 { } 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] return [string trimright $output \n]
@ -881,6 +1122,7 @@ namespace eval textblock {
#assert cidx is integer >=0 #assert cidx is integer >=0
set cdef [dict get $o_columndefs $cidx] set cdef [dict get $o_columndefs $cidx]
set t [dict get $cdef -header] ;#may be empty string set t [dict get $cdef -header] ;#may be empty string
set t_maxdataheight 1
set items [dict get $o_columndata $cidx] set items [dict get $o_columndata $cidx]
set ansibase_body [dict get $o_opts_table -ansibase_body] 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} { proc frame {args} {
variable frametypes
set expect_optval 0 set expect_optval 0
set argposn 0 set argposn 0
set pmax [expr {[llength $args]-1}] set pmax [expr {[llength $args]-1}]
@ -1690,34 +1969,20 @@ namespace eval textblock {
set opt_boxlimits [dict get $opts -boxlimits] set opt_boxlimits [dict get $opts -boxlimits]
set opt_joins [dict get $opts -joins] set opt_joins [dict get $opts -joins]
set opt_boxmap [dict get $opts -boxmap] 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] 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 set known_frametypes $frametypes ;# light, heavey etc as defined in textblock::frametypes variable
if {[llength $opt_type] %2 == 0} { set default_custom [dict create hl " " vl " " tlc " " trc " " blc " " brc " "]
#custom dict may leave out keys - but cannot have unknown keys
dict for {k v} $opt_type { lassign [textblock::frametype $opt_type] _cat category _type ftype
switch -- $k { if {$category eq "custom"} {
hl - hlt - hlb - vl - vll - vlr - tlc - trc - blc - brc {} set custom_frame $ftype
default { set frameset "custom"
#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
} else { } else {
set frame_type $opt_type #category = predefined
set frameset $ftype ;# light,heavy etc
} }
set is_boxlimits_ok 1 set is_boxlimits_ok 1
set exact_boxlimits [list] set exact_boxlimits [list]
foreach v $opt_boxlimits { 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 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 #the arc set can't even join to itself e.g with curved equivalents of T-like shapes
#I guess #I guess
switch -- $frame_type { switch -- $frameset {
"altg" { "altg" {
#old style ansi escape sequences with alternate graphics page G0 #old style ansi escape sequences with alternate graphics page G0
set hl [cd::hl] set hl [cd::hl]
@ -2050,7 +2315,7 @@ namespace eval textblock {
set brc \u2527 ;#boxd_dhlul down heavy and left up light (rtj) set brc \u2527 ;#boxd_dhlul down heavy and left up light (rtj)
} }
light { 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) set brc [punk::char::charshort boxd_lvl] ;#light vertical and left (rtj)
} }
} }
@ -2088,9 +2353,56 @@ namespace eval textblock {
} }
down_left { down_left {
#5 #5
set blc [punk::char::charshort boxd_lvhz] ;#light vertical and horizontal (fwj) switch -- $targetdown-$targetleft {
set tlc [punk::char::charshort boxd_ldhz] ;#T shape (ttj) other-light {
set brc [punk::char::charshort boxd_lvl] ;#light vertical and left (rtj) 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 { down_right {
#6 #6
@ -2727,7 +3039,7 @@ namespace eval textblock {
} }
} }
switch -- $frame_type { switch -- $frameset {
custom { custom {
set vll_width [punk::ansi::printing_length $vll] set vll_width [punk::ansi::printing_length $vll]
@ -2859,7 +3171,7 @@ namespace eval textblock {
} }
#boxlimits used for partial borders in table generation #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] set unspecified_limits [struct::set difference $all_exact_boxlimits $exact_boxlimits]
foreach lim $unspecified_limits { foreach lim $unspecified_limits {
switch -- $lim { switch -- $lim {

530
src/modules/textblock-999999.0a1.0.tm

@ -50,7 +50,12 @@ namespace eval textblock {
bottomleft {} bottominner {} bottomright {} bottomsolo {}\ bottomleft {} bottominner {} bottomright {} bottomsolo {}\
onlyleft {} onlyinner {} onlyright {} onlysolo {}\ 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_edge 1\
-show_seps 1\ -show_seps 1\
-show_hseps ""\ -show_hseps ""\
@ -58,25 +63,64 @@ namespace eval textblock {
-show_header ""\ -show_header ""\
-show_footer ""\ -show_footer ""\
] ]
variable table_border_parts #for 'L' shaped table building pattern (tables bigger than 4x4 will be mostly 'L' patterns)
#for 'L' shaped table building pattern #ie only vll,blc,hlb used for cells except top row and right column
set table_border_parts [dict create\ #top right cell uses all 'O' shape, other top cells use 'C' shape (hlt,tlc,vll,blc,hlb)
topleft [list hlt vll tlc blc]\ #right cells use 'U' shape (vll,blc,hlb,brc,vlr)
topinner [list hlt tlc]\ #e.g for 4x4
topright [list hlt tlc vlr trc brc]\ # C C C O
topsolo [list hlt tlc trc blc brc vl]\ # L L L U
middleleft [list vll blc]\ # L L L U
midleinner [list]\ #anti-clockwise elements
middleright [list vlr brc]\ set C [list hlt tlc vll blc hlb]
middlesolo [list vl blc brc]\ set O [list trc hlt tlc vll blc hlb brc vlr]
bottomleft [list vll blc hlb]\ set L [list vll blc hlb]
bottominner [list hlb blc]\ set U [list vll blc hlb brc vlr]
bottomright [list hlb blc brc vlr]\ set tops [list trc hlt tlc]
bottomsolo [list hlb blc brc tlc trc vl]\ set lefts [list tlc vll blc]
onlyleft [list hlt hlb vll tlc blc]\ set bottoms [list blc hlb brc]
onlyinner [list hlt hlb tlc blc]\ set rights [list trc brc vlr]
onlyright [list hlt hlb tlc blc brc trc vlr]\
onlysolo [list hlt hlb vll vlr blc brc trc brc]\ 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 variable table_hseps
set table_hseps [dict create\ set table_hseps [dict create\
@ -99,10 +143,6 @@ namespace eval textblock {
] ]
variable table_vseps variable table_vseps
set table_vseps [dict create\ set table_vseps [dict create\
headerleft [list]\
headerinner [list vll tlc blc]\
headerright [list vll tlc blc]\
headersolo [list]\
topleft [list]\ topleft [list]\
topinner [list vll tlc blc]\ topinner [list vll tlc blc]\
topright [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 " "] #e.g $t configure -framemap_body [table_edge_map " "]
proc table_border_map {char} { proc table_edge_map {char} {
variable table_border_parts variable table_edge_parts
set map [list] set map [list]
dict for {celltype parts} $table_border_parts { dict for {celltype parts} $table_edge_parts {
set tmap [list] set tmap [list]
foreach p $parts { foreach p $parts {
dict set tmap $p $char dict set tmap $p $char
@ -155,10 +188,10 @@ namespace eval textblock {
} }
return $map return $map
} }
proc header_border_map {char} { proc header_edge_map {char} {
variable header_border_parts variable header_edge_parts
set map [list] set map [list]
dict for {celltype parts} $header_border_parts { dict for {celltype parts} $header_edge_parts {
set tmap [list] set tmap [list]
foreach p $parts { foreach p $parts {
dict set tmap $p $char dict set tmap $p $char
@ -181,7 +214,9 @@ namespace eval textblock {
#[enum] CLASS [class interface_caphandler.registry] #[enum] CLASS [class interface_caphandler.registry]
#[list_begin definitions] #[list_begin definitions]
# [para] [emph METHODS] # [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_columndefs
variable o_columndata variable o_columndata
variable o_rowdefs variable o_rowdefs
@ -207,7 +242,8 @@ namespace eval textblock {
} }
} }
#set o_opts_table [dict merge $o_opts_table_defaults $args] #set o_opts_table [dict merge $o_opts_table_defaults $args]
set o_opts_table $o_opts_table_defaults 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] my configure {*}[dict merge $o_opts_table_defaults $args]
set o_columndefs [dict create] set o_columndefs [dict create]
set o_columndata [dict create] ;#we store data by column even though it is often added row by row 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] 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 { method configure args {
if {![llength $args]} { if {![llength $args]} {
return $o_opts_table return $o_opts_table
} }
if {[llength $args] == 1 && [lindex $args 0] in [dict keys $o_opts_table_defaults]} { if {[llength $args] == 1} {
#query single option if {[lindex $args 0] in [dict keys $o_opts_table_defaults]} {
set k [lindex $args 0] #query single option
set val [dict get $o_opts_table $k] set k [lindex $args 0]
set infodict [dict create] set val [dict get $o_opts_table $k]
switch -- $k { set returndict [dict create option $k value $val ansireset "\x1b\[m"]
-ansibase_header - -ansibase_body - -ansiborder_header - -ansiborder_body - -ansiborder_footer { set infodict [dict create]
dict set infodict debug [ansistring VIEW $val] 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} { if {[llength $args] %2 != 0} {
error "[namespace current]::table configure - unexpected argument count. Require name value pairs" 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] set ansival [punk::ansi::codetype::sgr_merge $ansi_codes]
lappend checked_opts $k $ansival 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 { -ansireset {
if {$v eq "\uFFEF"} { if {$v eq "\uFFEF"} {
lappend checked_opts $k "\x1b\[m" ;# [a] set RST "\x1b\[m" ;#[a]
lappend checked_opts $k $RST
} else { } else {
error "textblock::table::configure -ansireset is read-only. It is present only to prevent unwanted colourised output in configure commands" 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 #integrate with struct::matrix - allows ::m format 2string $table
@ -671,46 +885,66 @@ namespace eval textblock {
} }
switch -- $opt_posn { switch -- $opt_posn {
left { left {
set header_boxlimits {hl tlc blc vll} set header_boxlimits {hlb hlt tlc blc vll}
set header_joins [list down-$ftype_body] set header_joins [list down-$ftype_body]
set boxlimits_position {hlb blc vll} 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} set joins {down}
} }
inner { 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 header_joins [list left down-$ftype_body]
set boxlimits_position {hlb blc vll} 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} set joins {down left}
} }
right { 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 header_joins [list left down-$ftype_body]
set boxlimits_position {hlb blc vll vlr brc} 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} set joins {down left}
} }
solo { 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 header_joins [list down-$ftype_body]
set boxlimits_position {hlb blc vll vlr brc} 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} set joins {down}
} }
} }
#use struct::set instead of simple for loop - will be faster at least when critcl available #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]} { if {![dict get $o_opts_table -show_edge]} {
set fmap [dict merge $defaultmap [textblock::class::table_border_map ""]] set body_edgemap [textblock::class::table_edge_map ""]
set hmap [dict merge $default_hmap [textblock::class::header_border_map ""]] dict for {k v} $fmap {
} else { dict set fmap $k [dict merge $v [dict get $body_edgemap $k]]
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 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_horizontal $::textblock::class::table_hseps
set sep_elements_vertical $::textblock::class::table_vseps set sep_elements_vertical $::textblock::class::table_vseps
@ -719,14 +953,17 @@ namespace eval textblock {
set botmap [dict get $fmap bottom$opt_posn] set botmap [dict get $fmap bottom$opt_posn]
set midmap [dict get $fmap middle$opt_posn] set midmap [dict get $fmap middle$opt_posn]
set onlymap [dict get $fmap only$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_h [dict get $sep_elements_horizontal top$opt_posn]
set topseps_v [dict get $sep_elements_vertical 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_h [dict get $sep_elements_horizontal middle$opt_posn]
set midseps_v [dict get $sep_elements_vertical 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 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 lassign [my Get_seps] _h show_seps_h _v show_seps_v
@ -758,7 +995,7 @@ namespace eval textblock {
if {!$show_seps_v} { if {!$show_seps_v} {
set hlims [struct::set difference $header_boxlimits $headerseps_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]\ set header_frame [textblock::frame -width [expr {$colwidth+2}] -type [dict get $ftypes header]\
-ansibase $ansibase_header -ansiborder $ansiborder_final\ -ansibase $ansibase_header -ansiborder $ansiborder_final\
-boxlimits $hlims -boxmap $hdrmap -joins $header_joins $hval\ -boxlimits $hlims -boxmap $hdrmap -joins $header_joins $hval\
@ -776,6 +1013,8 @@ namespace eval textblock {
set blims_top $boxlimits set blims_top $boxlimits
set blims_bot $boxlimits set blims_bot $boxlimits
set blims_top_headerless $boxlimits_headerless set blims_top_headerless $boxlimits_headerless
set blims_only $boxlimits
set blims_only_headerless $boxlimits_headerless
if {!$show_seps_h} { if {!$show_seps_h} {
set blims_mid [struct::set difference $blims_mid $midseps_h] set blims_mid [struct::set difference $blims_mid $midseps_h]
set blims_top [struct::set difference $blims_top $topseps_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 [struct::set difference $blims_top $topseps_v]
set blims_top_headerless [struct::set difference $blims_top_headerless $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_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 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 joins [lremove $joins [lsearch $joins down*]]
set bmap $onlymap set bmap $onlymap
if {$do_show_header} { if {$do_show_header} {
set blims $boxlimits set blims $blims_only
} else { } else {
set blims $boxlimits_headerless set blims $blims_only_headerless
} }
} else { } else {
set bmap $topmap 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 #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 #This is because the frame with no data is made entirely of corner elements
if {$do_show_header} { 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 { } 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] return [string trimright $output \n]
@ -881,6 +1122,7 @@ namespace eval textblock {
#assert cidx is integer >=0 #assert cidx is integer >=0
set cdef [dict get $o_columndefs $cidx] set cdef [dict get $o_columndefs $cidx]
set t [dict get $cdef -header] ;#may be empty string set t [dict get $cdef -header] ;#may be empty string
set t_maxdataheight 1
set items [dict get $o_columndata $cidx] set items [dict get $o_columndata $cidx]
set ansibase_body [dict get $o_opts_table -ansibase_body] 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} { proc frame {args} {
variable frametypes
set expect_optval 0 set expect_optval 0
set argposn 0 set argposn 0
set pmax [expr {[llength $args]-1}] set pmax [expr {[llength $args]-1}]
@ -1690,34 +1969,20 @@ namespace eval textblock {
set opt_boxlimits [dict get $opts -boxlimits] set opt_boxlimits [dict get $opts -boxlimits]
set opt_joins [dict get $opts -joins] set opt_joins [dict get $opts -joins]
set opt_boxmap [dict get $opts -boxmap] 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] 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 set known_frametypes $frametypes ;# light, heavey etc as defined in textblock::frametypes variable
if {[llength $opt_type] %2 == 0} { set default_custom [dict create hl " " vl " " tlc " " trc " " blc " " brc " "]
#custom dict may leave out keys - but cannot have unknown keys
dict for {k v} $opt_type { lassign [textblock::frametype $opt_type] _cat category _type ftype
switch -- $k { if {$category eq "custom"} {
hl - hlt - hlb - vl - vll - vlr - tlc - trc - blc - brc {} set custom_frame $ftype
default { set frameset "custom"
#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
} else { } else {
set frame_type $opt_type #category = predefined
set frameset $ftype ;# light,heavy etc
} }
set is_boxlimits_ok 1 set is_boxlimits_ok 1
set exact_boxlimits [list] set exact_boxlimits [list]
foreach v $opt_boxlimits { 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 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 #the arc set can't even join to itself e.g with curved equivalents of T-like shapes
#I guess #I guess
switch -- $frame_type { switch -- $frameset {
"altg" { "altg" {
#old style ansi escape sequences with alternate graphics page G0 #old style ansi escape sequences with alternate graphics page G0
set hl [cd::hl] set hl [cd::hl]
@ -2050,7 +2315,7 @@ namespace eval textblock {
set brc \u2527 ;#boxd_dhlul down heavy and left up light (rtj) set brc \u2527 ;#boxd_dhlul down heavy and left up light (rtj)
} }
light { 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) set brc [punk::char::charshort boxd_lvl] ;#light vertical and left (rtj)
} }
} }
@ -2088,9 +2353,56 @@ namespace eval textblock {
} }
down_left { down_left {
#5 #5
set blc [punk::char::charshort boxd_lvhz] ;#light vertical and horizontal (fwj) switch -- $targetdown-$targetleft {
set tlc [punk::char::charshort boxd_ldhz] ;#T shape (ttj) other-light {
set brc [punk::char::charshort boxd_lvl] ;#light vertical and left (rtj) 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 { down_right {
#6 #6
@ -2727,7 +3039,7 @@ namespace eval textblock {
} }
} }
switch -- $frame_type { switch -- $frameset {
custom { custom {
set vll_width [punk::ansi::printing_length $vll] set vll_width [punk::ansi::printing_length $vll]
@ -2859,7 +3171,7 @@ namespace eval textblock {
} }
#boxlimits used for partial borders in table generation #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] set unspecified_limits [struct::set difference $all_exact_boxlimits $exact_boxlimits]
foreach lim $unspecified_limits { foreach lim $unspecified_limits {
switch -- $lim { switch -- $lim {

Loading…
Cancel
Save