apavebase.tcl
README.md

apavebase.tcl

  • apavebase.tcl
  • TCLLIBPATH
  • Remove installed subpackages of apave
  • apave NS
  •   apave variables
  •   default options & attributes of widgets
  •   Helpers
    • WindowStatus WindowStatus : 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
    • mainWindowOfApp mainWindowOfApp : Sets/gets a main window of application. win - window's path This should be run at application start, before opening any window.
    • IntStatus IntStatus : 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
    • iconImage iconImage : 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*.
    • iconData iconData : Gets an icon's data. icon - icon's name iconset - one of small/middle/large Returns data of the icon.
    • setAppIcon setAppIcon : 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.
    • getAppIcon getAppIcon : Gets application's icon.
    • precedeWidgetName precedeWidgetName : 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
    • defaultAttrs defaultAttrs : 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
    • focusApp focusApp : 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.
  •   Text little procs
    • eventOnText eventOnText : 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.
    • getTextHotkeys getTextHotkeys : Gets upper & lower keys for a hot key. key - the hot key
    • setTextHotkeys setTextHotkeys : 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
    • setTextIndent setTextIndent : Sets an indenting for text widgets. len - length of indenting padchar - indenting character
  •   EONS ::apave
  • source *.tcl
  • APaveBase oo::class
    • constructor constructor : 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
    • destructor destructor : Clears variables used in the object.
  •   Methods to be redefined
    • themePopup themePopup : Applies a color scheme to a popup menu. mnu - name of popup menu The method is to be redefined in descendants/mixins.
    • NonTtkTheme NonTtkTheme : Applies a current color scheme for non-ttk widgets. win - path to a window to be colored. Method to be redefined in descendants/mixins.
    • NonTtkStyle NonTtkStyle : 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
    • paveoptionValue paveoptionValue : Gets an option's value. opt - option's name Returns a value for options like "Moveall".
    • checkXY checkXY : 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)
    • CenteredXY CenteredXY : 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.
    • ownWName ownWName : Gets a tail (last part) of widget's name name - name (path) of the widget
    • parentWName parentWName : Gets parent name of widget. name - name (path) of the widget
    • iconA iconA : 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).
    • configure configure : Configures the apave object (all of options may be changed). args - list of pairs name/value of options Example: pobj configure edge "@@"
    • ExpandOptions ExpandOptions : Expands shortened options.
    • AddButtonIcon AddButtonIcon : 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
    • ListboxesAttrs ListboxesAttrs : 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
    • getWidChildren getWidChildren : Gets children of a widget. wid - widget's path treeName - name of variable to hold the result.
    • findWidPath findWidPath : 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.
  •   File content widget
    • FCfieldAttrs FCfieldAttrs : 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 \
    • FCfieldValues FCfieldValues : Fills the file content widget's values. wnamefull - name (path) of fco widget attrs - attributes of the widget
  •   Timeout button
    • timeoutButton timeoutButton : 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
    • checkTimeoutButton checkTimeoutButton : 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
  •   Making widgets
    • widgetType widgetType : 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
    • defaultATTRS defaultATTRS : 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*
    • MC MC : Gets localized message msg - the message to use a preset namespace name, we need a fully qualified variable
    • GetMC GetMC : Gets localized -text attribute. attrs - list of attributes
    • SpanConfig SpanConfig : The method is used by *GetIntOptions* method to configure row/column for their *span* options.
    • GetIntOptions GetIntOptions : 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 ", "-cw " etc. Returns the resulting grid options.
    • GetAttrs GetAttrs : 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.
    • menuTips menuTips : 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}"
  •   Option cascade
    • optionCascadeText optionCascadeText : 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
    • tk_optionCascade tk_optionCascade : 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)
    • OptionCascade_add OptionCascade_add : 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
    • ParentOpt ParentOpt : Gets *-parent* option for choosers. w - parent window's name (path)
  •   Mega-widgets
    • fillGutter fillGutter : 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.
    • bindGutter bindGutter : 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)
    • gutterContents gutterContents : Gets contents of a text's gutter txt - text's path
    • AuxSetChooserGeometry AuxSetChooserGeometry : 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.
    • validateColorChoice validateColorChoice : 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".
    • scrolledFrame scrolledFrame : Retrieves the path where the scrollable contents of frame go. w - frame's path
    • chooserGeomVars chooserGeomVars : 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
    • chooser chooser : 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.
    • colorChooser colorChooser : 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.
    • sourceKlnd sourceKlnd : Loads klnd package at need. num - defines which name of package file to be used
    • dateChooser dateChooser : Date chooser (calendar widget). tvar - name of variable containing a date args - options of *::klnd::calendar* Returns a selected date.
    • Replace_Tcl Replace_Tcl : 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.
    • Replace_chooser Replace_chooser : 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.
    • Replace_bar Replace_bar : 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
    • fontChooser fontChooser : 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.
    • toolbarItem_Attrs toolbarItem_Attrs : 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
  •   Widget names & methods
    • chooserPath chooserPath : Gets a path to chooser's entry or label. W - widget/method name (e.g. Fil, Dir) w - ent / lab for entry / label
    • Transname Transname : 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.
    • LowercaseWidgetName LowercaseWidgetName : 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
    • NormalizeName NormalizeName : 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
    • WidgetNameFull WidgetNameFull : 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
    • dlgPath dlgPath : Gets a window name of apave open dialogue.
    • DiaWidgetName DiaWidgetName : 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
    • MakeWidgetName MakeWidgetName : 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
    • AddPopupAttr AddPopupAttr : 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
    • clearEntry clearEntry : 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)
    • makePopup makePopup : 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
    • Pre Pre : "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
    • Post Post : 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
    • CleanUps CleanUps : 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
    • UpdateColors UpdateColors : Updates colors of widgets at changing CS.
  •   Links in labels
    • initLinkFont initLinkFont : 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.
    • labelFlashing labelFlashing : 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}
    • VisitedLab VisitedLab : 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
    • HoverLab HoverLab : 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
    • textLink textLink : Gets a label's path of a link in a text widget. w - text's path idx - index of the link
    • makeLabelLinked makeLabelLinked : 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"
    • leadingSpaces leadingSpaces : Returns a number of leading spaces of a line line - the line
  •   Text methods
    • SetContentVariable SetContentVariable : 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
    • GetContentVariable GetContentVariable : Gets an internal text variable. See also: SetContentVariable
    • SplitContentVariable SplitContentVariable : Gets parts of an internal text variable. See also: SetContentVariable
    • getTextContent getTextContent : Gets text content. tvar - text variable Uses an internal text variable to extract the text contents. Returns the content of text.
    • onKeyTextM onKeyTextM : Processes indents and braces at pressing keys. w - text's path K - key's name s - key's state
    • setTextBinds setTextBinds : Returns bindings for a text widget. wt - the text's path
    • TextCommandForChange TextCommandForChange : 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.
    • readonlyWidget readonlyWidget : 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)
    • GetOutputValues GetOutputValues : Makes output values for some widgets (lbx, fco). Some i/o widgets need a special method to get their returned values.
    • focusNext focusNext : 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)
    • AdditionalCommands AdditionalCommands : Gets additional commands (for non-standard attributes). w - window name wdg - widget's full path attrsName - variable name for widget's attributes
    • DefineWidgetKeys DefineWidgetKeys : 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.
  •   Paving windows
    • colorWindow colorWindow : Initialize colors of a window. win - window's path args - arguments for csSet
    • ShowOption ShowOption : Gets a default show option, used in showModal. name - name of option See also: getShowOption, setShowOption
    • getShowOption getShowOption : Gets a default show option, used in showModal. name - name of option defval - default value See also: showModal
    • setShowOption setShowOption : Sets / gets a default show option, used in showModal. name - name of option args - value of option See also: showModal
    • pavedPath pavedPath : Gets the currently paved window's path.
    • Window Window : 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.
    • Eval Eval
    • paveWindow paveWindow : 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.
    • window window : Obsolete version of paveWindow (remains for compatibility). See also: paveWindow
    • WinVarname WinVarname : Gets a unique varname for a window. win - window's path
    • waitWinVar waitWinVar : 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
    • showWindow showWindow : 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"
    • showModal showModal : Shows a window as modal. win - window's name args - attributes of window ("-name value" pairs)
    • res res : 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.
    • makeWindow makeWindow : 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.
    • displayText displayText : Sets the text widget's contents. w - text widget's name conts - contents to be set in the widget
    • resetText resetText : 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
    • displayTaggedText displayTaggedText : 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 ARMY. 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 .. 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.
  • EOC ::apave::APaveBase
  • EOF

apave

A library for GUI development with Tcl/Tk.

Docs:

Full description

apavebase.tcl
###########################################################
# 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 lamp restricted \
  attach share mail www map hamburger 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 {{} {-takefocus 0}} \
  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]]]
      }
      set il [string last -checkvar $label]
      if {$il<=0} {set il [string last -radiovar $label]}
      if {$il > 0} {
        set last [string range $label $il end]
        lassign $last optvar vname opt com
        set label [string trimright [string range $label 0 [incr il -1]]]
        set com [string map [list %t $label] $com]
        set but [string range $optvar 1 5]
        $w add ${but}button -label $label -variable $vname \
          {*}$args {*}$adds {*}[list $opt $com]
      } else {
        $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}
  if {![winfo exists $w]} {
    set w .
    catch {set w [winfo toplevel [focus]]}
  }
  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 {[catch {set fn [set $tvar]}]} {set fn {}}
    if {$fn 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 com [lindex [split $dn] 0] ;# command for initialdir
    if {$com ne {.} && [llength [info commands $com]]} {catch {set dn [eval $dn]}}
    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 {} && [string first GEO $ent]<0} {
    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 orvert 0
  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
      }
    } elseif {$nam eq {-orient}} {
      set orvert [string match vert* $val]
    } 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_}} {
      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 {v_}} {
      set ntmp [my Transname fra ${name}[incr j2]]
      set wid1 [list $ntmp - - - - "pack -in $w.$name -fill x"]
      set wid2 [list $ntmp.[my ownWName [my Transname h_ $name$j]] - - - - "pack -fill x -expand 1 -pady $v2"]
    } elseif {$v1 eq {seh}} {
      set ntmp [my Transname fra ${name}[incr j2]]
      set wid1 [list $ntmp - - - - "pack -in $w.$name -fill x"]
      set wid2 [list $ntmp.[my ownWName [my Transname seh $name$j]] - - - - "pack -fill x -expand 1 -pady $v2"]
    } elseif {$v1 eq {sev}} {
      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"]
      # 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 [string map [list %w $v1] $v2]
          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]
          }
        }
      }
      if {$orvert} {
        set wid1 [list $name.$v1 - - - - "pack $packreq" $v2]
        set lwidgets [linsert $lwidgets [incr itmp] $wid1]
        continue
      }
      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 - -onevent {
        # 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 {} \
              -Attrs {}] tip t2 Attrs
            set wt [my MakeWidgetName $w $fr]
            if {[string match lab* $fr]} {
              set wid ttk::label
            } elseif {[string match laB* $fr]} {
              set wid label
            } elseif {[string match fra* $fr]} {
              set wid ttk::frame
            } else {
              set wid frame
            }
            $w add [$wid $wt {*}$Attrs] {*}$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 {
        my 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"
        }
      }
      -onevent {
        set v [string map [list %w $w] $v]
        foreach {ev proc} $v {
          after idle [list bind $w $ev [subst $proc]]
        }
      }
    }
  }
}
#_______________________

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]
      my 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 Eval {args} {

  eval {*}$args
}
#_______________________

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 0} {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
  }
  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 _____________________________________ #

apavebase.tcl