Browse Source

textblock frame/table fixes

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

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

@ -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 {

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

@ -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 {

Loading…
Cancel
Save