###########################################################
# Name:    apavebase.tcl
# Author:  Alex Plotnikov  (aplsimple@gmail.com)
# Date:    12/09/2021
# Brief:   Handles APaveBase class, sort of geometry manager.
# License: MIT.
###########################################################

# ________________________ TCLLIBPATH _________________________ #

# use TCLLIBPATH variable (some tclkits don't see it)
catch {
  foreach _ [lreverse $::env(TCLLIBPATH)] {
    set _ [file normalize $_]
    if {[lsearch -exact $::auto_path $_]<0 && [file exists $_]} {
      set ::auto_path [linsert $::auto_path 0 $_]
    }
  }
}
unset -nocomplain _

# _____ Remove installed subpackages of apave _____ #

foreach _ {baltip bartabs hl_tcl} {
  catch {package forget $_}
  catch {namespace delete ::$_}
}
unset -nocomplain _

# ________________________ apave NS _________________________ #

namespace eval ::apave {

  variable SRCDIR [file normalize [file dirname [info script]]]

  ## ________________________ apave variables _________________________ ##

  variable ISBALTIP yes
  variable cursorwidth 1
  variable apaveDir [file dirname [info script]]
  variable _AP_ICO { none folder OpenFile SaveFile saveall print font color \
    date help home misc terminal run tools file find replace other view \
    categories actions config pin cut copy paste plus minus add delete \
    change diagram box trash double more undo redo up down previous next \
    previous2 next2 upload download tag tagoff tree lock light restricted \
    attach share mail www map umbrella gulls sound heart clock people info \
    err warn ques retry yes no ok cancel exit }
  variable _AP_IMG;  array set _AP_IMG [list]
  variable _AP_VARS; array set _AP_VARS [list]
  set _AP_VARS(APPICON) {}
  set _AP_VARS(.,MODALS) 0
  set _AP_VARS(WPAVE) {}
  set _AP_VARS(TIMW) [list]
  set _AP_VARS(LINKFONT) [list -underline 1]
  set _AP_VARS(INDENT) "  "
  set _AP_VARS(KEY,F3) F3
  set _AP_VARS(KEY,CtrlA) [list Control-A Control-a]
  set _AP_VARS(KEY,CtrlD) [list Control-D Control-d]
  set _AP_VARS(KEY,CtrlY) [list Control-Y Control-y]
  set _AP_VARS(KEY,CtrlT) [list Control-T Control-t]
  set _AP_VARS(KEY,CtrlB) [list Control-B Control-b]
  set _AP_VARS(KEY,CtrlE) [list Control-E Control-e]
  set _AP_VARS(KEY,AltQ) [list Alt-Q Alt-q]
  set _AP_VARS(KEY,AltW) [list Alt-W Alt-w]
  variable _AP_VISITED;  array set _AP_VISITED [list]
  set _AP_VISITED(ALL) [list]
  variable UFF "\uFFFF"
  variable MC_NS {} FOCUSED {}

  ## _ default options & attributes of widgets _ ##

  variable _Defaults [dict create \
    bts {{} {}} \
    but {{} {}} \
    buT {{} {-width -20 -pady 1}} \
    btT {{} {-width -20 -pady 1 -relief flat -overrelief raised -highlightthickness 0 -takefocus 0}} \
    can {{} {}} \
    chb {{} {}} \
    swi {{} {}} \
    chB {{} {-relief sunken -padx 6 -pady 2}} \
    cbx {{} {}} \
    fco {{} {}} \
    ent {{} {}} \
    enT {{} {-insertwidth $::apave::cursorwidth -insertofftime 250 -insertontime 750}} \
    fil {{} {}} \
    fis {{} {}} \
    dir {{} {}} \
    fon {{} {}} \
    clr {{} {}} \
    dat {{} {}} \
    fiL {{} {}} \
    fiS {{} {}} \
    diR {{} {}} \
    foN {{} {}} \
    clR {{} {}} \
    daT {{} {}} \
    sta {{} {}} \
    too {{} {}} \
    fra {{} {-takefocus 0}} \
    frA {{} {-takefocus 0}} \
    ftx {{} {}} \
    gut {{} {-width 0 -highlightthickness 1}} \
    lab {{-sticky w} {-takefocus 0}} \
    laB {{-sticky w} {-takefocus 0}} \
    lfr {{} {-takefocus 0}} \
    lfR {{} {-relief groove -takefocus 0}} \
    lbx {{} {-activestyle none -exportselection 0 -selectmode browse}} \
    flb {{} {}} \
    meb {{} {}} \
    meB {{} {}} \
    nbk {{} {}} \
    opc {{} {}} \
    pan {{} {}} \
    pro {{} {}} \
    rad {{} {}} \
    raD {{} {-padx 6 -pady 2}} \
    sca {{} {-orient horizontal -takefocus 0}} \
    scA {{} {-orient horizontal -takefocus 0}} \
    sbh {{-sticky ew} {-orient horizontal -takefocus 0}} \
    sbH {{-sticky ew} {-orient horizontal -takefocus 0}} \
    sbv {{-sticky ns} {-orient vertical -takefocus 0}} \
    sbV {{-sticky ns} {-orient vertical -takefocus 0}} \
    scf {{} {}} \
    seh {{-sticky ew} {-orient horizontal -takefocus 0}} \
    sev {{-sticky ns} {-orient vertical -takefocus 0}} \
    siz {{} {}} \
    spx {{} {}} \
    spX {{} {}} \
    tbl {{} {-selectborderwidth 1 -highlightthickness 2 \
          -labelcommand tablelist::sortByColumn -stretch all \
          -showseparators 1}} \
    tex {{} {-undo 1 -maxundo 0 -highlightthickness 2 -insertofftime 250 -insertontime 750 -insertwidth $::apave::cursorwidth -wrap word -selborderwidth 1 -exportselection 0}} \
    tre {{} {-selectmode browse}} \
    h_ {{-sticky ew -csz 3 -padx 3} {}} \
    v_ {{-sticky ns -rsz 3 -pady 3} {}}]

  ## _______________________ Helpers _____________________ ##

  proc WindowStatus {w name {val ""} {defval ""}} {
    # Sets/gets a status of window. The status is a value assigned to a name.
    #   w - window's path
    #   name - name of status
    #   val - if blank, to get a value of status; otherwise a value to set
    #   defval - default value (actual if the status not set beforehand)
    # Returns a value of status.
    # See also: IntStatus

    variable _AP_VARS
    if {$val eq {}} {  ;# getting
      if {[info exist _AP_VARS($w,$name)]} {
        return $_AP_VARS($w,$name)
      }
      return $defval
    }
    set _AP_VARS($w,$name) $val  ;# setting
  }
  #_______________________

  proc mainWindowOfApp {{win ""}} {
    # Sets/gets a main window of application.
    #   win - window's path
    # This should be run at application start, before opening any window.

    WindowStatus . MAIN_WINDOW_OF_APP $win
  }
  #_______________________

  proc IntStatus {w {name "status"} {val ""}} {
    # Sets/gets a status of window. The status is an integer assigned to a name.
    #   w - window's path
    #   name - name of status
    #   val - if blank, to get a value of status; otherwise a value to set
    # Default value of status is 0.
    # Returns an old value of status.
    # See also: WindowStatus

    set old [WindowStatus $w $name {} 0]
    if {$val ne {}} {WindowStatus $w $name $val 1}
    return $old
  }
  #_______________________

  proc iconImage {{icon ""} {iconset "small"} {doit no}} {
    # Gets a defined icon's image or list of icons.
    # If *icon* equals to "-init", initializes apave's icon set.
    #   icon - icon's name
    #   iconset - one of small/middle/large
    #   doit - force the initialization
    # Returns the icon's image or, if *icon* is blank, a list of icons
    # available in *apave*.

    variable _AP_IMG
    variable _AP_ICO
    if {$icon eq {}} {return $_AP_ICO}
  ; proc imagename {icon} {   # Get a defined icon's image name
      return _AP_IMG(img$icon)
    }
    variable apaveDir
    if {![array size _AP_IMG] || $doit} {
      # Make images of icons
      source [file join $apaveDir apaveimg.tcl]
      if {$iconset ne "small"} {
        foreach ic $_AP_ICO {  ;# small icons best fit for menus
          set _AP_IMG($ic-small) [set _AP_IMG($ic)]
        }
        if {$iconset eq "middle"} {
          source [file join $apaveDir apaveimg2.tcl]
        } else {
          source [file join $apaveDir apaveimg2.tcl] ;# TODO
        }
      }
      foreach ic $_AP_ICO {
        if {[catch {image create photo [imagename $ic] -data [set _AP_IMG($ic)]}]} {
          # some png issues on old Tk
          image create photo [imagename $ic] -data [set _AP_IMG(none)]
        } elseif {$iconset ne "small"} {
          image create photo [imagename $ic-small] -data [set _AP_IMG($ic-small)]
        }
      }
    }
    if {$icon eq "-init"} {return $_AP_ICO} ;# just to get to icons
    if {$icon ni $_AP_ICO} {set icon [lindex $_AP_ICO 0]}
    if {$iconset eq "small" && "_AP_IMG(img$icon-small)" in [image names]} {
      set icon $icon-small
    }
    return [imagename $icon]
  }
  #_______________________

  proc iconData {{icon "info"} {iconset ""}} {
    # Gets an icon's data.
    #   icon - icon's name
    #   iconset - one of small/middle/large
    # Returns data of the icon.

    variable _AP_IMG
    iconImage -init
    if {$iconset ne {} && "_AP_IMG(img$icon-$iconset)" in [image names]} {
      return [set _AP_IMG($icon-$iconset)]
    }
    set _AP_IMG($icon)
  }
  #_______________________

  proc setAppIcon {win {winicon ""}} {
    # Sets application's icon.
    #   win - path to a window of application
    #   winicon - data of icon
    # The *winicon* may be a contents of variable (as supposed by default) or
    # a file's name containing th image data.
    # If it fails to find an image in either, no icon is set.

    variable _AP_VARS
    set _AP_VARS(APPICON) {}
    if {$winicon ne {}} {
      if {[catch {set _AP_VARS(APPICON) [image create photo -data $winicon]}]} {
        catch {set _AP_VARS(APPICON) [image create photo -file $winicon]}
      }
    }
    if {$_AP_VARS(APPICON) ne {}} {wm iconphoto $win -default $_AP_VARS(APPICON)}
  }
  #_______________________

  proc getAppIcon {} {
    # Gets application's icon.

    variable _AP_VARS
    return $_AP_VARS(APPICON)
  }
  #_______________________

  proc precedeWidgetName {widname prename} {
    # Adds a preceding name to a tail name of widget.
    #   widname - widget's full name
    #   prename - preceding name
    # Useful at getting a entry/button name of chooser.

    # Example:
    #   set wentry [::apave::precedeWidgetName [$pobj DirToChoose] ent]
    # See also: APaveBase::Replace_chooser

    set p [string last . $widname]
    set res [string range $widname 0 $p]
    append res $prename [string range $widname $p+1 end]
    return $res
  }
  #_______________________

  proc defaultAttrs {{type ""} {opts ""} {atrs ""} {widget ""}} {
    # Sets, gets or registers default options and attributes for widget type.
    #   type - widget type
    #   opts - new default grid/pack options
    #   atrs - new default attributes
    #   widget - Tcl/Tk command for the new registered widget type
    # See also: APaveBase::defaultATTRS

    obj defaultATTRS $type $opts $atrs $widget
  }
  #_______________________

  proc focusApp {{win ""}} {
    # Saves (if *win* is set) or restores app's focus.
    #   win - focused window's path
    # In some DE, if app loses focus, restoring it
    # focuses main window, ignores modal toplevel, locks keyboard.
    # focusApp tries to focus on last modal window.

    variable FOCUSED
    if {$win ne {}} {
      setProperty FOCW_$win [focus]
      return
    }
    catch {
      if {[set foc [focus]] ne {}} {
        set foc [winfo toplevel $foc]
        set modal 0
        foreach fw $FOCUSED {
          if {$fw eq $foc} {set modal 1; break}
        }
        # if non-modal is currently focused, let it be so
        if {!$modal} {
          if {[focus] eq $foc} {catch {focus [getProperty FOCW_$foc]}}
          return
        }
      }
      # find and focus last open modal
      for {set i [llength $FOCUSED]} {$i} {} {
        set fw [lindex $FOCUSED [incr i -1]]
        if {[winfo exists $fw]} {
          if {$fw ne $foc} {
            focus -force $fw
            catch {focus [getProperty FOCW_$fw]}
          }
          break
        }
        set FOCUSED [lreplace $FOCUSED $i $i]
      }
    }
  }

  ## _______________________ Text little procs _________________________ ##

  proc eventOnText {w ev} {
    # Generates an event on a text, saving its current index in hl_tcl.
    #   w - text widget's path
    #   ev - event
    # The hl_tcl needs to call MemPos before any action changing the text.

    catch {::hl_tcl::my::MemPos $w}
    if {[catch {$w tag ranges sel} sels]} {set sels [list]}
    switch -exact -- $ev {
      <<Cut>> - <<Copy>> {
        if {[set llen [expr {[llength $sels]-1}]] < 2} return
        # multiple ranges of selection:
        # first, copy all selections to clipboard
        clipboard clear -displayof $w
        foreach {pos1 pos2} $sels {
          clipboard append -displayof $w [$w get $pos1 $pos2]
        }
        if {$ev eq {<<Cut>>}} {
          # for Cut event: delete all selections
          for {set i $llen} {$i>0} {incr i -2} {
            set pos1 [lindex $sels $i-1]
            set pos2 [lindex $sels $i]
            $w delete $pos1 $pos2
          }
        }
        return -code break
      }
      default {
        event generate $w $ev
      }
    }
  }
  #_______________________

  proc getTextHotkeys {key} {
    # Gets upper & lower keys for a hot key.
    #   key - the hot key

    variable _AP_VARS
    if {![info exist _AP_VARS(KEY,$key)]} {return [list]}
    set keys $_AP_VARS(KEY,$key)
    if {[llength $keys]==1} {
      if {[set i [string last - $keys]]>0} {
        set lt [string range $keys $i+1 end]
        if {[string length $lt]==1} {  ;# for lower case of letters
          set keys "[string range $keys 0 $i][string toupper $lt]"
          lappend keys "[string range $keys 0 $i][string tolower $lt]"
        }
      }
    }
    return $keys
  }
  #_______________________

  proc setTextHotkeys {key value} {
    # Sets new key combinations for some operations on text widgets.
    #   key - ctrlD for "double selection", ctrlY for "delete line" operation
    #   value - list of new key combinations

    variable _AP_VARS
    set _AP_VARS(KEY,$key) $value
  }
  #_______________________

  proc setTextIndent {len {padchar { }}} {
    # Sets an indenting for text widgets.
    #   len - length of indenting
    #   padchar - indenting character

    variable _AP_VARS
    if {$padchar ne "\t"} {set padchar { }}
    set _AP_VARS(INDENT) [string repeat $padchar $len]
  }

  ## ________________________ EONS ::apave _________________________ ##

}

# ________________________ source *.tcl _________________________ #

# Let the *.tcl be sourced here just to ensure
# that apave's stuff available for them and vice versa.

source [file join $::apave::apaveDir obbit.tcl]

# ________________________ APaveBase oo::class _________________________ #

oo::class create ::apave::APaveBase {

  mixin ::apave::ObjectTheming

  variable PV Moveall Initialcolor Modalwin Fgbut Bgbut Fgtxt Bgtxt Prepost Widgetopts Edge

  constructor {{cs -2} args} {
    # Creates APaveBase object.
    #   cs - color scheme (CS)
    #   args - additional arguments
    # If cs>-2, the appropriate CS is set for the created APaveBase object.
    # Makes few procedures in the object's namespace to access from
    # event handlers:
    #   - ListboxHandle
    #   - ListboxSelect
    #   - WinResize
    # This trick with *proc* inside an object is discussed at
    #   [proc-in-tcl-ooclass](https://stackoverflow.com/questions/54804964/proc-in-tcl-ooclass)

    # keep the 'important' data of Pave object in array
    array set PV [list]
    set Moveall 1
    set Initialcolor {}
    set Modalwin .
    set Fgbut [ttk::style lookup TButton -foreground]; if {$Fgbut eq {}} {set Fgbut #000000}
    set Bgbut [ttk::style lookup TButton -background]; if {$Bgbut eq {}} {set Bgbut #d9d9d9}
    set Fgtxt [ttk::style lookup TEntry -foreground] ; if {$Fgtxt eq {}} {set Fgtxt #000000}
    set Prepost [list]
    set Widgetopts [list]
    set Edge @@
    if {$Fgtxt in {black #000000}} {
      set Bgtxt white
    } else {
      set Bgtxt [ttk::style lookup TEntry -background]
    }
    # set/reset a color scheme if it is/was requested
    if {$cs>=-1} {my csSet $cs} {my initTooltip}

    # object's procedures

  ; proc ListboxHandle {W offset maxChars} {

      set list {}
      foreach index [$W curselection] { lappend list [$W get $index] }
      set text [join $list \n]
      return [string range $text $offset [expr {$offset+$maxChars-1}]]
    }

  ; proc ListboxSelect {W} {
      # This code had been taken from Tcl's wiki:
      #   https://wiki.tcl-lang.org/page/listbox+selection

      selection clear -displayof $W
      selection own -command {} $W
      selection handle -type UTF8_STRING \
        $W [list [namespace current]::ListboxHandle $W]
      selection handle \
        $W [list [namespace current]::ListboxHandle $W]
      return
    }

  ; proc WinResize {win} {
      # Restricts the window's sizes (thus fixing Tk's issue with a menubar)
      #   win - path to a window to be of restricted sizes

      if {[$win cget -menu] ne {}} {
        lassign [::apave::splitGeometry [wm geometry $win]] w h
        lassign [wm minsize $win] wmin hmin
        if {$w<$wmin && $h<$hmin} {
          set corrgeom ${wmin}x$hmin
        } elseif {$w<$wmin} {
          set corrgeom ${wmin}x$h
        } elseif {$h<$hmin} {
          set corrgeom ${w}x$hmin
        } else {
          return
        }
        wm geometry $win $corrgeom
      }
      return
    }

    # the end of APaveBase constructor
    if {[llength [self next]]} { next {*}$args }
    return
  }

  destructor {
    # Clears variables used in the object.

    array unset PV *
    if {[llength [self next]]} next
  }

  ## _______________________ Methods to be redefined ____________________ ##

  method themePopup {mnu} {
    # Applies a color scheme to a popup menu.
    #   mnu - name of popup menu
    # The method is to be redefined in descendants/mixins.

  }

  method NonTtkTheme {win} {
    # Applies a current color scheme for non-ttk widgets.
    #   win - path to a window to be colored.
    # Method to be redefined in descendants/mixins.

  }

  method NonTtkStyle {typ {dsbl 0}} {
    # Gets a style for non-ttk widgets.
    #   typ - the type of widget (in apave terms, i.e. but, buT etc.)
    #   dsbl - a mode to get style of disabled (1) or readonly (2) widgets
    # See also: widgetType
    # Method to be redefined in descendants/mixins.

  }

  ## _______________________ Helpers for APaveBase ________________________ ##

  method paveoptionValue {opt} {
    # Gets an option's value.
    #   opt - option's name
    # Returns a value for options like "Moveall".

    if {$opt in [info object vars [self]]} {
      variable $opt
      return [set $opt]
    }
    return {}
  }
  #_______________________

  method checkXY {w h x y} {
    # Checks the coordinates of window (against the screen).
    #   w - width of window
    #   h - height of window
    #   x - window's X coordinate
    #   y - window's Y coordinate
    # Returns new coordinates in +X+Y form.

    # check for left/right edge of screen (accounting decors)
    set scrw [expr {[winfo vrootwidth .] - 12}]
    set scrh [expr {[winfo vrootheight .] - 36}]
    if {($x + $w) > $scrw } {
      set x [expr {$scrw - $w}]
    }
    if {($y + $h) > $scrh } {
      set y [expr {$scrh - $h}]
    }
    if {![string match -* $x]} {set x +[string trimleft $x +]}
    if {![string match -* $y]} {set y +[string trimleft $y +]}
    return $x$y
  }
  #_______________________

  method CenteredXY {rw rh rx ry w h} {
    # Gets the coordinates of centered window (against its parent).
    #   rw - parent's width
    #   rh - parent's height
    #   rx - parent's X coordinate
    #   ry - parent's Y coordinate
    #   w - width of window to be centered
    #   h - height of window to be centered
    # Returns centered coordinates in +X+Y form.

    set x [expr {max(0, $rx + ($rw - $w) / 2)}]
    set y [expr {max(0,$ry + ($rh - $h) / 2)}]
    my checkXY $w $h $x $y
  }
  #_______________________

  method ownWName {name} {
    # Gets a tail (last part) of widget's name
    #   name - name (path) of the widget

    lindex [split $name .] end
  }
  #_______________________

  method parentWName {name} {
    # Gets parent name of widget.
    #   name - name (path) of the widget

    string range $name 0 [string last . $name]-1
  }
  #_______________________

  method iconA {icon {iconset small} {cmpd left}} {
    # Gets icon attributes for buttons, menus etc.
    #   icon - name of icon
    #   iconset - one of small/middle/large
    #   cmpd - value of -compound option
    # The *iconset* is "small" for menus (recommended and default).

    return "-image [::apave::iconImage $icon $iconset] -compound $cmpd"
  }
  #_______________________

  method configure {args} {
    # Configures the apave object (all of options may be changed).
    #   args - list of pairs name/value of options
    # Example:
    #     pobj configure edge "@@"

    foreach {optnam optval} $args {set $optnam $optval}
  }
  #_______________________

  method ExpandOptions {options} {
    # Expands shortened options.

    set options [string map {
      { -st } { -sticky }
      { -com } { -command }
      { -t } { -text }
      { -w } { -width }
      { -h } { -height }
      { -var } { -variable }
      { -tvar } { -textvariable }
      { -lvar } { -listvariable }
      { -ro } { -readonly }
    } " $options"]
    return $options
  }
  #_______________________

  method AddButtonIcon {w attrsName} {
    # Gets the button's icon based on its text and name (e.g. butOK) and
    # appends it to the attributes of button.
    #   w - button's name
    #   attrsName - name of variable containing attributes of the button

    upvar 1 $attrsName attrs
    set com [::apave::getOption -com {*}$attrs]
    if {[string is integer -strict $com]} {  ;# returned integer result
      ::apave::extractOptions attrs -com {}
      append attrs " -com {[self] res {[my pavedPath]} $com}"
    }
    if {[::apave::getOption -image {*}$attrs] ne {}} return
    set txt [::apave::getOption -t {*}$attrs]
    if {$txt eq {}} { set txt [::apave::getOption -text {*}$attrs] }
    set im {}
    set icolist [list {exit abort} {exit close} \
      {SaveFile save} {OpenFile open}]
    # ok, yes, cancel, apply buttons should be at the end of list
    # as their texts can be renamed (e.g. "Help" in e_menu's "About")
    lappend icolist {*}[::apave::iconImage] {yes apply}
    foreach icon $icolist {
      lassign $icon ic1 ic2
      # text of button is of highest priority at defining its icon
      if {[string match -nocase $ic1 $txt] || \
      [string match -nocase b*t$ic1 $w] || ($ic2 ne {} && ( \
      [string match -nocase b*t$ic2 $w] || [string match -nocase $ic2 $txt]))} {
        if {[string match -nocase btT* $w]} {
          set cmpd none
        } else {
          set cmpd left
        }
        append attrs " [my iconA $ic1 small $cmpd]"
        break
      }
    }
  }
  #_______________________

  method ListboxesAttrs {w attrs} {
    # Appends selection attributes to listboxes.
    # Details:
    #   1. https://wiki.tcl-lang.org/page/listbox+selection
    #   2. https://stackoverflow.com, the question:
    #        the-tablelist-curselection-goes-at-calling-the-directory-dialog

    if {{-exportselection} ni $attrs} {
      append attrs " -ListboxSel $w -selectmode extended -exportselection 0"
    }
    return $attrs
  }
  #_______________________

  method getWidChildren {wid treeName {init yes}} {
    # Gets children of a widget.
    #   wid - widget's path
    #   treeName - name of variable to hold the result.

    upvar $treeName tree
    if {$init} {set tree [list]}
    foreach ch [winfo children $wid] {
      lappend tree $ch
      my getWidChildren $ch $treeName no
    }
  }
  #_______________________

  method findWidPath {wid {mode exact} {visible yes}} {
    # Searches a widget's path among the active widgets.
    #   w - widget name, set partially e.g. "wid" instead of ".win.wid"
    #   mode - if "exact", searches *.wid; if "globe", searches *wid*
    # Returns the widget's full path or "" if the widget isn't active.

    my getWidChildren . tree
    if {$mode eq {exact}} {
      set i [lsearch -glob $tree "*.$wid"]
    } else {
      set i [lsearch -glob $tree "*$wid*"]
    }
    if {$i>-1} {return [lindex $tree $i]}
    return {}
  }

  ## _______________________ File content widget _______________________ ##

  method FCfieldAttrs {wnamefull attrs varopt} {
    # Fills the non-standard attributes of file content widget.
    #   wnamefull - a widget name
    #   attrs - a list of all attributes
    #   varopt - a variable option
    # The *varopt* refers to a variable part such as tvar, lvar:
    #  * -inpval option means an initial value of the field
    #  * -retpos option has p1:p2 format (e.g. 0:10) to cut a substring \
    from a returned value
    # Returns *attrs* without -inpval and -retpos options.

    lassign [::apave::parseOptions $attrs $varopt {} -retpos {} -inpval {}] \
      vn rp iv
    if {[string first {-state disabled} $attrs]<0 && $vn ne {}} {
      set all {}
      if {$varopt eq {-lvar}} {
        lassign [::apave::extractOptions attrs -values {} -ALL 0] iv a
        if {[string is boolean -strict $a] && $a} {set all ALL}
        lappend Widgetopts "-lbxname$all $wnamefull $vn"
      }
      if {$rp ne {}} {
        if {$all ne {}} {set rp 0:end}
        lappend Widgetopts "-retpos $wnamefull $vn $rp"
      }
    }
    if {$iv ne {}} { set $vn $iv }
    return [::apave::removeOptions $attrs -retpos -inpval]
  }
  #_______________________

  method FCfieldValues {wnamefull attrs} {
    # Fills the file content widget's values.
    #   wnamefull - name (path) of fco widget
    #   attrs - attributes of the widget

  ; proc readFCO {fname} {
      # Reads a file's content.
      # Returns a list of (non-empty) lines of the file.
      if {$fname eq {}} {
        set retval {{}}
      } else {
        set retval {}
        foreach ln [::apave::textsplit [::apave::readTextFile $fname {} 1]] {
          # probably, it's bad idea to have braces in the file of contents
          set ln [string map [list \\ \\\\ \{ \\\{ \} \\\}] $ln]
          if {$ln ne {}} {lappend retval $ln}
        }
      }
      return $retval
    }

  ; proc contFCO {fline opts edge args} {
      # Given a file's line and options,
      # cuts a substring from the line.
      lassign [::apave::parseOptionsFile 1 $opts {*}$args] opts
      lassign $opts - - - div1 - div2 - pos - len - RE - ret
      set ldv1 [string length $div1]
      set ldv2 [string length $div2]
      set i1 [expr {[string first $div1 $fline]+$ldv1}]
      set i2 [expr {[string first $div2 $fline]-1}]
      set filterfile yes
      if {$ldv1 && $ldv2} {
        if {$i1<0 || $i2<0} {return $edge}
        set retval [string range $fline $i1 $i2]
      } elseif {$ldv1} {
        if {$i1<0} {return $edge}
        set retval [string range $fline $i1 end]
      } elseif {$ldv2} {
        if {$i2<0} {return $edge}
        set retval [string range $fline 0 $i2]
      } elseif {$pos ne {} && $len ne {}} {
        set retval [string range $fline $pos $pos+[incr len -1]]
      } elseif {$pos ne {}} {
        set retval [string range $fline $pos end]
      } elseif {$len ne {}} {
        set retval [string range $fline 0 $len-1]
      } elseif {$RE ne {}} {
        set retval [regexp -inline $RE $fline]
        if {[llength $retval]>1} {
          foreach r [lrange $retval 1 end] {append retval_tmp $r}
          set retval $retval_tmp
        } else {
          set retval [lindex $retval 0]
        }
      } else {
        set retval $fline
        set filterfile no
      }
      if {$retval eq {} && $filterfile} {return $edge}
      set retval [string map [list "\}" "\\\}"  "\{" "\\\{"] $retval]
      return [list $retval $ret]
    }

    set edge $Edge
    set ldv1 [string length $edge]
    set filecontents {}
    set optionlists {}
    set tplvalues {}
    set retpos {}
    set values [::apave::getOption -values {*}$attrs]
    if {[string first $edge $values]<0} { ;# if 1 file, edge
      set values "$edge$values$edge"      ;# may be omitted
    }
    # get: files' contents, files' options, template line
    set lopts {-list {} -div1 {} -div2 {} -pos {} -len {} -RE {} -ret 0}
    while {1} {
      set i1 [string first $edge $values]
      set i2 [string first $edge $values $i1+1]
      if {$i1>=0 && $i2>=0} {
        incr i1 $ldv1
        append tplvalues [string range $values 0 $i1-1]
        set fdata [string range $values $i1 $i2-1]
        lassign [::apave::parseOptionsFile 1 $fdata {*}$lopts] fopts fname
        lappend filecontents [readFCO $fname]
        lappend optionlists $fopts
        set values [string range $values $i2+$ldv1 end]
      } else {
        append tplvalues $values
        break
      }
    }
    # fill the combobox lines, using files' contents and options
    if {[set leno [llength $optionlists]]} {
      set newvalues {}
      set ilin 0
      lassign $filecontents firstFCO
      foreach fline $firstFCO { ;# lines of first file for a base
        set line {}
        set tplline $tplvalues
        for {set io 0} {$io<$leno} {incr io} {
          set opts [lindex $optionlists $io]
          if {$ilin==0} {  ;# 1st cycle: add items from -list option
            lassign $opts - list1  ;# -list option goes first
            if {[llength $list1]} {
              foreach l1 $list1 {append newvalues "\{$l1\} "}
              lappend Widgetopts "-list $wnamefull [list $list1]"
            }
          }
          set i1 [string first $edge $tplline]
          if {$i1>=0} {
            lassign [contFCO $fline $opts $edge {*}$lopts] retline ret
            if {$ret ne "0" && $retline ne $edge && \
            [string first $edge $line]<0} {
              set p1 [expr {[string length $line]+$i1}]
              if {$io<($leno-1)} {
                set p2 [expr {$p1+[string length $retline]-1}]
              } else {
                set p2 end
              }
              set retpos "-retpos $p1:$p2"
            }
            append line [string range $tplline 0 $i1-1] $retline
            set tplline [string range $tplline $i1+$ldv1 end]
          } else {
            break
          }
          set fline [lindex [lindex $filecontents $io+1] $ilin]
        }
        if {[string first $edge $line]<0} {
          # put only valid lines into the list of values
          append newvalues "\{$line$tplline\} "
        }
        incr ilin
      }
      # replace old 'values' attribute with the new 'values'
      lassign [::apave::parseOptionsFile 2 $attrs -values \
        [string trimright $newvalues]] attrs
    }
    return "$attrs $retpos"
  }

  ## _______________________ Timeout button _______________________ ##

  method timeoutButton {w tmo lbl {lbltext ""}} {
    # Invokes a button's action after a timeout.
    #   w - button's path
    #   tmo - timeout in sec.
    #   lbl - label widget, where seconds to wait are displayed
    #   lbltext - original text of label

    if {$tmo>0} {
      catch {set lbl [my $lbl]}
      if {[winfo exist $lbl]} {
        if {$lbltext eq {}} {
          set lbltext [$lbl cget -text]
          lappend ::apave::_AP_VARS(TIMW) $w
        }
        $lbl configure -text "$lbltext $tmo sec. "
      }
      incr tmo -1
      after 1000 [list if "\[info commands [self]\] ne {}" \
        "[self] checkTimeoutButton $w $tmo $lbl {$lbltext}"]
      return
    }
    if {[winfo exist $w]} {$w invoke}
  }
  #_______________________

  method checkTimeoutButton {w tmo lbl {lbltext ""}} {
    # Checks if the timeout button is alive & focused; if not, cancels the timeout.
    #   w - button's path
    #   tmo - timeout in sec.
    #   lbl - label widget, where seconds to wait are displayed
    #   lbltext - original text of label

    if {[winfo exists $lbl]} {
      if {[focus] in [list $w {}]} {
        if {$w in $::apave::_AP_VARS(TIMW)} {
          my timeoutButton $w $tmo $lbl $lbltext
        }
      } else {
        $lbl configure -text $lbltext
      }
    }
  }

  ## ________________________ Making widgets _________________________ ##

  method widgetType {wnamefull options attrs} {
    # Gets the widget type based on 3 initial letters of its name. Also
    # fills the grid/pack options and attributes of the widget.
    #   wnamefull - path to the widget
    #   options - grid/pack options of the widget
    #   attrs - attribute of the widget
    # Returns a list of items:
    #   widget - Tk/Ttk widget name
    #   options - grid/pack options of the widget
    #   attrs - attribute of the widget
    #   nam3 - 3 initial letters of widget's name
    #   disabled - flag of *disabled* state

    set disabled [expr {[::apave::getOption -state {*}$attrs] eq {disabled}}]
    set pack $options
    set name [my ownWName $wnamefull]
    if {[info exists ::apave::_AP_VARS(ProSplash,type)] && \
    $::apave::_AP_VARS(ProSplash,type) eq {}} {
      set val [my progress_Go [incr ::apave::_AP_VARS(ProSplash,curvalue)] {} $name]
    }
    set nam3 [string tolower [string index $name 0]][string range $name 1 2]
    if {[string index $nam3 1] eq "_"} {set k [string range $nam3 0 1]} {set k $nam3}
    lassign [my defaultATTRS $k] defopts defattrs newtype
    set options "$defopts $options"
    set attrs "$defattrs $attrs"
    switch -glob -- $nam3 {
      bts {
        set widget ttk::frame
        if {![namespace exists ::bartabs]} {
          source [file join $::apave::SRCDIR bartabs bartabs.tcl]
        }
        set attrs "-bartabs {$attrs}"
      }
      but {
        set widget ttk::button
        my AddButtonIcon $name attrs
      }
      buT - btT {
        set widget button
        my AddButtonIcon $name attrs
      }
      can {set widget canvas}
      chb {set widget ttk::checkbutton}
      swi {
        set widget ttk::checkbutton
        if {![my apaveTheme]} {
          set attrs "$attrs -style Switch.TCheckbutton"
        }
      }
      chB {set widget checkbutton}
      cbx - fco {
        set widget ttk::combobox
        if {$nam3 eq {fco}} {  ;# file content combobox
          set attrs [my FCfieldValues $wnamefull $attrs]
        }
        set attrs [my FCfieldAttrs $wnamefull $attrs -tvar]
      }
      ent {set widget ttk::entry}
      enT {set widget entry}
      fil - fiL -
      fis - fiS -
      dir - diR -
      fon - foN -
      clr - clR -
      dat - daT -
      sta -
      too -
      fra {
        # + frame for choosers and bars
        set widget ttk::frame
      }
      frA {
        set widget frame
        if {$disabled} {set attrs [::apave::removeOptions $attrs -state]}
      }
      ftx {set widget ttk::labelframe}
      gut {set widget canvas}
      lab {
        set widget ttk::label
        if {$disabled} {
          set grey [lindex [my csGet] 8]
          set attrs "-foreground $grey $attrs"
        }
        lassign [::apave::parseOptions $attrs -link {} -style {} -font {}] \
          cmd style font
        if {$cmd ne {}} {
          set attrs "-linkcom {$cmd} $attrs"
          set attrs [::apave::removeOptions $attrs -link]
        }
        if {$style eq {} && $font eq {}} {
          set attrs "-font {$::apave::FONTMAIN} $attrs"
        } elseif {$style ne {}} {
          # some themes stumble at ttk styles, so bring their attrs directly
          set attrs [::apave::removeOptions $attrs -style]
          set attrs "[ttk::style configure $style] $attrs"
        }
      }
      laB {set widget label}
      lfr {set widget ttk::labelframe}
      lfR {
        set widget labelframe
        if {$disabled} {set attrs [::apave::removeOptions $attrs -state]}
      }
      lbx - flb {
        set widget listbox
        if {$nam3 eq {flb}} {  ;# file content listbox
          set attrs [my FCfieldValues $wnamefull $attrs]
        }
        set attrs "[my FCfieldAttrs $wnamefull $attrs -lvar]"
        set attrs "[my ListboxesAttrs $wnamefull $attrs]"
        my AddPopupAttr $wnamefull attrs -entrypop 1
        foreach {ev com} {Home {::apave::LbxSelect %w 0} End {::apave::LbxSelect %w end}} {
          append attrs " -bindEC {<$ev> {$com}} "
        }
      }
      meb {set widget ttk::menubutton}
      meB {set widget menubutton}
      nbk {
        set widget ttk::notebook
        set attrs "-notebazook {$attrs}"
      }
      opc {
        ;# tk_optionCascade - example of "my method" widget
        ;# arguments: vname items mbopts precom args
        set widget {my tk_optionCascade}
        set imax [expr {min(4,[llength $attrs])}]
        for {set i 0} {$i<$imax} {incr i} {
          set atr [lindex $attrs $i]
          if {$i!=1} {
            lset attrs $i \{$atr\}
          } elseif {[llength $atr]==1 && [info exist $atr]} {
            lset attrs $i [set $atr]  ;# items stored in a variable
          }
        }
      }
      pan {set widget ttk::panedwindow
        if {[string first -w $attrs]>-1 && [string first -h $attrs]>-1} {
          # important for panes with fixed (customized) dimensions
          set attrs "-propagate {$options} $attrs"
        }
      }
      pro {set widget ttk::progressbar}
      rad {set widget ttk::radiobutton}
      raD {set widget radiobutton}
      sca {set widget ttk::scale}
      scA {set widget scale}
      sbh {set widget ttk::scrollbar}
      sbH {set widget scrollbar}
      sbv {set widget ttk::scrollbar}
      sbV {set widget scrollbar}
      scf {
        if {![namespace exists ::apave::sframe]} {
          namespace eval ::apave {
            source [file join $::apave::apaveDir sframe.tcl]
          }
        }
        # scrolledFrame - example of "my method" widget
        set widget {my scrolledFrame}
      }
      seh {set widget ttk::separator}
      sev {set widget ttk::separator}
      siz {set widget ttk::sizegrip}
      spx - spX {
        if {$nam3 eq {spx}} {set widget ttk::spinbox} {set widget spinbox}
        lassign [::apave::parseOptions $attrs \
          -command {} -com {} -from {} -to {}] cmd cmd2 from to
        append cmd $cmd2
        lassign [::apave::extractOptions attrs -tip {} -tooltip {}] t1 t2
        set t2 "$t1$t2"
        if {$from ne {} || $to ne {}} {
          if {$t2 ne {}} {set t2 "\n $t2"}
          set t2 " $from .. $to $t2"
        }
        if {$t2 ne {}} {set t2 "-tip {$t2}"}
        append attrs " -onReturn {$::apave::UFF{$cmd} {$from} {$to}$::apave::UFF} $t2"
      }
      tbl { ;# tablelist
        if {![namespace exists ::tablelist::]} {
          namespace eval :: {package require tablelist}
        }
        set widget ::tablelist::tablelist
        set attrs "[my FCfieldAttrs $wnamefull $attrs -lvar]"
        set attrs "[my ListboxesAttrs $wnamefull $attrs]"
      }
      tex {set widget text
        if {[::apave::getOption -textpop {*}$attrs] eq {}} {
          my AddPopupAttr $wnamefull attrs -textpop \
            [expr {[::apave::getOption -rotext {*}$attrs] ne {}}] -- disabled
        }
        lassign [::apave::parseOptions $attrs -ro {} -readonly {} -rotext {} \
          -gutter {} -gutterwidth 5 -guttershift 6] r1 r2 r3 g1 g2 g3
        set b1 [expr [string is boolean -strict $r1]]
        set b2 [expr [string is boolean -strict $r2]]
        if {($b1 && $r1) || ($b2 && $r2) || \
        ($r3 ne {} && !($b1 && !$r1) && !($b2 && !$r2))} {
          set attrs "-takefocus 0 $attrs"
        }
        set attrs [::apave::removeOptions $attrs -gutter -gutterwidth -guttershift]
        if {$g1 ne {}} {
          set attrs "$attrs -gutter {-canvas $g1 -width $g2 -shift $g3}"
        }
      }
      tre {
        set widget ttk::treeview
        set ec [list Home {::apave::TreSelect %w 0} End {::apave::TreSelect %w end}]
        if {[::isunix]} {lappend ec KP_Enter {event generate %w <Return>}}
        foreach {ev com} $ec {
          append attrs " -bindEC {<$ev> {$com}} "
        }
      }
      h_* {set widget ttk::frame}
      v_* {set widget ttk::frame}
      default {set widget $newtype}
    }
    set attrs [my GetMC $attrs]
    if {$nam3 in {cbx ent enT fco spx spX}} {
      # entry-like widgets need their popup menu
      set clearcom [lindex [::apave::parseOptions $attrs -clearcom -] 0]
      if {$clearcom eq {-}} {
        my AddPopupAttr $wnamefull attrs -entrypop 0 readonly disabled
      }
    }
    if {[string first pack [string trimleft $pack]]==0} {
      catch {
        # try to expand -after option (if set as WidgetName instead widgetName)
        if {[set i [lsearch -exact $pack {-after}]]>=0} {
          set aft [lindex $pack [incr i]]
          if {[regexp {^[A-Z]} $aft]} {
            set aft [my $aft]
            set pack [lreplace $pack $i $i $aft]
          }
        }
      }
      set options $pack
    }
    set options [string trim $options]
    set attrs   [list {*}$attrs]
    list $widget $options $attrs $nam3 $disabled
  }
  #_______________________

  method defaultATTRS {{type ""} {opts ""} {atrs ""} {widget ""}} {
    # Sets, gets or registers default options and attributes for widget type.
    #   type - widget type
    #   opts - new default grid/pack options
    #   atrs - new default attributes
    #   widget - Tcl/Tk command for the new registered widget type
    # The *type* should be a three letter unique string.
    # If the *type* is absent in the registered types and *opts* and/or *atrs*
    # is not set to "", defaultATTRS registers the new *type* with its grid/pack
    # options and attributes. At that *widget* is a command for the new widget
    # type. For example, to register "toolbutton" widget:
    #   my defaultATTRS tbt {} {-style Toolbutton -compound top} ttk::button
    # Options and attributes may contain data (variables and commands)
    # to be processed by [subst].
    # Returns:
    #   - if not set *type*: a full list of options and attributes of all types
    #   - if set *type* only: a list of options, attributes and *widget*
    #   - else: a list of updated options, attributes and *widget*

    if {$type eq {}} {return $::apave::_Defaults}
    set optatr "$opts$atrs"
    if {[catch {set def1 [dict get $::apave::_Defaults $type]}]} {
      if {$optatr eq {}} {
        set err "[self method]: \"$type\" widget type not registered."
        puts -nonewline stderr $err
        return -code error $err
      }
      set def1 [list $opts $atrs $widget]
    }
    if {$optatr eq {}} {return [subst $def1]}
    lassign $def1 defopts defatrs widget
    if {[catch {set defopts [dict replace $defopts {*}$opts]}]} {
      set defopts [string trim "$defopts $opts"]
    }
    if {[catch {set defatrs [dict replace $defatrs {*}$atrs]}]} {
      set defatrs [string trim "$defatrs $atrs"]
    }
    set newval [list $defopts $defatrs $widget]
    dict set ::apave::_Defaults $type $newval
    return $newval
  }
  #_______________________

  method MC {msg} {
    # Gets localized message
    #   msg - the message

    # to use a preset namespace name, we need a fully qualified variable
    set ::apave::_MC_TEXT_ [string trim $msg \{\}]
    if {$::apave::MC_NS ne {}} {
      namespace eval $::apave::MC_NS {
        set ::apave::_MC_TEXT_ [msgcat::mc $::apave::_MC_TEXT_]
      }
    } else {
      set ::apave::_MC_TEXT_ [msgcat::mc $::apave::_MC_TEXT_]
    }
    return $::apave::_MC_TEXT_
  }
  #_______________________

  method GetMC {attrs} {
    # Gets localized -text attribute.
    #   attrs - list of attributes

    lassign [::apave::extractOptions attrs -t {} -text {}] t text
    if {$t ne {} || $text ne {}} {
      if {$text eq {}} {set text $t}
      dict set attrs -t [my MC $text]
    }
    return $attrs
  }
  #_______________________

  method SpanConfig {w rcnam rc rcspan opt val} {
    # The method is used by *GetIntOptions* method to configure
    # row/column for their *span* options.

    for {set i $rc} {$i < ($rc + $rcspan)} {incr i} {
      eval [grid ${rcnam}configure $w $i $opt $val]
    }
  }
  #_______________________

  method GetIntOptions {w options row rowspan col colspan} {
    # Gets specific integer options. Then expands other options.
    #   w - widget's name
    #   options - grid options
    #   row, rowspan - row and its span of thw widget
    #   col, colspan - column and its span of thw widget
    # The options are set in grid options as "-rw <int>", "-cw <int>" etc.
    # Returns the resulting grid options.

    set opts {}
    foreach {opt val} [list {*}$options] {
      switch -exact -- $opt {
        -rw  {my SpanConfig $w row $row $rowspan -weight $val}
        -cw  {my SpanConfig $w column $col $colspan -weight $val}
        -rsz {my SpanConfig $w row $row $rowspan -minsize $val}
        -csz {my SpanConfig $w column $col $colspan -minsize $val}
        -ro  {my SpanConfig $w column $col $colspan -readonly $val}
        default {append opts " $opt $val"}
      }
    }
    # Get other grid options
    return [my ExpandOptions $opts]
  }
  #_______________________

  method GetAttrs {options {nam3 ""} {disabled 0} } {
    # Expands attributes' values.
    #   options - list of attributes and values
    #   nam3 - first three letters (type) of widget's name
    #   disabled - flag of "disabled" state
    # Returns expanded attributes.

    set opts [list]
    foreach {opt val} [list {*}$options] {
      switch -exact -- $opt {
        -t - -text {
          ;# these options need translating \\n to \n
          # catch {set val [subst -nocommands -novariables $val]}
          set val [string map [list \\n \n \\t \t] $val]
          set opt -text
        }
        -st {set opt -sticky}
        -com {set opt -command}
        -w {set opt -width}
        -h {set opt -height}
        -var {set opt -variable}
        -tvar {set opt -textvariable}
        -lvar {set opt -listvariable}
        -ro {set opt -readonly}
      }
      lappend opts $opt \{$val\}
    }
    if {$disabled} {
      append opts [my NonTtkStyle $nam3 1]
    }
    return $opts
  }
  #_______________________

  method menuTips {win tip {wpar {}}} {
    # Makes tip(s) for menu and its items.
    #   win - menu's path
    #   tip - tip's text
    #   wpar - path to menu's parent (for opc widget)
    # The tips for menu items are set by "-indexedtips ?idx tip...?"
    # e.g., a tip can be "parent tip -indexedtips 0 1stItem 9 {10th Item}"

    if {$tip ne {}} {
      set tip [my MC $tip]
      if {[set i [string first {-indexedtips } $tip]]>-1} {
        set indexedtips [string range $tip [string first { } $tip $i]+1 end]
        set tip [string range $tip 0 $i-1]
      } else {
        set indexedtips {}
      }
      # \indexedtips to present -indexedtips in parent tip
      set tip [string map "\\indexedtips -indexedtips" $tip]
      catch {
        # tips for indexed items of menu
        while {$indexedtips ne {}} {
          lassign $indexedtips idx itip
          if {$idx eq {}} break
          after idle [list ::baltip tip $win $itip -index $idx -ontop 1]
          set indexedtips [lrange $indexedtips 2 end]
        }
      }
      if {$tip ne {} && $wpar ne {}} {
        after idle [list ::baltip tip $wpar $tip]  ;# tip for the parent widget
      }
    }
  }

  ## ________________________ Option cascade _________________________ ##

  method optionCascadeText {it} {
    # Rids a tk_optionCascade item of braces.
    #   it - an item to be trimmed
    # Reason: tk_optionCascade items shimmer between 'list' and 'string'
    # so a multiline item is displayed with braces, if not got rid of them.
    # Returns the item trimmed.
    # See also: tk_optionCascade

    if {[string match "\{*\}" $it]} {
      set it [string range $it 1 end-1]
    }
    return $it
  }
  #_______________________

  method tk_optionCascade {w vname items {mbopts ""} {precom ""} args} {
    # A bit modified tk_optionCascade widget made by Richard Suchenwirth.
    #   w      - widget name
    #   vname  - variable name for current selection
    #   items  - list of items
    #   mbopts - ttk::menubutton options (e.g. "-width -4")
    #   precom - command to get entry's options (%a presents its label)
    #   args   - additional options of entries
    # Returns a path to the widget.
    # See also:
    #   optionCascadeText
    #   [wiki.tcl-lang.org](https://wiki.tcl-lang.org/page/tk_optionCascade)

    set win $w.m
    if {![info exists $vname]} {
      set it [lindex $items 0]
      while {[llength $it]>1} {set it [lindex $it 0]}
      set it [my optionCascadeText $it]
      set $vname $it
    }
    lassign [::apave::extractOptions mbopts -tip {} -tooltip {} -com {} -command {}] \
      tip tip2 com com2
    if {$tip eq {}} {set tip $tip2}
    if {$com eq {}} {set com $com2}
    if {$com ne {}} {lappend args -command $com}
    ttk::menubutton $w -menu $win -text [set $vname] -style TMenuButtonWest {*}$mbopts
    menu $win -tearoff 0
    my menuTips $win $tip $w
    my OptionCascade_add $win $vname $items $precom {*}$args
    trace add variable $vname write \
      "$w config -text \"\[[self] optionCascadeText \${$vname}\]\" ;\#"
    lappend ::apave::_AP_VARS(_TRACED_$w) $vname
    ::apave::bindToEvent $w <ButtonPress> focus $w
    return $win
  }
  #_______________________

  method OptionCascade_add {w vname argl precom args} {
    # Adds tk_optionCascade items recursively.
    #   w      - tk_optionCascade widget's name
    #   vname  - variable name for current selection
    #   arg1   - list of items to be added
    #   precom - command to get entry's options (%a presents its label)
    #   args   - additional options of entries

    set n [set colbreak 0]
    foreach arg $argl {
      if {$arg eq {--}} {
        $w add separator
      } elseif {$arg eq {|}} {
        if {[tk windowingsystem] ne {aqua}} { set colbreak 1 }
        continue
      } elseif {[llength $arg] == 1} {
        set label [my optionCascadeText [join $arg]]
        if {$precom eq {}} {
          set adds {}
        } else {
          set adds [eval {*}[string map [list \$ \\\$ \[ \\\[] \
            [string map [list %a $label] $precom]]]
        }
        $w add radiobutton -label $label -variable $vname {*}$args {*}$adds
      } else {
        set child [menu $w.[incr n] -tearoff 0]
        $w add cascade -label [lindex $arg 0] -menu $child
        my OptionCascade_add $child $vname [lrange $arg 1 end] $precom {*}$args
      }
      if $colbreak {
        $w entryconfigure end -columnbreak 1
        set colbreak 0
      }
    }
    return
  }
  #_______________________

  method ParentOpt {{w "."}} {
    # Gets *-parent* option for choosers.
    #   w - parent window's name (path)

    if {$Modalwin ne {.}} {set w $Modalwin}
    return "-parent $w"
  }

  ## ________________________ Mega-widgets _________________________ ##

  method fillGutter {txt {canvas ""} {width ""} {shift ""} args} {
    # Fills a gutter of text with the text's line numbers.
    #  txt - path to the text widget
    #  canvas - canvas of the gutter
    #  width - width of the gutter, in chars
    #  shift - addition to the width (to shift from the left side)
    #  args - additional arguments for tracing
    # The code is borrowed from open source tedit project.

    set savedcont [namespace current]::gc$txt
    if {![winfo exists $txt] || ![winfo ismapped $txt]} {
      unset -nocomplain $savedcont
      return
    }
    if {$canvas eq {}} {
      catch {{*}[bind $txt <Configure>]} ;# update gutter
      return
    }
    set oper [lindex $args 0 1]
    if {![llength $args] || [lindex $args 0 4] eq {-elide} || \
    $oper in {configure delete insert see yview}} {
      set i [$txt index @0,0]
      set gcont [list]
      while true {
        set dline [$txt dlineinfo $i]
        if {[llength $dline] == 0} break
        set height [lindex $dline 3]
        set y [expr {[lindex $dline 1]}]
        set linenum [format "%${width}d" [lindex [split $i .] 0]]
        set i [$txt index "$i +1 lines linestart"]
        lappend gcont [list $y $linenum]
      }
      # update the gutter at changing its contents/config
      if {[::apave::cs_Active]} {
        lassign [my csGet] - - - bg - - - - fg
        ::apave::setProperty _GUTTER_FGBG [list $fg $bg]
      } else {
        lassign [::apave::getProperty _GUTTER_FGBG] fg bg
      }
      set cwidth [expr {$shift + \
        [font measure apaveFontMono -displayof $txt [string repeat 0 $width]]}]
      set newbg [expr {$bg ne [$canvas cget -background]}]
      set newwidth [expr {$cwidth ne [$canvas cget -width]}]
      if {![llength $args] || $newbg || $newwidth || ![info exists $savedcont] || \
      $gcont ne [set $savedcont]} {
        if {$newbg} {$canvas config -background $bg}
        if {$newwidth} {$canvas config -width $cwidth}
        $canvas delete all
        foreach g $gcont {
          lassign $g y linenum
          $canvas create text 2 $y -anchor nw -text $linenum -font apaveFontMono -fill $fg
        }
        set $savedcont $gcont
      }
    }
  }
  #_______________________

  method bindGutter {txt canvas {width 5} {shift 3}} {
    # Makes bindings for a text and its gutter.
    #  txt - path to the text widget
    #  canvas - canvas of the gutter
    #  width - width of the gutter, in chars
    #  shift - addition to the width (to shift from the left side)

    set bind [list [self] fillGutter $txt $canvas $width $shift]
    bind $txt <Configure> $bind
    bind $txt <Motion> [list after idle $bind]
    if {[trace info execution $txt] eq {}} {
      trace add execution $txt leave $bind
    }
  }
  #_______________________

  method gutterContents {txt} {
    # Gets contents of a text's gutter
    #   txt - text's path

    set savedcont [namespace current]::gc$txt
    if {[info exists $savedcont]} {
      return [set $savedcont]
    }
    return {}
  }
  #_______________________

  method AuxSetChooserGeometry {vargeo vargeo2 parent widname} {
    # Auxiliary method to set some Tk choosers' geometry.
    #   vargeo - variable for geometry value
    #   vargeo2 - variable for geometry value with second type of dialogue
    #   parent - list containing a parent's path
    #   widname - name of the chooser
    # If there is no saved geometry with *vargeo*, tries to get it with *vargeo2*.
    # Returns a path to the chooser to be open.

    set wp [lindex $parent 1]
    set wchooser $wp.$widname
    set geom {}
    if {[catch {lassign [set $vargeo] -> geom}] || $geom eq {}} {
      # no saved geometry with *vargeo*, so get it with *vargeo2*
      catch {lassign [set $vargeo2] -> geom}
    }
    if {![string match *x*+*+* $geom]} {
      # chooser's default geometry centered in parent
      if {![winfo exists $wp]} {set wp .}
      set geom [set W 640]x[set H 470]
      catch {append geom [my CenteredXY {*}[split [wm geometry $wp] x+] $W $H]}
    }
    if {[::isunix]} {
      # the below equilibristics provides the smooth display
      after idle "catch {wm withdraw $wchooser; wm geometry $wchooser 1x1}"
      after 0 [list after idle \
        "catch {wm withdraw $wchooser; wm geometry $wchooser $geom; wm deiconify $wchooser; wm geometry $wchooser $geom}"]
    }
    return $wchooser
  }
  #_______________________

  method validateColorChoice {lab {ent ""}} {
    # Displays a current color of color chooser's entry.
    #   lab - color chooser's label (or apave name's clr1 / Clr1)
    #   ent - color chooser's entry
    # Can be called as "validateColorChoice clr1 / Clr1".

    if {[string match -nocase clr* $lab]} {
      set lab [string tolower [string index $lab 0]][string range $lab 1 end]
      set ent Ent$lab
      set lab Lab$lab
    }
    set ent [my [my ownWName $ent]]
    set lab [my [my ownWName $lab]]
    set val [$ent get]
    catch {$lab configure -background $val}
    catch {$ent selection clear}
    return yes
  }
  #_______________________

  method scrolledFrame {w args} {
    # Retrieves the path where the scrollable contents of frame go.
    #   w - frame's path

    lassign [::apave::extractOptions args -toplevel no -anchor center -mode both] tl anc mode
    ::apave::sframe new $w -toplevel $tl -anchor $anc -mode $mode
    set path [::apave::sframe content $w]
    return $path
  }
  #_______________________

  method chooserGeomVars {{dirvar ""} {filevar ""}} {
    # Sets/gets variables to save/restore geometry of Tcl/Tk dir/file choosers (in Linux).
    #   dirvar - variable's name for geometry of directory chooser
    #   filevar - variable's name for geometry of file chooser
    # See also: chooser

    if {$dirvar eq {}} {
      return [::apave::getProperty DirFilGeoVars]
    }
    ::apave::setProperty DirFilGeoVars [list $dirvar $filevar]
  }
  #_______________________

  method chooser {nchooser tvar args} {
    # Chooser (for all available types).
    #   nchooser - name of chooser
    #   tvar - name of variable containing an input/output value
    #   args - options of the chooser
    # The chooser names are:
    #   tk_getOpenFile - choose a file to open
    #   tk_getSaveFile - choose a file to save
    #   tk_chooseDirectory - choose a directory
    #   fontChooser - choose a font
    #   dateChooser - choose a date
    #   colorChooser - choose a color
    #   ftx_OpenFile - (internal) choose a file for ftx widget
    # Returns a selected value.

    set isfilename [set rootname 0]
    lassign [apave::extractOptions args \
      -ftxvar {} -tname {} -bname {} -parent {}] ftxvar tname bname parent
    if {$parent ne {}} {
      set parent "-parent $parent"
    } else {
      set parent [my ParentOpt]
    }
    lassign $parent -> wpar
    set wtoplist [my onTop $wpar 1]
    my onTop $wpar 0 $wtoplist ;# do not overlap choosers
    lassign [my chooserGeomVars] dirvar filvar
    if {$dirvar eq {}} {
      set [set dirvar ::apave::APaveDirVar] {}
      set [set filvar ::apave::APaveFilVar] {}
      my chooserGeomVars $dirvar $filvar
    }
    set vargeo {}
    if {$nchooser eq {ftx_OpenFile}} {
      set nchooser tk_getOpenFile
    }
    set widname {}
    set choosname $nchooser
    if {$choosname in {fontChooser colorChooser dateChooser}} {
      set nchooser "my $choosname $tvar $parent $args"
      if {$choosname eq {fontChooser}} {
        append nchooser " -topmost [llength $wtoplist]"
      }
    } elseif {$choosname in {tk_getOpenFile tk_getSaveFile}} {
      set vargeo $filvar
      set widname [my AuxSetChooserGeometry $vargeo $dirvar $parent __tk_filedialog]
      if {[set fn [set $tvar]] eq {}} {
        set dn [pwd]
      } else {
        set dn [file dirname $fn]
        set fn [file tail $fn]
      }
      lassign [apave::extractOptions args -initialdir $dn] dn
      if {[string match -* $dn]} {
        set rootname 1
        set dn [string range $dn 1 end]
      }
      set args [list -initialfile $fn -initialdir $dn {*}$parent {*}$args]
      incr isfilename
    } elseif {$nchooser eq {tk_chooseDirectory}} {
      set vargeo $dirvar
      set widname [my AuxSetChooserGeometry $vargeo $filvar $parent __tk_choosedir]
      set args [list -initialdir [set $tvar] {*}$parent {*}$args]
      incr isfilename
    }
    if {[::isunix] && $choosname ne {dateChooser}} {
      my themeExternal *.foc.* *f1.demo  ;# don't touch tkcc's boxes
    }
    set res [{*}$nchooser {*}$args]
    my onTop $wpar 1 $wtoplist
    if {"$res" ne {} && "$tvar" ne {}} {
      if {$rootname} {set res [file rootname [file tail $res]]}
      if {$isfilename} {
        lassign [my SplitContentVariable $ftxvar] -> txtnam wid
        if {[info exist $ftxvar] && \
        [file exist [set res [file nativename $res]]]} {
          set $ftxvar [apave::readTextFile $res]
          if {[winfo exist $txtnam]} {
            my readonlyWidget $txtnam no
            my displayTaggedText $txtnam $ftxvar
            my readonlyWidget $txtnam yes
            set wid [string range $txtnam 0 [string last . $txtnam]]$wid
            $wid configure -text "$res"
            ::tk::TextSetCursor $txtnam 1.0
            update
          }
        }
      }
      set $tvar $res
    }
    if {$vargeo ne {} && $widname ne {} && [::isunix]} {
      catch {
        set $vargeo [list $widname [wm geometry $widname]]  ;# 1st item for possible usage only
      }
    }
    if {$tname ne {}} {
      set tname [my [my ownWName $tname]]
      if {$bname ne {}} {
        # re-focus to fire invalidation of the entry (esp. for Windows)
        set ent [my ownWName $tname]
        set but [my ownWName $bname]
        set bname [string map [list .$ent .$but] $tname]
        focus $bname
      }
      focus $tname
      after idle "catch {$tname selection range 0 end ; $tname icursor end}"
    }
    return $res
  }
  #_______________________

  method colorChooser {tvar args} {
    # Color chooser.
    #   tvar - name of variable containing a color
    #   args - options of *tk_chooseColor*
    # The *tvar* sets the value of *-initialcolor* option. Also
    # it gets a color selected in the chooser.
    # Returns a selected color.

    if {$Initialcolor eq {} && [::isunix]} {
      source [file join $::apave::apaveDir pickers color clrpick.tcl]
    }
    lassign [apave::extractOptions args -entry {} -inifile {} -ontop 0] ent ini top
    if {$ent ne {}} {
      set ent [my [my ownWName $ent]]
      set x [winfo rootx $ent]
      set y [expr {[winfo rooty $ent]+32}]
      dict set args -geometry +$x+$y  ;# the same as with date picker
    }
    if {[set _ [string trim [set $tvar]]] ne {}} {
      set ic $_
      set _ [. cget -background]
      if {[catch {. configure -background $ic}]} {
        set ic "#$ic"
        if {[catch {. configure -background $ic}]} {set ic black}
      }
      set Initialcolor $ic
      . configure -background $_
    } else {
      set Initialcolor black
    }
    if {[catch {lassign [tk_chooseColor -moveall $Moveall \
    -initialcolor $Initialcolor {*}$args -inifile $ini -ontop $top] res Moveall}]} {
      set args [apave::removeOptions $args -moveall -tonemoves -geometry]
      set res [tk_chooseColor -initialcolor $Initialcolor {*}$args]
    }
    if {$res ne {}} {
      set Initialcolor [set $tvar $res]
    }
    return $res
  }
  #_______________________

  method sourceKlnd {{num ""}} {
    # Loads klnd package at need.
    #   num - defines which name of package file to be used

    if {[info commands ::klnd::calendar$num] eq {}} {
      # imo, it's more effective to source on request than to require on possibility
      source [file join $::apave::apaveDir pickers klnd klnd$num.tcl]
    }
  }
  #_______________________

  method dateChooser {tvar args} {
    # Date chooser (calendar widget).
    #   tvar - name of variable containing a date
    #   args - options of *::klnd::calendar*
    # Returns a selected date.

    my sourceKlnd {}
    if {![catch {set ent [my [my ownWName [apave::getOption -entry {*}$args]]]}]} {
      dict set args -entry $ent
      set res [::klnd::calendar {*}$args -tvar $tvar -parent [winfo toplevel $ent]]
    } else {
      set res [::klnd::calendar {*}$args -tvar $tvar]
    }
    return $res
  }
  #_______________________

  method Replace_Tcl {r1 r2 r3 args} {
    # Replaces Tcl code with its resulting items in *lwidgets* list.
    #   r1 - variable name for a current index in *lwidgets* list
    #   r2 - variable name for a length of *lwidgets* list
    #   r3 - variable name for *lwidgets* list
    #   args - "tcl" and "tcl code" for "tcl" type of widget
    # The code should use the wildcard that goes first at a line:
    #   %C - a command for inserting an item into lwidgets list.
    # The "tcl" widget type can be useful to automate the inserting
    # a list of similar widgets to the list of widgets.
    # See tests/test2_pave.tcl where the "tcl" fills "Color schemes" tab.

    lassign $args _name _code
    if {[my ownWName $_name] ne {tcl}} {return $args}
    upvar 1 $r1 _ii $r2 _lwlen $r3 _lwidgets
  ; proc lwins {lwName i w} {
      upvar 2 $lwName lw
      set lw [linsert $lw $i $w]
    }
    set _lwidgets [lreplace $_lwidgets $_ii $_ii]  ;# removes tcl item
    set _inext [expr {$_ii-1}]
    eval [string map {%C {lwins $r3 [incr _inext] }} $_code]
    return {}
  }
  #_______________________

  method Replace_chooser {r0 r1 r2 r3 args} {
    # Replaces an item for a chooser with two items.
    #   r0 - variable name for a widget's name
    #   r1 - variable name for a current index in *lwidgets* list
    #   r2 - variable name for a length of *lwidgets* list
    #   r3 - variable name for *lwidgets* list
    #   args - the widget item of *lwidgets* list
    # Choosers should contain 2 fields: entry + button.
    # Here every chooser is replaced with these two widgets.

    upvar 1 $r0 w $r1 i $r2 lwlen $r3 lwidgets
    lassign $args name neighbor posofnei rowspan colspan options1 attrs1
    lassign {} wpar view addattrs addattrs2
    lassign [::apave::parseOptions $attrs1 -tvar {-} -validatecommand {}] tvar validatecommand
    lassign [::apave::extractOptions attrs1 -takefocus 0 -showcolor {} -filetypes {} \
      -initialdir {} -initialfile {} -defaultextension {} -multiple {}] \
      takefocus showcolor filetypes initialdir initialfile defaultextension multiple
    lassign [::apave::extractOptions options1 -padx 0 -pady 0] padx pady
    set takefocus "-takefocus $takefocus"
    foreach atr {filetypes initialdir initialfile defaultextension multiple} {
      set val [set $atr]
      if {$val ne {}} {
        lset args 6 $attrs1
        append addattrs2 " -$atr {$val}"
      }
    }
    set an [set entname {}]
    lassign [my LowercaseWidgetName $name] n
    set ownname [my ownWName $n]
    set wtyp [string range $ownname 0 2]
    switch -exact $wtyp {
      daT { ;# embed calendar widgets into $ownname frame
        my sourceKlnd
        my sourceKlnd 2
        set attrs1 [subst $attrs1]
        set lwidgets2 [::klnd::calendar2 [self] $w $n {*}$attrs1]
        set lwlen2 [llength $lwidgets2]
        for {set i2 0} {$i2 < $lwlen2} {} {
          set lst2 [lindex $lwidgets2 $i2]
          if {[my Replace_Tcl i2 lwlen2 lwidgets2 {*}$lst2] ne {}} {incr i2}
        }
        incr lwlen [llength $lwidgets2]
        set lwidgets [linsert $lwidgets [expr {$i+1}] {*}$lwidgets2]
        lset args 6 [::klnd::clearArgs {*}$attrs1]
        return $args
      }
      fil - fiL {set chooser tk_getOpenFile}
      fis - fiS {set chooser tk_getSaveFile}
      dir - diR {set chooser tk_chooseDirectory}
      fon - foN {set chooser fontChooser}
      clr - clR {
        set chooser colorChooser
        if {$showcolor eq {}} {set showcolor 1} ;# default is "show color label"
        set showcolor [string is true -strict $showcolor]
        set wpar "-parent $w" ;# specific for color chooser (parent of $w)
        set entname {-entry }
      }
      dat {set chooser dateChooser; set entname {-entry }}
      ftx {
        set chooser [set view ftx_OpenFile]
        if {$tvar ne {} && [info exist $tvar]} {
          append addattrs " -t {[set $tvar]}"
        }
        set an tex
        set txtnam [my Transname $an $name]
      }
      default {
        return $args
      }
    }
    set inname [my MakeWidgetName $w $name $an]
    set name $n
    if {$view ne {}} {
      set tvname $inname
      set inname [my WidgetNameFull $w $name]
    }
    set tvar [set vv [set addopt {}]]
    set attmp [list]
    foreach {nam val} $attrs1 {
      if {$nam in {-title -parent -dateformat -weekday -modal -centerme}} {
        append addopt " $nam \{$val\}"
      } else {
        lappend attmp $nam $val
      }
    }
    set attrs1 $attmp
    catch {array set a $attrs1; set tvar "-tvar [set vv $a(-tvar)]"}
    catch {array set a $attrs1; set tvar "-tvar [set vv $a(-textvariable)]"}
    if {$vv eq {}} {
      set vv [namespace current]::$name
      set tvar "-tvar $vv"
    }
    # make a frame in the widget list
    set ispack 0
    if {![catch {set gm [lindex [lindex $lwidgets $i] 5]}]} {
      set ispack [expr [string first pack $gm]==0]
    }
    if {$ispack} {
      lassign [::apave::parseOptions $options1 -expand 0 -fill x] exp fil
      set args [list $name - - - - \
        "pack -expand $exp -fill $fil [string range $gm 5 end]" $addattrs]
    } else {
      lassign [::apave::parseOptions $options1 -st ew -sticky {} -rw {} -cw {}] st st2 rw cw
      if {$st2 ne {}} {set st $st2}
      if {$rw ne {}} {set rw "-rw $rw"}
      if {$cw ne {}} {set cw "-cw $cw"}
      set args [list $name $neighbor $posofnei $rowspan $colspan \
        "-st $st $rw $cw" $addattrs]
    }
    lset lwidgets $i $args
    set btTname [my Transname btT $name]
    if {$view ne {}} {
      append attrs1 " -callF2 {.texF .btTf .texf .btTf}"
      set tvar [::apave::getOption -tvar {*}$attrs1]
      set attrs1 [::apave::removeOptions $attrs1 -tvar]
      if {$tvar ne {} && [file exist [set $tvar]]} {
        set tcont [my SetContentVariable $tvar $tvname [my ownWName $name]]
        set wpar "-ftxvar $tcont"
        set $tcont [::apave::readTextFile [set $tvar]]
        set attrs1 [::apave::putOption -rotext $tcont {*}$attrs1]
      }
      set entf [list $txtnam - - - - "pack -side top -expand 1 -fill both -in $inname" "$attrs1"]
    } else {
      if {$wtyp in {fiL fiS diR foN clR}} {
        set field cbx
        set tname [my Transname Cbx $name]
      } else {
        set tname [my Transname Ent $name]
        set field ent
      }
      if {$entname ne {}} {append entname $tname}
      append attrs1 " -callF2 {.$field .btT}"
      append wpar " -tname $tname -bname $btTname"
      if {$chooser eq {fontChooser}} {
        append wpar " -parent \[[self] [my ownWName $tname]\]"
      }
      set entf [list $tname - - - - "pack -padx $padx -pady $pady -side left -expand 1 -fill x -in $inname" "$attrs1 $tvar"]
    }
    set icon folder
    foreach ic {OpenFile SaveFile font color date} {
      if {[string first $ic $chooser] >= 0} {set icon $ic; break}
    }
    set com "[self] chooser $chooser \{$vv\} $addopt $wpar $addattrs2 $entname"
    if {$view ne {}} {set anc n} {set anc center}
    set butf [list $btTname - - - - "pack -side right -anchor $anc -in $inname -padx 2" "-com \{$com\} -compound none -image [::apave::iconImage $icon small] -font \{-weight bold -size 5\} -fg $Fgbut -bg $Bgbut $takefocus"]
    if {$view ne {}} {
      set scrolv [list [my Transname sbv $name] $txtnam L - - "pack -in $inname -side bottom -after [my WidgetNameFull $w $btTname]" {}]
      set lwidgets [linsert $lwidgets [expr {$i+1}] $butf]
      set lwidgets [linsert $lwidgets [expr {$i+2}] $entf]
      set lwidgets [linsert $lwidgets [expr {$i+3}] $scrolv]
      incr lwlen 3
      set wrap [::apave::getOption -wrap {*}$attrs1]
      if {$wrap eq {none}} {
        set scrolh [list [my Transname sbh $name] $txtnam T - - "pack -in $inname -side bottom -after [my WidgetNameFull $w $txtnam]" {}]
        set lwidgets [linsert $lwidgets [expr {$i+3}] $scrolh]
        incr lwlen
      }
    } else {
      if {$chooser eq {colorChooser} && $showcolor} {
        set f0 [my Transname Lab $name]
        set labf [list $f0 - - - - "pack -side right -in $inname -padx 2" \
          "-t \{    \} -relief raised"]
        lassign $entf f1 - - - - f2 f3
        set com "[self] validateColorChoice $f0 $f1"
        append f3 " -afteridle \"$com; bind \[string map \{.entclr .labclr\} %w\] <ButtonPress> \{eval \[string map \{.entclr .btTclr\} %w\] invoke\}\""
        append f3 " -validate all -validatecommand \{$com ; $validatecommand\}"
        set entf [list $f1 - - - - $f2 $f3]
        set lwidgets [linsert $lwidgets [expr {$i+1}] $entf $butf $labf]
        incr lwlen 3
      } else {
        set lwidgets [linsert $lwidgets [expr {$i+1}] $entf $butf]
        incr lwlen 2
      }
    }
    return $args
  }
  #_______________________

  method Replace_bar {r0 r1 r2 r3 args} {
    # Replaces an item for a menu/tool/status bar with appropriate items.
    #   r0 - variable name for a widget's name
    #   r1 - variable name for a current index in *lwidgets* list
    #   r2 - variable name for a length of *lwidgets* list
    #   r3 - variable name for *lwidgets* list
    #   args - the widget item of *lwidgets* list
    # Bar widgets should contain N fields of appropriate type

    upvar 1 $r0 w $r1 i $r2 lwlen $r3 lwidgets
    if {[catch {set winname [winfo toplevel $w]}]} {
      return $args
    }
    lassign $args name neighbor posofnei rowspan colspan options1 attrs1
    my MakeWidgetName $w $name
    set name [lindex [my LowercaseWidgetName $name] 0]
    set wpar {}
    switch -glob -- [my ownWName $name] {
      men* {set typ menuBar}
      too* {set typ toolBar}
      sta* {set typ statusBar}
      default {
        return $args
      }
    }
    set attcur [list]
    set namvar [list]
    # get array of pairs (e.g. image-command for toolbar)
    foreach {nam val} $attrs1 {
      if {$nam eq {-array}} {
        catch {set val [subst $val]}
        set ind -1
        foreach {v1 v2} $val {
          catch {set v1 [subst -nocommand -nobackslash $v1]}
          catch {set v2 [subst -nocommand -nobackslash $v2]}
          if {$name eq {menu}} {set v2 [list [my MC $v2]]}
          lappend namvar [namespace current]::$typ[incr ind] $v1 $v2
        }
      } else {
        lappend attcur $nam $val
      }
    }
    # make a frame in the widget list
    if {$typ eq {menuBar}} {
      if {[set fillmenu [lindex $args 7]] ne {}} {
        after idle $fillmenu
      }
      set args {}
    } else {
      set ispack 0
      if {![catch {set gm [lindex [lindex $lwidgets $i] 5]}]} {
        set ispack [expr [string first pack $gm]==0]
      }
      if {$ispack} {
        set args [list $name - - - - "pack -expand 0 -fill x -side bottom [string range $gm 5 end]" $attcur]
      } else {
        set args [list $name $neighbor $posofnei $rowspan $colspan "-st ew" $attcur]
      }
      lset lwidgets $i $args
    }
    lassign [my csGet] fga fg bga bg
    set fontB [my boldTextFont 16]
    set fontS [my basicSmallFont]
    set itmp $i
    set k [set j [set j2 [set wasmenu 0]]]
    foreach {nam v1 v2} $namvar {
      if {[string first # $v1]==0} continue
      if {$v1 eq {h_}} {  ;# horisontal space
        set ntmp [my Transname fra ${name}[incr j2]]
        set wid1 [list $ntmp - - - - "pack -side left -in $w.$name -fill y"]
        set wid2 [list $ntmp.[my ownWName [my Transname h_ $name$j]] - - - - "pack -fill y -expand 1 -padx $v2"]
      } elseif {$v1 eq {sev}} {   ;# vertical separator
        set ntmp [my Transname fra ${name}[incr j2]]
        set wid1 [list $ntmp - - - - "pack -side left -in $w.$name -fill y"]
        set wid2 [list $ntmp.[my ownWName [my Transname sev $name$j]] - - - - "pack -fill y -expand 1 -padx $v2"]
      } elseif {$typ eq {statusBar}} {  ;# statusbar
        my NormalizeName name i lwidgets
        set dattr [lrange $v1 1 end]
        if {[::apave::extractOptions dattr -expand 0]} {
          set expand {-expand 1 -fill x}
        } else {
          set expand {}
        }
        set font " -font {$fontS}"
        # status prompt
        set wid1 [list .[my ownWName [my Transname Lab ${name}_[incr j]]] - - - - "pack -side left -in $w.$name" "-t {[lindex $v1 0]} $font $dattr"]
        # status value
        if {$::apave::_CS_(LABELBORDER)} {set relief sunken} {set relief flat}
        set wid2 [list .[my ownWName [my Transname Lab $name$j]] - - - - "pack -side left $expand -in $w.$name" "-style TLabelSTD -relief $relief -w $v2 -t { } $font $dattr"]
      } elseif {$typ eq {toolBar}} {  ;# toolbar
        set packreq {}
        switch -nocase -glob -- $v1 {
          lab* - laB* { ;# label
            lassign $v2 txt packreq att
            set v2 "-text {$txt} $att"
          }
          opc* { ;# tk_optionCascade
            lset v2 2 "[lindex $v2 2] -takefocus 0"
          }
          spx* - chb* - ent* - cbx* { ;# spinbox etc.
            set v2 "$v2 -takefocus 0"
          }
          default {
            if {[string is lower [string index $v1 0]]} { ;# button with -image
              set but buT
            } else {
              set but BuT
            }
            set v2 "[my toolbarItem_Attrs [string match _* $v1] $v1 $fontB \
              $fg $bg $fga $bga] -command $v2"
            lassign [::apave::extractOptions v2 -method {}] ismeth
            set v1 [my Transname $but _$v1]
            if {[string is true -strict $ismeth]} {
              # -method option forces making "WidgetName" method from "widgetName"
              my MakeWidgetName $w.$name [string totitle $v1 0 0]
            }
          }
        }
        set wid1 [list $name.$v1 - - - - "pack -side left $packreq" $v2]
        if {[incr wasseh]==1} {
          ;# horiz.separator for multiline toolbar
          set wid2 [list [my Transname seh $name$j] - - - - "pack -side top -fill x"]
        } else {
          ;# 1st line of toolbar
          set lwidgets [linsert $lwidgets [incr itmp] $wid1]
          continue
        }
      } elseif {$typ eq {menuBar}} {
        ;# menubar: making it here; filling it outside of 'pave window'
        if {[incr wasmenu]==1} {
          set menupath [my MakeWidgetName $winname $name]
          menu $menupath -tearoff 0
        }
        set menuitem [my MakeWidgetName $menupath $v1]
        menu $menuitem -tearoff 0
        set ampos [string first & [string trimleft $v2  \{]]
        if {$ampos>=0} {append v2 " -underline $ampos"}
        set v2 [string map {& {}} $v2]
        $menupath add cascade -label [lindex $v2 0] {*}[lrange $v2 1 end] -menu $menuitem
        continue
      } else {
        error "\npaveme.tcl: erroneous \"$v1\" for \"$nam\"\n"
      }
      set lwidgets [linsert $lwidgets [incr itmp] $wid1 $wid2]
      incr itmp
    }
    if {$wasmenu} {
      $winname configure -menu $menupath
    }
    incr lwlen [expr {$itmp - $i}]
    return $args
  }
  #_______________________

  method fontChooser {tvar args} {
    # Font chooser.
    #   tvar - name of variable containing a font
    #   args - options of *tk fontchooser*
    # The *tvar* sets the value of *-font* option. Also
    # it gets a font selected in the chooser.
    # Returns a selected font.

    set top [apave::extractOptions args -topmost 0]
    set parw [apave::parseOptions $args -parent [::apave::rootModalWindow .]]
  ; proc [namespace current]::applyFont {font} " \
      set $tvar \[font actual \$font\]; \
      focus -force $parw"
    set font [set $tvar]
    if {$font eq {}} {
      catch {font create fontchoose {*}$::apave::FONTMAIN}
    } else {
      catch {font delete fontchoose}
      catch {font create fontchoose {*}[font actual $font]}
    }
    tk fontchooser configure -font fontchoose {*}[my ParentOpt] \
      {*}$args -command [namespace current]::applyFont
    tk fontchooser show
    # core Tk font chooser is bad with focusing in and out, it isn't modal
    if {[set foc [info commands *__tk__fontchooser.ok]] ne {}} {
      after idle [list after 0 [list catch "focus -force $foc"]]
      catch {wm attributes [winfo toplevel $foc] -topmost $top}
    }
    set $tvar
  }
  #_______________________

  method toolbarItem_Attrs {istext img fontB fg bg fga bga} {
    # Gets default attributes of toolbar button.
    #   istext - true if textual button
    #   img - image of button
    #   fontB - bold font
    #   fg - foreground
    #   bg - background
    #   fga - active foreground
    #   bga - active background

    if {$istext} {
      set img "-font {$fontB} -foreground $fg -background $bg -width 2 -pady 0 -padx 2"
    } else {
      set img "-image $img -background $bg"
    }
    append img " -relief flat -overrelief raised -activeforeground $fga \
      -activebackground $bga -highlightthickness 0 -takefocus 0"
  }

  ## ________________________ Widget names & methods _________________________ ##

  method chooserPath {W {w ent}} {
    # Gets a path to chooser's entry or label.
    #   W - widget/method name (e.g. Fil, Dir)
    #   w - ent / lab for entry / label

    ::apave::precedeWidgetName [my $W] $w
  }
  #_______________________

  method Transname {typ name} {
    # Transforms *name* by adding *typ* (its type).
    #   typ - type of widget in *apave* terms (but, buT etc.)
    #   name - name (path) of widget
    # Returns the transformed name.

    if {[set pp [string last . $name]]>-1} {
      set name [string range $name 0 $pp]$typ[string range $name $pp+1 end]
    } else {
      set name $typ$name
    }
    return $name
  }
  #_______________________

  method LowercaseWidgetName {name} {
    # Makes the widget name lowercased.
    #   name - widget's name
    # The widgets of widget list can have uppercased names which
    # means that the appropriate methods will be created to access
    # their full pathes with a command `my Name`.
    # This method gets a "normal" name of widget accepted by Tk.
    # See also: MakeWidgetName

    set root [my ownWName $name]
    list [string range $name 0 [string last . $name]][string tolower $root 0 0] $root
  }
  #_______________________

  method NormalizeName {refname refi reflwidgets} {
    # Gets the real name of widget from *.name*.
    #   refname - variable name for widget name
    #   refi - variable name for index in widget list
    #   reflwidgets - variable name for widget list
    # The *.name* means "child of some previous" and should be normalized.
    # Example:
    #   If parent: fra.fra .....
    #      child: .but
    #   => normalized: fra.fra.but

    upvar $refname name $refi i $reflwidgets lwidgets
    set wname $name
    if {[string index $name 0] eq {.}} {
      for {set i2 [expr {$i-1}]} {$i2 >=0} {incr i2 -1} {
        lassign [lindex $lwidgets $i2] name2
        if {[string index $name2 0] ne {.}} {
          set name2 [lindex [my LowercaseWidgetName $name2] 0]
          set wname "$name2$name"
          set name [lindex [my LowercaseWidgetName $name] 0]
          set name "$name2$name"
          break
        }
      }
    }
    list $name $wname
  }
  #_______________________

  method WidgetNameFull {w name {an {}}} {
    # Gets a full name of a widget.
    #   w - name of root widget
    #   name - name of widget
    #   an - additional prefix for name
    # See also: apave::sframe::content

    set wn [string trim [my parentWName $name].$an[my ownWName $name] .]
    set wnamefull $w.$wn
    set wcc canvas.container.content ;# sframe.tcl may be not sourced
    if {[set i1 [string first .scf $wnamefull]]>0 && \
    [set i2 [string first . $wnamefull $i1+1]]>0 && \
    [string first .$wcc. $wnamefull]<0} {
      # insert a container's name into a scrolled frame's child
      set wend [string range $wnamefull $i2 end]
      set wnamefull [string range $wnamefull 0 $i2]
      append wnamefull $wcc $wend
    }
    return $wnamefull
  }
  #_______________________

  method dlgPath {} {
    # Gets a window name of apave open dialogue.

    if {[catch {set res $Dlgpath}] || $Dlgpath eq {}} {
      set res $::apave::MODALWINDOW
    }
    return $res
  }
  #_______________________

  method DiaWidgetName {w} {
    # Gets a widget name of apave dialogue.
    #   w - name of widget
    # The name of widget may be partial. In this case it's prepended
    # the current dialogue's frame path.
    # Useful in "input" dialogue when -method option is present
    # or widget names are uppercased.
    # See also: MakeWidgetName, input

    if {[string index $w 0] eq {.}} {return $w}
    return $Dlgpath.fra.$w
  }
  #_______________________

  method MakeWidgetName {w name {an {}}} {
    # Makes an exported method named after root widget, if it's uppercased.
    #   w - name of root widget
    #   name - name of widget
    #   an - additional prefix for name (if "-", $w is full/partial name)
    # The created method used for easy access to the widget's path.
    # Example:
    #   fra1.fra2.fra3.Entry1
    #   => method Entry1 {} {...}
    #   ...
    #   my Entry1  ;# instead of .win.fra1.fra2.fra3.Entry1

    if {$an eq {-}} {
      set wnamefull "\[my DiaWidgetName $w\]"
    } else {
      set wnamefull [my WidgetNameFull $w $name $an]
      lassign [my LowercaseWidgetName $wnamefull] wnamefull
    }
    set method [my ownWName $name]
    set root1 [string index $method 0]
    if {[string is upper $root1]} {
      oo::objdefine [self] "method $method {} {return $wnamefull} ; \
        export $method"
    }
    return $wnamefull
  }
  #_______________________

  method AddPopupAttr {w attrsName atRO isRO args} {
    # Adds the attribute to call a popup menu for an editable widget.
    #   w - widget's name
    #   attrsName - variable name for attributes of widget
    #   atRO - "readonly" attribute (internally used)
    #   isRO - flag of readonly widget
    #   args - widget states to be checked

    upvar 1 $attrsName attrs
    lassign $args state state2
    if {$state2 ne {}} {
      if {[::apave::getOption -state {*}$attrs] eq $state2} return
      set isRO [expr {$isRO || [::apave::getOption -state {*}$attrs] eq $state}]
    }
    if {$isRO} {append atRO RO}
    append attrs " $atRO $w"
  }
  #_______________________

  method clearEntry {w clearcom} {
    # Clears entry-like widget's value, after calling a command.
    #   w - widget's path
    #   clearcom - a command to call, can have %w for *w* (widget's path)

    if {$clearcom ne {}} {
      {*}[string map [list %w $w %p [self]] $clearcom]
    }
    #! perhaps, needs refactoring:
    if {[catch {$w delete 0 end}]} { ;# entry
      if {[catch {$w set {}}]} {     ;# combobox
        # others
      }
    }
  }
  #_______________________

  method makePopup {w {isRO no} {istext no} {tearoff no} {addpop ""} {clearcom ""}} {
    # Makes a popup menu for an editable widget.
    #   w - widget's name
    #   isRO - flag for "is it readonly"
    #   istext - flag for "is it a text"
    #   tearoff - flag for "-tearoff" option
    #   addpop - additional commands for popup menu
    #   clearcom - command for "Clear" item

    set pop $w.popupMenu
    catch {menu $pop -tearoff $tearoff}
    $pop delete 0 end
    if {$isRO || [$w cget -state] eq {disabled}} {
      $pop add command {*}[my iconA copy] -accelerator Ctrl+C -label Copy \
        -command "event generate $w <<Copy>>"
      if {$istext} {
        eval [my popupHighlightCommands $pop $w]
        after idle [list [self] set_highlight_matches $w]
      }
    } else {
      if {$istext} {
        ::apave::bindToEvent $w <<Copy>> ::apave::eventOnText $w <<Copy>>
        ::apave::bindToEvent $w <<Cut>> ::apave::eventOnText $w <<Cut>>
        $pop add command {*}[my iconA cut] -accelerator Ctrl+X -label Cut \
          -command "event generate $w <<Cut>>"
        $pop add command {*}[my iconA copy] -accelerator Ctrl+C -label Copy \
          -command "event generate $w <<Copy>>"
        $pop add command {*}[my iconA paste] -accelerator Ctrl+V -label Paste \
          -command "::apave::eventOnText $w <<Paste>>"
        $pop add separator
        $pop add command {*}[my iconA undo] -accelerator Ctrl+Z -label Undo \
          -command "::apave::eventOnText $w <<Undo>>"
        $pop add command {*}[my iconA redo] -accelerator Ctrl+Shift+Z -label Redo \
          -command "::apave::eventOnText $w <<Redo>>"
        catch {
          eval [my popupBlockCommands $pop $w]
          eval [my popupHighlightCommands $pop $w]
          if {$addpop ne {}} {
            lassign $addpop com par1 par2
            eval [my $com $pop $w {*}$par1 {*}$par2]
          }
          after idle [list [self] set_highlight_matches $w]
          after idle [my setTextBinds $w]
        }
      } else {
        if {$clearcom ne {}} {
          $pop add command {*}[my iconA no] -label Clear \
            -command [list [self] clearEntry $w $clearcom]
          $pop add separator
        }
        $pop add command {*}[my iconA cut] -accelerator Ctrl+X -label Cut \
          -command "event generate $w <<Cut>>"
        $pop add command {*}[my iconA copy] -accelerator Ctrl+C -label Copy \
          -command "event generate $w <<Copy>>"
        $pop add command {*}[my iconA paste] -accelerator Ctrl+V -label Paste \
          -command "event generate $w <<Paste>>"
      }
    }
    if {$istext} {
      $pop add separator
      $pop add command {*}[my iconA none] -accelerator Ctrl+A -label {Select All} \
        -command "$w tag add sel 1.0 end"
      bind $w <Control-a> "$w tag add sel 1.0 end; break"
    }
    bind $w <Button-3> "[self] themePopup $w.popupMenu; tk_popup $w.popupMenu %X %Y"
  }
  #_______________________

  method Pre {refattrs} {
    # "Pre" actions for the text widget and similar
    # which all require some actions before and after their creation e.g.:
    #   the text widget's text cannot be filled if disabled
    #   so, we must act this way:
    #     1. call Pre - to get a text of widget
    #     2. create the widget
    #     3. call Post - to enable, then fill it with a text, then disable it
    # It's only possible with Pre and Post methods.
    # See also: Post

    upvar 1 $refattrs attrs
    set attrs_ret [set Prepost [list]]
    foreach {a v} $attrs {
      switch -exact -- $a {
        -disabledtext - -rotext - -lbxsel - -cbxsel - -notebazook - \
        -entrypop - -entrypopRO - -textpop - -textpopRO - -ListboxSel - \
        -callF2 - -timeout - -bartabs - -onReturn - -linkcom - -selcombobox - \
        -afteridle - -gutter - -propagate - -columnoptions - -selborderwidth -
        -selected - -popup - -bindEC - -tags - -debug - -clearcom {
          # attributes specific to apave, processed below in "Post"
          set v2 [string trimleft $v \{]
          set v2 [string range $v2 0 end-[expr {[string length $v]-[string length $v2]}]]
          lappend Prepost [list $a $v2]
        }
        -myown {
          lappend Prepost [list $a [subst $v]]
        }
        -labelwidget { ;# widget path as a method
          set v [string trim $v \{\}]
          catch {set v [my $v]}
          lappend attrs_ret $a $v
        }
        default {
          lappend attrs_ret $a $v
        }
      }
    }
    set attrs $attrs_ret
  }
  #_______________________

  method Post {w attrs} {
    # Performes "post" actions after creation a widget.
    #   w - widget's path
    #   attrs - widget's attributes
    # Processes the same *apave* options that are processed in Pre method.
    # See also: Pre

    if {[set i [lsearch -exact -index 0 $Prepost -tags]]>-1} {
      set v [lindex $Prepost $i 1]
      set tags [set $v]
    } else {
      set tags {}
    }
    foreach pp $Prepost {
      lassign $pp a v
      set v [string trim $v $::apave::UFF]
      switch -exact -- $a {
        -disabledtext {
          $w configure -state normal
          my displayTaggedText $w v $tags
          $w configure -state disabled
          my readonlyWidget $w no
        }
        -rotext {
          if {[info exist v]} {
            if {[info exist $v]} {
              my displayTaggedText $w $v $tags
            } else {
              my displayTaggedText $w v $tags
            }
          }
          my readonlyWidget $w yes
        }
        -lbxsel {
          set v [lsearch -glob [$w get 0 end] "$v*"]
          if {$v>=0} {
            $w selection set $v
            $w yview $v
            $w activate $v
          }
          my UpdateSelectAttrs $w
        }
        -cbxsel {
          set cbl [$w cget -values]
          set v [lsearch -glob $cbl "$v*"]
          if {$v>=0} { $w set [lindex $cbl $v] }
        }
        -ListboxSel {
          bind $v <<ListboxSelect>> [list [namespace current]::ListboxSelect %W]
        }
        -entrypop - -entrypopRO {
          if {[winfo exists $v]} {
            my makePopup $v [expr {$a eq {-entrypopRO}}]
          }
        }
        -clearcom {
          my makePopup $w no no no {} $v   ;# popup menu with "Clear" command
        }
        -textpop - -textpopRO {
          if {[winfo exists $v]} {
            set ro [expr {$a eq {-textpopRO}}]
            my makePopup $v $ro yes
            set w $v
          } elseif {[string length $v]>5} {
            my makePopup $w no yes no $v
          }
          $w tag configure sel -borderwidth 1
        }
        -notebazook {
          foreach {fr attr} $v {
            if {[string match -tr* $fr]} {
              if {[string is boolean -strict $attr] && $attr} {
                ttk::notebook::enableTraversal $w
              }
            } elseif {[string match -sel* $fr]} {
              $w select $w.$attr
            } elseif {![string match #* $fr]} {
              set attr [my GetMC $attr]
              set attr [subst $attr]
              lassign [::apave::extractOptions attr -tip {} -tooltip {}] tip t2
              set wt [my MakeWidgetName $w $fr]
              $w add [ttk::frame $wt] {*}$attr
              catch {$wt config -takefocus 0}
              if {[append tip $t2] ne {}} {
                set tip [my MC $tip]
                ::baltip::tip $w $tip -nbktab $wt
              }
            }
          }
        }
        -gutter {
          lassign [::apave::parseOptions $v -canvas Gut -width 5 -shift 6] canvas width shift
          if {![winfo exists $canvas]} {set canvas [my $canvas]}
          my bindGutter $w $canvas $width $shift
        }
        -onReturn {   ;# makes a command run at Enter key pressing
          lassign $v cmd from to
          if {[set tvar [$w cget -textvariable]] ne {}} {
            if {$from ne {}} {
              set cmd "if {\$$tvar < $from} {set $tvar $from}; $cmd"
            }
            if {$to ne {}} {
              set cmd "if {\$$tvar >$to} {set $tvar $to}; $cmd"
            }
          }
          foreach k {<Return> <KP_Enter>} {
            if {$v ne {}} {bind $w $k $cmd}
          }
        }
        -linkcom {
          lassign [my csGet] fg fg2 bg bg2
          my makeLabelLinked $w $v $fg $bg $fg2 $bg2 yes yes
        }
        -callF2 {
          if {[llength $v]==1} {set w2 $v} {set w2 [string map $v $w]}
          ::apave::bindToEvent $w <F2> $w2 invoke
        }
        -bindEC {
          set v [string map [list %w $w] $v]
          lassign $v ev com
          ::apave::bindToEvent $w $ev {*}$com
          switch -exact -- [winfo class $w] {
            Treeview {
              ::apave::bindToEvent $w <ButtonPress> selection clear
              ::apave::bindToEvent $w <KeyPress> selection clear
            }
            Listbox {
              ::apave::bindToEvent $w <ButtonPress> selection clear
              ::apave::bindToEvent $w <KeyPress> selection clear
            }
          }
        }
        -timeout {
          lassign $v timo lbl
          after idle [list [self] timeoutButton $w $timo $lbl]
        }
        -myown {
          eval {*}[string map [list %w $w] $v]
        }
        -bartabs {
          after 10 [string map [list %w $w] $v]
        }
        -afteridle {
          after idle [string map [list %w $w] $v]
        }
        -propagate {
          if {[lindex $v 0] in {add pack}} {
            pack propagate $w 0
          } else {
            grid propagate $w 0
          }
        }
        -columnoptions {
          foreach {col opts} $v {
            $w column $col {*}$opts
          }
        }
        -selborderwidth {
          $w tag configure sel -borderwidth $v
        }
        -selcombobox {
          bind $w <<ComboboxSelected>> $v
        }
        -selected {
          if {[string is true $v]} {
            after idle "$w selection range 0 end"
          }
        }
        -popup {
          after 50 "bind $w <Button-3> {$v}" ;# redefines other possible popups
        }
        -debug {
          if {$v} {
            # puts out the widget's name and (if exists) its method
            set method [string toupper [my ownWName $w] 0]
            if {$method in [info object methods [self]]} {
              set method "  METHOD: $method"
            } else {
              set method {}
            }
            puts "WIDGET: $w $method"
          }
        }
      }
    }
  }
  #_______________________

  method CleanUps {{wr ""}} {
    # Performs various clean-ups before and after showing a window.
    #   wr - window's path (to clean up at closing)

    # Cleans the unused widgets from _AP_VISITED list
    for {set i [llength $::apave::_AP_VISITED(ALL)]} {[incr i -1]>=0} {} {
      if {![winfo exists [lindex $::apave::_AP_VISITED(ALL) $i 0]]} {
        set ::apave::_AP_VISITED(ALL) [lreplace $::apave::_AP_VISITED(ALL) $i $i]
      }
    }
    if {$wr ne {}} {
      for {set i [llength $::apave::_AP_VARS(TIMW)]} {[incr i -1]>=0} {} {
        set w [lindex $::apave::_AP_VARS(TIMW) $i]
        if {[string first $wr $w]==0 && ![catch {::baltip::hide $w}]} {
          set ::apave::_AP_VARS(TIMW) [lreplace $::apave::_AP_VARS(TIMW) $i $i]
        }
      }
      foreach {lst vars} [array get ::apave::_AP_VARS "_TRACED_${wr}*"] {
        foreach v $vars {
          ::apave::traceRemove $v
        }
        set ::apave::_AP_VARS($lst) [list]
      }
    }
  }
  #_______________________

  method UpdateColors {} {
    # Updates colors of widgets at changing CS.

    lassign [my csGet] fg fg2 bg bg2 - - - - - fg3
    # Visited labels:
    my CleanUps
    foreach lw $::apave::_AP_VISITED(ALL) {  ;# mark the same links
      lassign $lw w v inv
      lassign [my makeLabelLinked $w $v $fg $bg $fg2 $bg2 no $inv] fg0 bg0
      if {[info exists ::apave::_AP_VISITED(FG,$w)]} {
        set fg0 $fg3
        set ::apave::_AP_VISITED(FG,$w) $fg3
      }
      $w configure -foreground $fg0 -background $bg0
    }
  }

  ## ________________________ Links in labels _________________________ ##

  method initLinkFont {args} {
    # Gets/sets font attributes of links (labels & text tags with -link).
    #  args - font attributes ("-underline 1" by default)
    # Returns the current value of these attributes.

    if {[set ll [llength $args]]} {
      if {$ll%2} {   ;# clear the attributes, if called with ""
        set ::apave::_AP_VARS(LINKFONT) [list]
      } else {
        lassign [::apave::extractOptions args -foreground {} -background {}] \
          ::apave::_AP_VARS(LINKFG) ::apave::_AP_VARS(LINKBG)
        set ::apave::_AP_VARS(LINKFONT) $args
      }
    }
    return $::apave::_AP_VARS(LINKFONT)
  }
  #_______________________

  method labelFlashing {w1 w2 first args} {
    # Options of 'flashing' label:
    #   -file (or -data) {list of image files (or data variables)}
    #   -label {list of labels' texts}
    #   -incr {increment for -alpha option}
    #   -pause {pause in seconds for -alpha 1.0}
    #   -after {interval for 'after'}
    #   -squeeze {value for *-big.png}

    if {![winfo exists $w1]} return
    if {$first} {
      lassign [::apave::parseOptions $args \
        -file {} -data {} -label {} -incr 0.01 -pause 3.0 -after 10 -squeeze {} -static 0] \
        ofile odata olabel oincr opause oafter osqueeze ostatic
      if {$osqueeze ne {}} {set osqueeze "-subsample $osqueeze"}
      lassign {0 -2 0 1} idx incev waitev direv
    } else {
      lassign $args ofile odata olabel oincr opause oafter osqueeze ostatic \
        idx incev waitev direv
    }
    set llf [llength $ofile]
    set lld [llength $odata]
    if {[set llen [expr {max($llf,$lld)}]]==0} return
    incr incev $direv
    set alphaev [expr {$oincr*$incev}]
    if {$alphaev>=1} {
      set alpha 1.0
      if {[incr waitev -1]<0} {
        set direv -1
      }
    } elseif {$alphaev<0} {
      set alpha 0.0
      set idx [expr {$idx%$llen+1}]
      set direv 1
      set incev 0
      set waitev [expr {int($opause/$oincr)}]
    } else {
      set alpha $alphaev
    }
    if {$llf} {
      set png [list -file [lindex $ofile $idx-1]]
    } elseif {[info exists [set datavar [lindex $odata $idx-1]]]} {
      set png [list -data [set $datavar]]
    } else {
      set png [list -data $odata]
    }
    set NS [namespace current]
    if {$ostatic} {
      image create photo ${NS}::ImgT$w1 {*}$png
      $w1 configure -image ${NS}::ImgT$w1
    } else {
      image create photo ${NS}::ImgT$w1 {*}$png -format "png -alpha $alpha"
      image create photo ${NS}::Img$w1
      ${NS}::Img$w1 copy ${NS}::ImgT$w1 {*}$osqueeze
      $w1 configure -image ${NS}::Img$w1
    }
    if {$w2 ne {}} {
      if {$alphaev<0.33 && !$ostatic} {
        set fg [$w1 cget -background]
      } else {
        if {[info exists ::apave::_AP_VISITED(FG,$w2)]} {
          set fg $::apave::_AP_VISITED(FG,$w2)
        } else {
          set fg [$w1 cget -foreground]
        }
      }
      $w2 configure -text [lindex $olabel $idx-1] -foreground $fg
    }
    after $oafter [list [self] labelFlashing $w1 $w2 0 \
      $ofile $odata $olabel $oincr $opause $oafter $osqueeze $ostatic \
      $idx $incev $waitev $direv]
  }
  #_______________________

  method VisitedLab {w cmd {on ""} {fg ""} {bg ""}} {
    # Marks a label as visited/not visited
    #   w - label's path
    #   cmd - command linked
    #   on - flag "the label visited"
    #   fg - foreground of label
    #   bg - background of label

    set styl [ttk::style configure TLabel]
    if {$fg eq {}} {lassign [my csGet] - fg - bg}
    if {[info exists ::apave::_AP_VARS(LINKFG)]} {
      if {$::apave::_AP_VARS(LINKFG) ne {}} {set fg $::apave::_AP_VARS(LINKFG)}
      if {$::apave::_AP_VARS(LINKBG) ne {}} {set bg $::apave::_AP_VARS(LINKBG)}
    }
    set vst [string map {{ } _} $cmd]
    if {$on eq {}} {
      set on [expr {[info exists ::apave::_AP_VISITED($vst)]}]
    }
    if {$on} {
      set fg [lindex [my csGet] 9]
      set ::apave::_AP_VISITED($vst) 1
      set ::apave::_AP_VISITED(FG,$w) $fg
      foreach lw $::apave::_AP_VISITED(ALL) {  ;# mark the same links
        lassign $lw w2 cmd2
        if {[winfo exists $w2] && $cmd eq $cmd2} {
          $w2 configure -foreground $fg -background $bg
          set ::apave::_AP_VISITED(FG,$w2) $fg
        }
      }
    }
    $w configure -foreground $fg -background $bg
    if {[set font [$w cget -font]] eq {}} {
      set font $::apave::FONTMAIN
    } else {
      catch {set font [font actual $font]}
    }
    foreach {o v} [my initLinkFont] {dict set font $o $v}
    $w configure -font $font
  }
  #_______________________

  method HoverLab {w cmd on {fg ""} {bg ""}} {
    # Actions on entering/leaving a linked label.
    #   w - label's path
    #   cmd - command linked
    #   on - flag "now hovering on the label"
    #   fg - foreground of label
    #   bg - background of label

    if {$on} {
      if {$fg eq {}} {lassign [my csGet] fg - bg}
      $w configure -background $bg
    } else {
      my VisitedLab $w $cmd {} $fg $bg
    }
  }
  #_______________________

  method textLink {w idx} {
    # Gets a label's path of a link in a text widget.
    #   w - text's path
    #   idx - index of the link

    if {[info exists ::apave::__TEXTLINKS__($w)]} {
      return [lindex $::apave::__TEXTLINKS__($w) $idx]
    }
    return {}
  }
  #_______________________

  method makeLabelLinked {lab v fg bg fg2 bg2 {doadd yes} {inv no} } {
    # Makes the linked label from a label.
    #   lab - label's path
    #   v - data of the link: command, tip, visited
    #   fg - foreground unhovered
    #   bg - background unhovered
    #   fg2 - foreground hovered
    #   bg2 - background hovered
    #   doadd - flag "register the label in the list of visited"
    #   inv - flag "invert the meaning of colors"

    set txt [$lab cget -text]
    lassign [split [string map [list $Edge $::apave::UFF] $v] $::apave::UFF] v tt vz
    set tt [string map [list %l $txt] $tt]
    set v [string map [list %l $txt %t $tt] $v]
    if {$tt ne {}} {
      set tt [my MC $tt]
      ::baltip tip $lab $tt
      lappend ::apave::_AP_VARS(TIMW) $lab
    }
    if {$inv} {
      set ft $fg
      set bt $bg
      set fg $fg2
      set bg $bg2
      set fg2 $ft
      set bg2 $bt
    }
    my VisitedLab $lab $v $vz $fg $bg
    bind $lab <Enter> "::apave::obj EXPORT HoverLab $lab {$v} yes $fg2 $bg2"
    bind $lab <Leave> "::apave::obj EXPORT HoverLab $lab {$v} no $fg $bg"
    bind $lab <Button-1> "::apave::obj EXPORT VisitedLab $lab {$v} yes $fg2 $bg2;$v"
    if {$doadd} {lappend ::apave::_AP_VISITED(ALL) [list $lab $v $inv]}
    list $fg $bg $fg2 $bg2
  }
  #_______________________

  method leadingSpaces {line} {
    # Returns a number of leading spaces of a line
    #   line - the line

    expr {[string length $line]-[string length [string trimleft $line]]}
  }

  ## ________________________ Text methods _________________________ ##

  method SetContentVariable {tvar txtnam name} {
    # Sets an internal text variable combining its main attributes.
    #   tvar - external variable for text
    #   txtnam - full name of widget
    #   name - short (tail) name of widget
    # The tricky thing is for further access to all of the text.
    # See also: GetContentVariable

    set PV(textcont,$tvar) $tvar*$txtnam*$name
  }
  #_______________________

  method GetContentVariable {tvar} {
    # Gets an internal text variable.
    # See also: SetContentVariable

    return $PV(textcont,$tvar)
  }
  #_______________________

  method SplitContentVariable {ftxvar} {
    # Gets parts of an internal text variable.
    # See also: SetContentVariable

    split $ftxvar *
  }
  #_______________________

  method getTextContent {tvar} {
    # Gets text content.
    #   tvar - text variable
    # Uses an internal text variable to extract the text contents.
    # Returns the content of text.

    lassign [my SplitContentVariable [my GetContentVariable $tvar]] \
      -> txtnam wid
    string trimright [$txtnam get 1.0 end]
  }
  #_______________________

  method onKeyTextM {w K {s {}}} {
    # Processes indents and braces at pressing keys.
    #   w - text's path
    #   K - key's name
    #   s - key's state

    set lindt [string length $::apave::_AP_VARS(INDENT)]
    switch -exact $K {
      Return - KP_Enter {
        # at pressing Enter key, indent (and possibly add the right brace)
        # but shift/ctrl+Enter acts by default - without indenting
        if {$s & 1 || $s & 4} return
        set idx1 [$w index {insert linestart}]
        set idx2 [$w index {insert lineend}]
        set line [$w get $idx1 $idx2]
        set nchars [my leadingSpaces $line]
        set indent [string range $line 0 $nchars-1]
        set ch1 [string range $line $nchars $nchars+1]
        set islist [expr {$ch1 in {{* } {- } {# }}}]
        set ch2 [string index $line end]
        set idx1 [$w index insert]
        set idx2 [$w index "$idx1 +1 line"]
        set st2 [$w get "$idx2 linestart" "$idx2 lineend"]
        set ch3 [string index [string trimleft $st2] 0]
        if {$indent ne {} || $ch2 eq "\{" || $K eq {KP_Enter} || $st2 ne {} || $islist} {
          set st1 [$w get "$idx1" "$idx1 lineend"]
          if {[string index $st1 0] in [list \t { }]} {
            # if space(s) are at the right, remove them at cutting
            set n1 [my leadingSpaces $st1]
            $w delete $idx1 [$w index "$idx1 +$n1 char"]
          } elseif {$ch2 eq "\{" && $st1 eq {}} {
            # indent + closing brace
            set nchars2 [my leadingSpaces $st2]
            if {$st2 eq {} || $nchars>$nchars2 || ($nchars==$nchars2 && $ch3 ne "\}")} {
              append indent $::apave::_AP_VARS(INDENT) \n $indent "\}"
            } else {
              append indent $::apave::_AP_VARS(INDENT)
            }
            incr nchars $lindt
          } elseif {$indent eq {} && $st2 ne {}} {
            # no indent of previous line, try to get it from the next
            if {[string trim $st2] eq "\}"} {
              # add indentation for the next brace
              set st2 "$::apave::_AP_VARS(INDENT)$st2"
            }
            set nchars [my leadingSpaces $st2]
            set indent [string range $st2 0 [expr {$nchars-1}]]
          }
          # a new line supplied with "list-like pattern"
          if {$islist && ![string match *.0 $idx1] && \
          [string trim [$w get "$idx1 linestart" $idx1]] ne {}} {
            if {$ch1 eq {# } && int($idx1)>1} {
              # for comments: if only more than 1 of them, then add another
              set idx0 [$w index "$idx1 -1 line"]
              set st0 [string trimleft [$w get "$idx0 linestart" "$idx0 lineend"]]
              if {[string index $st0 0] ne {#} && $ch3 ne {#}} {
                set ch1 {}
              }
            }
            set indent "$indent$ch1"
            incr nchars [string length $ch1]
          }
          $w insert $idx1 \n$indent
          ::tk::TextSetCursor $w [$w index "$idx2 linestart +$nchars char"]
          return -code break
        }
      }
    braceright {
        # right brace pressed: shift the brace to left
        set idx1 [$w index insert]
        set st [$w get "$idx1 linestart" "$idx1 lineend"]
        set idx2 [$w index "$idx1 -1 line"]
        set st2 [$w get "$idx2 linestart" "$idx2 lineend"]
        set nchars [my leadingSpaces $st]
        set nchars2 [my leadingSpaces $st2]
        set st2 [string index $st2 end]
        if {($st2 ne "\{" && $nchars2<=$nchars || $st2 eq "\{" && $nchars2<$nchars) \
        && [string trimright $st] eq {} && [string length $st]>=$lindt} {
          if {$nchars>$nchars2} {set lindt [expr {$nchars-$nchars2}]}
          $w delete "$idx1 lineend -$lindt char" "$idx1 lineend"
        }
      }
    }
  }
  #_______________________

  method setTextBinds {wt} {
    # Returns bindings for a text widget.
    #   wt - the text's path

    if {[bind $wt <<Paste>>] eq {}} {
      set res " \
      ::apave::bindToEvent $wt <<Paste>> [self] pasteText $wt ;\
      ::apave::bindToEvent $wt <KP_Enter> [self] onKeyTextM $wt %K %s ;\
      ::apave::bindToEvent $wt <Return> [self] onKeyTextM $wt %K %s ;\
      catch {::apave::bindToEvent $wt <braceright> [self] onKeyTextM $wt %K}"
    }
    foreach k [::apave::getTextHotkeys CtrlD] {
      append res " ; ::apave::bindToEvent $wt <$k> [self] doubleText $wt"
    }
    foreach k [::apave::getTextHotkeys CtrlY] {
      append res " ; ::apave::bindToEvent $wt <$k> [self] deleteLine $wt"
    }
    foreach k [::apave::getTextHotkeys CtrlA] {
      append res " ; ::apave::bindToEvent $wt <$k> $wt tag add sel 1.0 end {;} break"
    }
    foreach k [::apave::getTextHotkeys CtrlT] {
      append res " ; ::apave::bindToEvent $wt <$k> ::apave::InsertChar $wt {\t} {;} break"
    }
    set lstart linestart
    if {[::isunix]} {append lstart { +1c}} ;# don't use "break"
    foreach k [::apave::getTextHotkeys CtrlB] {
      append res " ; ::apave::bindToEvent $wt <$k> ::apave::CursorToBEOL $wt {$lstart}"
    }
    foreach k [::apave::getTextHotkeys CtrlE] {
      append res " ; ::apave::bindToEvent $wt <$k> ::apave::CursorToBEOL $wt lineend"
    }
    append res " ;\
      ::apave::bindToEvent $wt <Alt-Up> [self] linesMove $wt -1 ;\
      ::apave::bindToEvent $wt <Alt-Down> [self] linesMove $wt +1"
  }
  #_______________________

  method TextCommandForChange {w com on {com2 ""}} {
    # Replaces a command of text widget for making changes
    #   w - text widget's name
    #   com - command for changes
    #   on - if "yes", replaces a text command; if "no", restores it
    # In particular, when `com` is empty, the text widget becomes readonly.

    set newcom $w.internal
    if {!$on} {
      if {[info commands ::$newcom] ne {}} {
        rename ::$w {}
        rename ::$newcom ::$w
      }
    } elseif {[info commands ::$newcom] eq {}} {
      rename $w ::$newcom
      if {$com eq {}} {
        # text to be readonly
      ; proc ::$w {args} "
          switch -exact -- \[lindex \$args 0\] \{
              insert \{\}
              delete \{\}
              replace \{\}
              default \{
                  return \[eval ::$newcom \$args\]
              \}
          \}"
      } else {
        # text to be sensible to changes
      ; proc ::$w {args} "
          set _res_of_TextCommandForChange \[eval ::$newcom \$args\]
          switch -exact -- \[lindex \$args 0\] \{
              insert \{$com\}
              delete \{$com\}
              replace \{$com\}
          \}
          return \$_res_of_TextCommandForChange"
      }
    }
    if {$com2 ne {}} {
      {*}$com2
    }
  }
  #_______________________

  method readonlyWidget {w {on yes} {popup yes}} {
    # Switches on/off a widget's readonly state for a text widget.
    #   w - text widget's path
    #   on - "on/off" boolean flag
    #   popup - "make popup menu" boolean flag
    # See also:
    #   [wiki.tcl-lang.org](https://wiki.tcl-lang.org/page/Read-only+text+widget)

    my TextCommandForChange $w {} $on
    if {$popup} {my makePopup $w $on yes}
  }
  #_______________________

  method GetOutputValues {} {
    # Makes output values for some widgets (lbx, fco).
    # Some i/o widgets need a special method to get their returned values.

    foreach aop $Widgetopts {
      lassign $aop optnam vn v1 v2
      switch -glob -- $optnam {
        -lbxname* {
          # To get a listbox's value, its methods are used.
          # The widget may not exist when an apave object is used for
          # several dialogs which is a bad style (very very bad).
          if {[winfo exists $vn]} {
            lassign [$vn curselection] s1
            if {$s1 eq {}} {set s1 0}
            set w [string range $vn [string last . $vn]+1 end]
            if {[catch {set v0 [$vn get $s1]}]} {set v0 {}}
            if {$optnam eq {-lbxnameALL}} {
              # when -ALL option is set to 1, listbox returns
              # a list of 3 items - sel index, sel contents and all contents
              set $v1 [list $s1 $v0 [set $v1]]
            } else {
              set $v1 $v0
            }
          }
        }
        -retpos { ;# a range to cut from -tvar/-lvar variable
          lassign [split $v2 :] p1 p2
          set val1 [set $v1]
          # there may be -list option for this widget
          # then if the value is from the list, it's fully returned
          foreach aop2 $Widgetopts {
            lassign $aop2 optnam2 vn2 lst2
            if {$optnam2 eq {-list} && $vn eq $vn2} {
              foreach val2 $lst2 {
                if {$val1 eq $val2} {
                  set p1 0
                  set p2 end
                  break
                }
              }
              break
            }
          }
          set $v1 [string range $val1 $p1 $p2]
        }
      }
    }
  }
  #_______________________

  method focusNext {w wnext {wnext0 ""}} {
    # Sets focus on a next widget (possibly, defined as `my Widget`).
    #   w - parent window name
    #   wnext - next widget's name
    #   wnext0 - core next name (used internally, for recursive search)

    if {$wnext eq {}} return
    if {[winfo exist $wnext]} {
      focus $wnext  ;# direct path to the next widget
      return
    }
    # try to find the next widget in hierarchy of widgets
    set ws $wnext
    if {$wnext0 eq {}} {
      # get the real next widget (wnext can be uppercased or calculated)
      catch {set wnext [subst $wnext]}
      if {![string match {my *} $wnext]} {
        catch {set wnext [my [my ownWName $wnext]]}
      }
      my focusNext $w $wnext $wnext
    } else {
      set wnext $wnext0
    }
    foreach wn [winfo children $w] {
      my focusNext $wn $wnext $wnext0
      if {[string match "*.$wnext" $wn] || [string match "*.$ws" $wn]} {
        focus $wn
        return
      }
    }
  }
  #_______________________

  method AdditionalCommands {w wdg attrsName} {
    # Gets additional commands (for non-standard attributes).
    #   w - window name
    #   wdg - widget's full path
    #   attrsName - variable name for widget's attributes

    upvar $attrsName attrs
    set addcomms {}
    if {[set tooltip [::apave::getOption -tooltip {*}$attrs]] ne {} ||
    [set tooltip [::apave::getOption -tip {*}$attrs]] ne {}} {
      ::apave::initBaltip
      if {[set i [string first $Edge $tooltip]]>=0} {
        set tooltip [string range $tooltip 1 end-1]
        set tattrs [string range $tooltip [incr i -1]+[string length $Edge] end]
        set tooltip "{[string range $tooltip 0 $i-1]}"
      } else {
        set tattrs {}
      }
      set tooltip [my MC $tooltip]
      lappend addcomms [list ::baltip::tip $wdg $tooltip {*}$tattrs]
      set attrs [::apave::removeOptions $attrs -tooltip -tip]
    }
    if {[::apave::getOption -ro {*}$attrs] ne {} || \
    [::apave::getOption -readonly {*}$attrs] ne {}} {
      lassign [::apave::extractOptions attrs -ro 0 -readonly 0] ro readonly
      lappend addcomms [list my readonlyWidget $wdg [expr $ro||$readonly]]
    }
    if {[set wnext [::apave::getOption -tabnext {*}$attrs]] ne {}} {
      # two widgets for Tab & Shift/Tab (proc can be used to get them)
      set wnext [string trim $wnext "\{\}"]
      if {[string first \[ $wnext]==0} { ;# if [comm1] [comm2] for next/prev
        set wprev {}
        catch {lassign [subst $wnext] wnext wprev}
      } else {
        if {[catch {lassign [{*}$wnext] wnext wprev}]} {
          lassign $wnext wnext wprev
        }
      }
      if {$wnext eq {0}} {set wnext $wdg} ;# disables Tab on this widget
      if {[::iswindows]} {
        set i1 {{%s}==0}  ;# in Windows: Shift+Tab doesn't work in text
      } else {
        set i1 1
      }
      set c1 "[self] focusNext $w $wnext ; break"
      set c2 "[self] focusNext $w $wprev ; break"
      set i2 [expr {$wprev ne {}}]
      after idle [list if "\[winfo exists $wdg\]" [list bind $wdg <Key> \
        [list + if {{%K} eq {Tab}} [list if $i1 $c1 elseif $i2 $c2]]]]
      set attrs [::apave::removeOptions $attrs -tabnext]
    }
    return $addcomms
  }
  #_______________________

  method DefineWidgetKeys {wname widget} {
    # Sets some hotkeys for some widgets (e.g. Enter to work as Tab)
    #   wname - the widget's name
    #   widget - the widget's type
    # This may be disabled by including "STD" in the widget's name.

    if {[string first STD $wname]>0} return
    if {($widget in {ttk::entry entry})} {
      bind $wname <Up>  \
        "$wname selection clear ; \
        if {{$::tcl_platform(platform)} eq {windows}} {
          event generate $wname <Shift-Tab>
        } else {
          event generate $wname <Key> -keysym ISO_Left_Tab
        }"
      bind $wname <Down>  \
        "$wname selection clear ; \
        event generate $wname <Key> -keysym Tab"
    } elseif {$widget in {ttk::button button ttk::checkbutton checkbutton \
    ttk::radiobutton radiobutton "my tk_optionCascade"}} {
      foreach k {<Up> <Left>} {
        bind $wname $k [list \
          if {$::tcl_platform(platform) eq {windows}} [list \
            event generate $wname <Shift-Tab> \
          ] else [list \
            event generate $wname <Key> -keysym ISO_Left_Tab] \
          ]
      }
      foreach k {<Down> <Right>} {
        bind $wname $k \
          [list event generate $wname <Key> -keysym Tab]
      }
    }
    if {$widget in {ttk::button button \
    ttk::checkbutton checkbutton ttk::radiobutton radiobutton}} {
      foreach k {<Return> <KP_Enter>} {
        bind $wname $k \
        [list event generate $wname <Key> -keysym space]
      }
    }
    if {$widget in {ttk::entry entry spinbox ttk::spinbox ttk::combobox}} {
      foreach k {<Return> <KP_Enter>} {
        bind $wname $k \
          "+ $wname selection clear ; event generate $wname <Key> -keysym Tab"
      }
    }
  }

  ## ________________________ Paving windows _________________________ ##

  method colorWindow {win args} {
    # Initialize colors of a window.
    #   win - window's path
    #   args - arguments for csSet

    if {[my apaveTheme]} {
      my csSet [my csCurrent] $win {*}$args
      if {$args ne {-doit}} {my themeNonThemed $win}
    } else {
      my themeNonThemed $win
    }
  }
  #_______________________

  method ShowOption {name} {
    # Gets a default show option, used in showModal.
    #   name - name of option
    # See also: getShowOption, setShowOption

    return "_SHOWMODAL_$name"
  }
  #_______________________

  method getShowOption {name {defval ""}} {
    # Gets a default show option, used in showModal.
    #   name - name of option
    #   defval - default value
    # See also: showModal

    ::apave::getProperty [my ShowOption $name] $defval
  }
  #_______________________

  method setShowOption {name args} {
    # Sets / gets a default show option, used in showModal.
    #   name - name of option
    #   args - value of option
    # See also: showModal

    ::apave::setProperty [my ShowOption $name] {*}$args
  }
  #_______________________

  method pavedPath {} {
    # Gets the currently paved window's path.

    return $Modalwin
  }
  #_______________________

  method Window {w inplists} {
    # Paves the window with widgets.
    #   w - window's name (path)
    #   inplists - list of widget items (lists of widget data)
    # Contents of a widget's item:
    #   name - widget's name (first 3 characters define its type)
    #   neighbor - top (T) or left (L) neighbor of the widget
    #   posofnei - position of neighbor: T (top) or L (left)
    #   rowspan - row span of the widget
    #   colspan - column span of the widget
    #   options - grid/pack options
    #   attrs - attributes of widget
    # First 3 items are mandatory, others are set at need.
    # Called by *paveWindow* method to process a portion of widgets.
    # The "portion" refers to a separate block of widgets such as
    # notebook's tabs or frames.

    set ::apave::_AP_VARS(WPAVE) [winfo toplevel $w]
    set lwidgets [list]
    # comments be skipped
    foreach lst $inplists {
      if {[string index $lst 0] ne {#}} {
        lappend lwidgets $lst
      }
    }
    set lused [list]
    set lwlen [llength $lwidgets]
    if {$lwlen<2 && [string trim $lwidgets "{} "] eq {}} {
      set lwidgets [list {fra - - - - {pack -padx 99 -pady 99}}]
      set lwlen 1
    }
    for {set i 0} {$i < $lwlen} {} {
      set lst1 [lindex $lwidgets $i]
      if {[my Replace_Tcl i lwlen lwidgets {*}$lst1] ne {}} {incr i}
    }
    # firstly, normalize all names that are "subwidgets" (.lab for fra.lab)
    # also, "+" for previous neighbors
    set i [set lwlen [llength $lwidgets]]
    while {$i>1} {
      incr i -1
      set lst1 [lindex $lwidgets $i]
      lassign $lst1 name neighbor
      if {$neighbor eq {+}} {set neighbor [lindex $lwidgets $i-1 0]}
      lassign [my NormalizeName name i lwidgets] name wname
      set neighbor [lindex [my NormalizeName neighbor i lwidgets] 0]
      set lst1 [lreplace $lst1 0 1 $wname $neighbor]
      set lwidgets [lreplace $lwidgets $i $i $lst1]
    }
    for {set i 0} {$i < $lwlen} {} {
      # List of widgets contains data per widget:
      #   widget's name,
      #   neighbor widget, position of neighbor (T, L),
      #   widget's rowspan and columnspan (both optional),
      #   grid options, widget's attributes (both optional)
      set lst1 [lindex $lwidgets $i]
      set lst1 [my Replace_chooser w i lwlen lwidgets {*}$lst1]
      if {[set lst1 [my Replace_bar w i lwlen lwidgets {*}$lst1]] eq {}} {
        incr i
        continue
      }
      lassign $lst1 name neighbor posofnei rowspan colspan options1 attrs1
      lassign [my NormalizeName name i lwidgets] name wname
      set wname [my MakeWidgetName $w $wname]
      if {$colspan eq {} || $colspan eq {-}} {
        set colspan 1
        if {$rowspan eq {} || $rowspan eq {-}} {
          set rowspan 1
        }
      }
      foreach ao {attrs options} {
        if {[catch {set $ao [uplevel 2 subst -nocommand -nobackslashes [list [set ${ao}1]]]}]} {
          set $ao [set ${ao}1]
        }
      }
      lassign [my widgetType $wname $options $attrs] widget options attrs nam3 dsbl
      # The type of widget (if defined) means its creation
      # (if not defined, it was created after "makewindow" call
      # and before "window" call)
      if { !($widget eq {} || [winfo exists $widget])} {
        set attrs [my GetAttrs $attrs $nam3 $dsbl]
        set attrs [my ExpandOptions $attrs]
        # for scrollbars - set up the scrolling commands
        if {$widget in {ttk::scrollbar scrollbar}} {
          set neighbor [lindex [my LowercaseWidgetName $neighbor] 0]
          set wneigb [my WidgetNameFull $w $neighbor]
          if {$posofnei eq {L}} {
            $wneigb config -yscrollcommand "$wname set"
            set attrs "$attrs -com \\\{$wneigb yview\\\}"
            append options { -side right -fill y} ;# -after $wneigb"
          } elseif {$posofnei eq {T}} {
            $wneigb config -xscrollcommand "$wname set"
            set attrs "$attrs -com \\\{$wneigb xview\\\}"
            append options { -side bottom -fill x} ;# -before $wneigb"
          }
          set options [string map [list %w $wneigb] $options]
        }
        my Pre attrs
        set addcomms [my AdditionalCommands $w $wname attrs]
        eval $widget $wname {*}$attrs
        my Post $wname $attrs
        foreach acm $addcomms {{*}$acm}
        # for buttons and entries - set up the hotkeys (Up/Down etc.)
        my DefineWidgetKeys $wname $widget
      }
      if {$neighbor eq {-} || $row < 0} {
        set row [set col 0]
      }
      # check for simple creation of widget (without pack/grid)
      if {$neighbor ne {#}} {
        set options [my GetIntOptions $w $options $row $rowspan $col $colspan]
        set pack [string trim $options]
        if {[string first add $pack]==0} {
          set comm "[winfo parent $wname] add $wname [string range $pack 4 end]"
          {*}$comm
        } elseif {[string first pack $pack]==0} {
          set opts [string trim [string range $pack 5 end]]
          if {[string first forget $opts]==0} {
            pack forget {*}[string range $opts 6 end]
          } else {
            pack $wname {*}$opts
          }
        } else {
          grid $wname -row $row -column $col -rowspan $rowspan \
             -columnspan $colspan -padx 1 -pady 1 {*}$options
        }
      }
      lappend lused [list $name $row $col $rowspan $colspan]
      if {[incr i] < $lwlen} {
        lassign [lindex $lwidgets $i] name neighbor posofnei
        set neighbor [lindex [my LowercaseWidgetName $neighbor] 0]
        set row -1
        foreach cell $lused {
          lassign $cell uname urow ucol urowspan ucolspan
          if {[lindex [my LowercaseWidgetName $uname] 0] eq $neighbor} {
            set col $ucol
            set row $urow
            if {$posofnei eq {T} || $posofnei eq {}} {
              incr row $urowspan
            } elseif {$posofnei eq {L}} {
              incr col $ucolspan
            }
          }
        }
      }
    }
    return $lwidgets
  }
  #_______________________

  method paveWindow {args} {
    # Processes "win / list_of_widgets" pairs.
    #   args - list of pairs "win / lwidgets"
    # The *win* is a window's path. The *lwidgets* is a list of widget items.
    # Each widget item contains:
    #   name - widget's name (first 3 characters define its type)
    #   neighbor - top or left neighbor of the widget
    #   posofnei - position of neighbor: T (top) or L (left)
    #   rowspan - row span of the widget
    #   colspan - column span of the widget
    #   options - grid/pack options
    #   attrs - attributes of widget
    # First 3 items are mandatory, others are set at need.
    # This method calls *paveWindow* in a cycle, to process a current "win/lwidgets" pair.

    set res [list]
    set wmain [set wdia {}]
    foreach {w lwidgets} $args {
      if {[lindex $lwidgets 0 0] eq {after}} {
        # if 1st item is "after idle" or like "after 1000", layout the window after...
        # (fit for "invisible independent" windows/frames/tabs)
        set what [lindex $lwidgets 0 1]
        if {$what eq {idle} || [string is integer -strict $what]} {
          after $what [list [self] paveWindow $w [lrange $lwidgets 1 end]]
          after $what [list [self] colorWindow $w -doit]
        }
        continue
      }
      lappend res {*}[my Window $w $lwidgets]
      if {[set ifnd [regexp -indices -inline {[.]dia\d+} $w]] ne {}} {
        set wdia [string range $w 0 [lindex $ifnd 0 1]]
      } else {
        set wmain .[lindex [split $w .] 1]
      }
    }
    # add a system Menu binding for the created window
    if {[winfo exists $wdia]} {::apave::initPOP $wdia} elseif {
        [winfo exists $wmain]} {::apave::initPOP $wmain}
    return $res
  }
  #_______________________

  method window {args} {
    # Obsolete version of paveWindow (remains for compatibility).
    # See also: paveWindow

    return [uplevel 1 [list [self] paveWindow {*}$args]]
  }
  #_______________________

  method WinVarname {win} {
    # Gets a unique varname for a window.
    #   win - window's path

    return [namespace current]::PV(_WIN_,$win)
  }
  #_______________________

  method waitWinVar {win var modal} {
    # Tk waiting for variable's change.
    #   win - the window's path
    #   var - variable's name to receive a result (tkwait's variable)
    #   modal - yes at showing the window as modal

    # first of all, wait till the window be visible
    after 1 ;# solves an issue with doubleclicking buttons
    if {![winfo viewable $win]} {
      tkwait visibility $win
    }
    set wmain [::apave::mainWindowOfApp]
    if {$modal} {      ;# for modal, grab the window
      set wgr [grab current]
      if {$wmain ne {} && $wmain ne $win} {
        if {[catch {grab set $win} e]} {
          catch {tkwait visibility $win}  ;# 2nd attempt to get the window visible, by force
          catch {grab set $win}           ;# (not sure, where it can fire, still let it be)
          puts stderr "\napave::waitWinVar - please send a note to apave developers on this catch. Error: $e"
          catch {puts stderr "apave::waitWinVar - [info level -1]\n"}
        }
      }
    }
    # at need, wait till the window associated variable be changed
    if {$var ne {}} {
      tkwait variable $var
    }
    if {$modal} {      ;# for modal, release the grab and restore the old one
      catch {grab release $win}
      if {$wgr ne {}} {
        catch {grab set $wgr}
      }
    }
  }
  #_______________________

  method showWindow {win modal ontop {var ""} {minsize ""} {waitvar 1} {waitme {}}} {
    # Displays a windows and goes in tkwait cycle to interact with a user.
    #   win - the window's path
    #   modal - yes at showing the window as modal
    #   ontop - yes at showing the window as topmost
    #   var - variable's name to receive a result (tkwait's variable)
    #   minsize - list {minwidth minheight} or {}
    #   waitvar - if yes, force tkwait variable (mostly for non-modal windows)
    #   waitme - if empty, deiconify immediately, otherwise after waiting a variable or "timeout and/or idle"

    ::apave::InfoWindow [expr {[::apave::InfoWindow] + 1}] $win $modal $var yes
    if {$waitme ne {}} {
      if {[info exists $waitme]} {
        vwait $waitme
        ::apave::deiconify $win
        catch {incr $waitme} ;# used to trigger chained events
      } else {
        after {*}$waitme ::apave::deiconify $win
      }
    } else {
      ::apave::deiconify $win
    }
    if {$minsize eq {}} {
      set minsize [list [winfo width $win] [winfo height $win]]
    }
    wm minsize $win {*}$minsize
    bind $win <Configure> "[namespace current]::WinResize $win"
    if {$ontop} {wm attributes $win -topmost 1}
    if {$modal} {
      # modal window:
      my waitWinVar $win $var $modal
      ::apave::InfoWindow [expr {[::apave::InfoWindow] - 1}] $win $modal $var
    } else {
      # non-modal window:
      if {[set wgr [grab current]] ne {}} {
        # otherwise the non-modal window is irresponsive (in Windows even at WM level):
        grab release $wgr
      }
      if {$waitvar && $var ne {}} {
        my waitWinVar $win $var $modal ;# show and wait for closing the window
      }
    }
  }
  #_______________________

  method showModal {win args} {
    # Shows a window as modal.
    #   win - window's name
    #   args - attributes of window ("-name value" pairs)

    set ::apave::MODALWINDOW $win
    ::apave::setAppIcon $win
    set ontop [my getShowOption -ontop 0]
    lassign [::apave::extractOptions args -centerme {} -ontop $ontop -modal yes \
      -minsize {} -themed {} -input 0 -variable {} -waitvar {} -transient {-} \
      -root {} -parent {} -waitme {}] \
      centerme ontop modal minsize themed input varname waitvar transient \
      root parent waitme
    $win configure -bg [lindex [my csGet] 3]  ;# removes blinking by default bg
    if {$themed in {{} {0}} && [my csCurrent] != [apave::cs_Non]} {
      my colorWindow $win
    }
    if {$centerme eq {}} {
      # obsolete options: -root, -parent
      if {$root ne {}} {set centerme $root} {set centerme $parent}
    }
    set root [winfo parent $win]
    set rooted 1
    if {$centerme ne {}} {
      ;# forced centering relative to a caller's window
      lassign [::apave::splitGeometry $centerme] rw rh rx ry
      set rooted [expr {![regexp {[+|-]+\d+\++} $centerme]}]
      if {$rooted && [winfo exist $centerme]} {
        set root $centerme
      }
    }
    set decor [expr {$root in {{} .}}]
    foreach {o v} [list -decor $decor -focus {} -onclose {} -geometry {} \
    -resizable {} -escape 1 -checkgeometry 1] {
      set v [my getShowOption $o $v]
      lappend defargs $o $v
      set [string range $o 1 end] $v
    }
    if {$varname ne {}} {
      set waitvar 1
    } else {
      set waitvar [string is true $waitvar]  ;# default 1: wait for closing the window
      set varname [my WinVarname $win]
    }
    array set opt [list {*}$defargs {*}$args]
    if {$ontop eq {}} {
      if {$opt(-ontop)} {
        set ontop yes
      } else {
        set ontop no
        catch {
          set ontop [wm attributes [winfo parent $win] -topmost]
        }
        if {!$ontop} {
          # find if a window child of "." is topmost
          # if so, let this one be topmost too
          foreach w [winfo children .] {
            catch {set ontop [wm attributes $w -topmost]}
            if {$ontop} break
          }
        }
      }
    }
    if {$rooted} {
      lassign [::apave::splitGeometry [wm geometry [winfo toplevel $root]]] rw rh rx ry
    }
    if {$transient ne {-}} {
      wm transient $win $transient
    } elseif {!$opt(-decor)} {
      wm transient $win $root
    }
    if {[set destroy [expr {$opt(-onclose) eq {destroy}}]]} {
      set opt(-onclose) {}
    }
    if {$opt(-onclose) eq {}} {
      set opt(-onclose) "set $varname 0"
    } else {
      set opt(-onclose) "$opt(-onclose) $varname"  ;# $opt(-onclose) is a command
      set opt(-onclose) [string map [list %w $win] $opt(-onclose)]
    }
    if {$destroy} {append opt(-onclose) " ; catch {destroy $win}"}
    if {$opt(-resizable) ne {}} {
      if {[string is boolean $opt(-resizable)]} {
        set opt(-resizable) "$opt(-resizable) $opt(-resizable)"
      }
      wm resizable $win {*}$opt(-resizable)
    }
    if {!($modal || $waitvar)} {
      append opt(-onclose) "; ::apave::obj EXPORT CleanUps $win"
    }
    foreach ev {KeyRelease ButtonRelease} {
      after idle [list bind $Modalwin <$ev> "::apave::focusApp $Modalwin"]
    }
    if {$modal} {lappend ::apave::FOCUSED $win}
    wm protocol $win WM_TAKE_FOCUS {after idle ::apave::focusApp}
    wm protocol $win WM_DELETE_WINDOW $opt(-onclose)
    # get the window's geometry from its requested sizes
    set inpgeom $opt(-geometry)
    if {$inpgeom eq {}} {
      # this is for less blinking:
      set opt(-geometry) [my CenteredXY $rw $rh $rx $ry \
        [winfo reqwidth $win] [winfo reqheight $win]]
    } elseif {[string first pointer $inpgeom]==0} {
      lassign [split $inpgeom+0+0 +] -> x y
      set inpgeom +[expr {$x+[winfo pointerx .]}]+[expr {$y+[winfo pointery .]}]
      set opt(-geometry) $inpgeom
    } elseif {[string first root $inpgeom]==0} {
      set root .[string trimleft [string range $inpgeom 5 end] .]
      set opt(-geometry) [set inpgeom {}]
    }
    if {$opt(-geometry) ne {}} {
      lassign [::apave::splitGeometry $opt(-geometry) {} {}] - - x y
      if {$x ne {}} {wm geometry $win $x$y}
    }
    if {$opt(-focus) eq {}} {
      set opt(-focus) $win
    }
    set $varname {-}
    if {$opt(-escape)} {bind $win <Escape> $opt(-onclose)}
    update
    if {![winfo exists $win]} {
      return 0 ;# looks idiotic, yet possible at sporadic calls
    }
    set w [winfo reqwidth $win]
    set h [winfo reqheight $win]
    if {$inpgeom eq {}} {  ;# final geometrizing with actual sizes
      set geo [my CenteredXY $rw $rh $rx $ry $w $h]
      set y [lindex [split $geo +] end]
      if {!$rooted || $root ne {.} && (($h/2-$ry-$rh/2)>30 || [::iswindows] && $y>0)} {
        # ::tk::PlaceWindow needs correcting in rare cases, namely:
        # when 'root' is of less sizes than 'win' and at screen top
        wm geometry $win $geo
      } else {
        ::tk::PlaceWindow $win widget $root
      }
    } else {
      lassign [::apave::splitGeometry $inpgeom {} {}] - - x y
      if {$x ne {} && $y ne {} && [string first x $inpgeom]<0 && $opt(-checkgeometry)} {
        set inpgeom [my checkXY $w $h $x $y]
      } elseif {$x eq {} && $y eq {} && $centerme ne {} && $opt(-geometry) ne {}} {
        lassign [split $opt(-geometry) x+] w h
        lassign [split [my CenteredXY $rw $rh $rx $ry $w $h] +] -> x y
        set inpgeom ${w}x$h+$x+$y
      }
      set inpgeom [::apave::checkGeometry $inpgeom]
      catch {wm geometry $win $inpgeom}
    }
    if {$opt(-focus) eq {Tab}} {
      after 100 "catch {focus $win; event generate $win <Tab>}" ;# to focus on 1st
    } else {
      after 100 "catch {focus -force $opt(-focus); apave::setProperty FOCW_$win $opt(-focus)}"
    }
    if {[info exists ::transpops::my::cntwait]} {
      # this specific bind - for transpops package (to hide a demo message by keys)
      bind $win <Control-Alt-0> {set ::transpops::my::cntwait 0}
    }
    my showWindow $win $modal $ontop $varname $minsize $waitvar $waitme
    set res 0
    catch {
      if {$modal || $waitvar} {my CleanUps $win}
      if {[winfo exists $win]} {
        if {$input} {my GetOutputValues}
        set res [set [set _ $varname]]
      }
    }
    return $res
  }
  #_______________________

  method res {{win {}} {result get}} {
    # Gets/sets a variable for *vwait* command.
    #   win - window's path
    #   result - value of variable
    # This method is used when
    #  - an event cycle should be stopped with changing a variable's value
    #  - a result of event cycle (the variable's value) should be got
    # In the first case, *result* is set to an integer. In *apave* dialogs
    # the integer is corresponding a pressed button's index.
    # In the second case, *result* is omitted or equal to "get".
    # Returns a value of variable that controls an event cycle.

    if {$win eq {}} {set win [my dlgPath]}
    set varname [my WinVarname $win]
    if {$result eq {get}} {
      return [set $varname]
    }
    my CleanUps $win
    return [set $varname $result]
  }
  #_______________________

  method makeWindow {w ttl args} {
    # Creates a toplevel window that has to be paved.
    #   w - window's name
    #   ttl - window's title
    #   args - options for 'toplevel' command
    # If $w matches "*.fra" then ttk::frame is created with name $w.

    my CleanUps
    set w [set wtop [string trimright $w .]]
    set withfr [expr {[set pp [string last . $w]]>0 && \
      [string match *.fra $w]}]
    if {$withfr} {
      set wtop [string range $w 0 $pp-1]
    }
    catch {destroy $wtop}
    lassign [::apave::extractOptions args -type {}] type
    set Modalwin [toplevel $wtop {*}$args]
    ::apave::withdraw $wtop ;# nice to hide all gui manipulations
    if {$type ne {} && [tk windowingsystem] eq {x11}} {
      wm attributes $wtop -type $type
    }
    if {$withfr} {
      pack [frame $w -background [lindex [my csGet] 3]] -expand 1 -fill both
    }
    wm title $wtop $ttl
    return $wtop
  }
  #_______________________

  method displayText {w conts {pos 1.0}} {
    # Sets the text widget's contents.
    #   w - text widget's name
    #   conts - contents to be set in the widget

    if {[set state [$w cget -state]] ne {normal}} {
      $w configure -state normal
    }
    $w replace 1.0 end $conts
    $w edit reset; $w edit modified no
    if {$state eq {normal}} {
      ::tk::TextSetCursor $w $pos
    } else {
      $w configure -state $state
    }
  }
  #_______________________

  method resetText {w state {contsName {}}} {
    # Resets a text widget to edit/view from scratch.
    #   w - text widget's name
    #   state - widget's final state (normal/disabled)
    #   contsName - variable name for contents to be set in the widget

    if {$contsName ne {}} {
      upvar 1 $contsName conts
      $w replace 1.0 end $conts
    }
    $w edit reset
    $w edit modified no
    $w configure -state $state
  }
  #_______________________

  method displayTaggedText {w contsName {tags ""}} {
    # Sets the text widget's contents using tags (ornamental details).
    #   w - text widget's name
    #   contsName - variable name for contents to be set in the widget
    #   tags - list of tags to be applied to the text
    # The lines in *text contents* are divided by \n and can include
    # *tags* like in a html layout, e.g. <red>RED ARMY</red>.
    # The *tags* is a list of "name/value" pairs. 1st is a tag's name, 2nd
    # is a tag's value.
    # The tag's name is "pure" one (without <>) so e.g.for <b>..</b> the tag
    # list contains "b".
    # The tag's value is a string of text attributes (-font etc.).
    # If the tag's name is FG, FG2, BG or BG2, then it is really a link color.

    upvar $contsName conts
    if {$tags eq {}} {
      my displayText $w $conts
      return
    }
    lassign [my csGet] fg fg2 bg bg2
    if { [set state [$w cget -state]] ne {normal}} {
      $w configure -state normal
    }
    set taglist [set tagpos [set taglen [list]]]
    foreach tagi $tags {
      lassign $tagi tag opts
      if {$tag in {FG FG2 BG BG2} } {
        set [string tolower $tag] $opts
      } elseif {![string match link* $tag]} {
        $w tag config $tag {*}$opts
      }
      lappend tagpos 0
      lappend taglen [string length $tag]
    }
    set tLen [llength $tags]
    set disptext {}
    set irow 1
    foreach line [split $conts \n] {
      if {$irow > 1} {
        append disptext \n
      }
      set newline {}
      while 1 {
        set p [string first \< $line]
        if {$p < 0} {
          break
        }
        append newline [string range $line 0 $p-1]
        set line [string range $line $p end]
        set i 0
        set nrnc $irow.[string length $newline]
        foreach tagi $tags pos $tagpos len $taglen {
          lassign $tagi tag
          if {[string first <$tag> $line]==0} {
            if {$pos ne {0}} {
              error "\napave: mismatched <$tag> in line $irow.\n"
            }
            lset tagpos $i $nrnc
            set line [string range $line $len+2 end]
            break
          } elseif {[string first </$tag> $line]==0} {
            if {$pos eq {0}} {
              error "\napave: mismatched </$tag> in line $irow.\n"
            }
            lappend taglist [list $i $pos $nrnc]
            lset tagpos $i 0
            set line [string range $line $len+3 end]
            break
          }
          incr i
        }
        if {$i == $tLen} {
          # tag not found after "<" - shift by 1 character
          append newline [string index $line 0]
          set line [string range $line 1 end]
        }
      }
      append disptext $newline $line
      incr irow
    }
    $w replace 1.0 end $disptext
    set lfont [$w cget -font]
    catch {set lfont [font actual $lfont]}
    foreach {o v} [my initLinkFont] {dict set lfont $o $v}
    set ::apave::__TEXTLINKS__($w) [list]
    for {set it [llength $taglist]} {[incr it -1]>=0} {} {
      set tagli [lindex $taglist $it]
      lassign $tagli i p1 p2
      lassign [lindex $tags $i] tag opts
      if {[string match link* $tag] && \
      [set ist [lsearch -exact -index 0 $tags $tag]]>=0} {
        set txt [$w get $p1 $p2]
        set lab ${w}l[incr ::apave::__linklab__]
        ttk::label $lab -text $txt -font $lfont -foreground $fg -background $bg
        set ::apave::__TEXTLINKS__($w) [linsert $::apave::__TEXTLINKS__($w) 0 $lab]
        $w delete $p1 $p2
        $w window create $p1 -window $lab
        set v [lindex $tags $ist 1]
        my makeLabelLinked $lab $v $fg $bg $fg2 $bg2
      } else {
        $w tag add $tag $p1 $p2
      }
    }
    my resetText $w $state
  }

# ________________________ EOC ::apave::APaveBase _________________________ #

}

# _____________________________ EOF _____________________________________ #
