apavedialog.tcl
README.md

apavedialog.tcl

  • apavedialog.tcl
  • apave NS
    • dlgPath dlgPath : Gets a current dialogue's path. In fact, it does the same as [my dlgPath], but it can be called outside of apave dialogue object (useful sometimes).
    • msgcatDialogs msgcatDialogs : Prepares localized messages used in dialogues.
  •   EONS apave
  • APaveDialog class
    • constructor constructor : Creates APaveDialog object. win - window's name (path) args - additional arguments
    • destructor destructor : Clears variables used in the object.
  •   Standard dialogs
    • PrepArgs PrepArgs : Prepares a list of arguments. Returns the list (wrapped in list) and a command for OK button.
    • ok ok : Shows the *OK* dialog. icon - icon ttl - title msg - message args - options
    • okcancel okcancel : Shows the *OKCANCEL* dialog. icon - icon ttl - title msg - message defb - button to be selected args - options
    • yesno yesno : Shows the *YESNO* dialog. icon - icon ttl - title msg - message defb - button to be selected args - options
    • yesnocancel yesnocancel : Shows the *YESNOCANCEL* dialog. icon - icon ttl - title msg - message defb - button to be selected args - options
    • retrycancel retrycancel : Shows the *RETRYCANCEL* dialog. icon - icon ttl - title msg - message defb - button to be selected args - options
    • abortretrycancel abortretrycancel : Shows the *ABORTRETRYCANCEL* dialog. icon - icon ttl - title msg - message defb - button to be selected args - options
    • misc misc : Shows the *MISCELLANEOUS* dialog. icon - icon ttl - title msg - message butts - list of buttons defb - button to be selected args - options The *butts* is a list of pairs "title of button" "number/ID of button"
  •   Progress for splash
    • progress_Begin progress_Begin : Creates and shows a progress window. Fit for splash screens. type - any word(s) wprn - parent window ttl - title message msg1 - top message msg2 - bottom message maxvalue - maximum value args - additional attributes of the progress bar If type={}, widgetType method participates too in progress_Go, and also progress_End puts out a little statistics. See also: APaveBase::widgetType, progress_Go, progress_End
    • progress_Go progress_Go : Updates a progress window. value - current value of the progress bar msg1 - top message msg2 - bottom message Returns current percents (value) of progress. If it reaches 100, the progress_Go may continue from 0. See also: progress_Begin
    • progress_End progress_End : Destroys a progress window. See also: progress_Begin
  •   Text utilities
    • pasteText pasteText : Removes a selection at pasting. txt - text's path The absence of this feature is very perpendicular of Tk's paste.
    • doubleText doubleText : Doubles a current line or a selection of text widget. txt - text's path dobreak - if true, means "return -code break" The *dobreak=true* allows to break the Tk processing of keypresses such as Ctrl+D. If not set, the text widget is identified as `my TexM`.
    • deleteLine deleteLine : Deletes a current line of text widget. txt - text's path dobreak - if true, means "return -code break" The *dobreak=true* allows to break the Tk processing of keypresses such as Ctrl+Y. If not set, the text widget is identified as `my TexM`.
    • linesMove linesMove : Moves a current line or lines of selection up/down. txt - text's path to - direction (-1 means "up", +1 means "down") dobreak - if true, means "return -code break" The *dobreak=true* allows to break the Tk processing of keypresses such as Ctrl+Y. If not set, the text widget is identified as `my TexM`.
    • selectedWordText selectedWordText : Returns a word under the cursor or a selected text. txt - the text's path
    • InitFindInText InitFindInText : Initializes the search in the text. ctrlf - "1" means that the method is called by Ctrl+F txt - path to the text widget
    • findInText findInText : Finds a string in text widget. donext - "1" means 'from a current position' txt - path to the text widget varFind - variable dobell - if yes, bells Returns yes, if found (or nothing to find), otherwise returns "no"; also, if there was a real search, the search string is added.
    • GetLinkLab GetLinkLab : Gets a link for label. m - label with possible link (between and ) Returns: list of "pure" message and link for label.
    • popupFindCommands popupFindCommands : Returns find commands for a popup menu on a text. pop - path to the menu txt - path to the text com1 - user's command "find first" com2 - user's command "find next"
    • popupBlockCommands popupBlockCommands : Returns block commands for a popup menu on a text. pop - path to the menu txt - path to the text
    • askForSave askForSave : For a text, sets/gets "ask for save changes" flag. wtxt - text's path doask - flag If the flag argument omitted, returns the flag else sets it. See also: constructor
  •   Highlighting
    • popupHighlightCommands popupHighlightCommands : Returns highlighting commands for a popup menu on a text. pop - path to the menu txt - path to the text
    • set_HighlightedString set_HighlightedString : Saves a string got from highlighting by Alt+left/right/q/w. sel - the string to be saved
    • get_HighlightedString get_HighlightedString : Returns a string got from highlighting by Alt+left/right/q/w.
    • set_highlight_matches set_highlight_matches : Creates bindings to highlight matches in a text. w - path to the text
    • get_highlighted get_highlighted : Gets a selected word after double-clicking on a text. w - path to the text
    • highlight_matches highlight_matches : Highlights matches of selected word in a text. txt - path to the text
    • unhighlight_matches unhighlight_matches : Unhighlights matches of selected word in a text. w - path to the text
    • seek_highlight seek_highlight : Seeks the selected word forward/backward/to first/to last in a text. w - path to the text mode - 0 (search backward), 1 (forward), 2 (first), 3 (last)
    • highlight_matches_real highlight_matches_real : Highlights a selected word in a text, esp. fow Windows. Windows thinks a word is edged by spaces only: not in real case. txt - path to the text pos1 - starting position of real selection pos2 - ending position of real selection
  •   Query's auxiliaries
    • varName varName : Gets a variable name associated with a widget's name of "input" dialogue. wname - widget's name
    • FieldName FieldName : Gets a field name.
    • GetVarsValues GetVarsValues : Gets values of entries passed (or set) in -tvar. lwidgets - list of widget items
    • SetGetTexts SetGetTexts : Sets/gets contents of text fields. oper - "set" to set, "get" to get contents of text field w - window's name iopts - equals to "" if no operation lwidgets - list of widget items
    • GetLinePosition GetLinePosition : Gets a line's position. txt - text widget ind - index of the line Returns a list containing a line start and a line end.
    • AppendButtons AppendButtons : Adds buttons to the widget list from a position of neighbor widget. widlistName - variable name for widget list buttons - buttons to add neighbor - neighbor widget pos - position of neighbor widget defb - default button timeout - timeout (to count down seconds and invoke a button) win - dialogue's path modal - yes if the window is modal ONCLOSE - command to run at closing the dialog Returns list of "Help" button's name and command.
  •   Query the terrible
    • Query Query : Makes a query (or a message) and gets the user's response. icon - icon name (info, warn, ques, err) ttl - title msg - message buttons - list of triples "button name, text, ID" defb - default button (OK, YES, NO, CANCEL, RETRY, ABORT) inopts - options for input dialog argdia - list of dialog's options precom - command(s) performed before showing the dialog args - additional options (message's font etc.) The *argdia* may contain additional options of the query, like these: -checkbox text (-ch text) - makes the checkbox's text visible -geometry +x+y (-g +x+y) - sets the geometry of dialog -color cval (-c cval) - sets the color of message If "-geometry" option is set (even equaling "") the Query procedure returns a list with chosen button's ID and a new geometry. Otherwise it returns only the chosen button's ID. See also: [aplsimple.github.io](https://aplsimple.github.io/en/tcl/pave/index.html)
  • EOC APaveDialog
  • EOF

apave

A library for GUI development with Tcl/Tk.

Docs:

Full description

apavedialog.tcl
###########################################################
# Name:    apavedialog.tcl
# Author:  Alex Plotnikov  (aplsimple@gmail.com)
# Date:    12/09/2021
# Brief:   Handles standard dialogs with advanced features.
# License: MIT.
###########################################################

source [file join [file dirname [info script]] apavebase.tcl]

# ________________________ apave NS _________________________ #

namespace eval ::apave {

variable querydlg {}
variable msgarray; array set msgarray [list]
set msgarray(savenot)  {Don't save}
set msgarray(savetext) {Save text}
set msgarray(saveask)  {Save changes made to the text?}
set msgarray(find)     {Find: }

proc dlgPath {}  {
  # Gets a current dialogue's path.
  # In fact, it does the same as [my dlgPath], but it can be
  # called outside of apave dialogue object (useful sometimes).

  return $::apave::querydlg
}
#_______________________

proc msgcatDialogs {} {
  # Prepares localized messages used in dialogues.

  variable msgarray
  foreach n [array names msgarray] {
    set msgarray($n) [msgcat::mc $msgarray($n)]
  }
}

## ________________________ EONS apave _________________________ ##

}

# ________________________ APaveDialog class _________________________ #

oo::class create ::apave::APaveDialog {

superclass ::apave::APaveBase

variable HLstring Winpath CheckNomore Foundstr Dlgpath Defb1 Defb2 Indexdlg

#_______________________

constructor {{win ""} args} {
  # Creates APaveDialog object.
  #   win - window's name (path)
  #   args - additional arguments

  set Winpath $win  ;# dialogs are bound to $win, default "" means .
  set Dlgpath {}    ;# current dialog's path
  set Foundstr {}   ;# current found string
  set HLstring {}   ;# current selected string

  # Actions on closing the editor
; proc exitEditor {w resExit} {
    upvar $resExit res
    set wtxt [my TexM]
    if {[my askForSave $wtxt] && [$wtxt edit modified]} {
      set pdlg [::apave::APaveDialog new $w]
      set r [$pdlg misc warn $::apave::msgarray(savetext) \
        "\n $::apave::msgarray(saveask) \n" \
        [list Save 1 $::apave::msgarray(savenot) Close Cancel 0] \
        1 -focusback [my TexM] -centerme $w]
      if {$r==1} {
        set res 1
      } elseif {$r eq "Close"} {
        set res 0
      }
      $pdlg destroy
    } else {
      set res 0
    }
    return
  }
  # end of APaveDialog constructor
  if {[llength [self next]]} { next {*}$args }
}
#_______________________

destructor {
  # Clears variables used in the object.

  if {[llength [self next]]} next
}

## ________________________ Standard dialogs _________________________ ##

#  ok               - dialog with button OK
#  okcancel         - dialog with buttons OK, Cancel
#  yesno            - dialog with buttons YES, NO
#  yesnocancel      - dialog with buttons YES, NO, CANCEL
#  retrycancel      - dialog with buttons RETRY, CANCEL
#  abortretrycancel - dialog with buttons ABORT, RETRY, CANCEL
#  misc             - dialog with miscellaneous buttons
#
# Called as:
#   dialog icon ttl msg ?defb? ?args?
#
# Mandatory arguments of dialogs:
#   icon   - icon name (info, warn, err, ques)
#   ttl    - title
#   msg    - message
# Optional arguments:
#   defb - default button (OK, YES, NO, CANCEL, RETRY, ABORT)
#   args - options for Query
#_______________________

method PrepArgs {args} {
  # Prepares a list of arguments.
  # Returns the list (wrapped in list) and a command for OK button.

  lassign [::apave::parseOptions $args -modal {} -ch {} -comOK {} -onclose {}] \
    modal ch comOK onclose
  if {[string is true -strict $modal]} {
    set com 1
  } elseif {$ch ne {}} {
    # some options are incompatible with -ch
    if {[string match *destroy* $onclose]} {set onclose {}}
    lappend args -modal 1 -onclose $onclose
    set com 1
  } elseif {$comOK eq {}} {
    set com destroy  ;# non-modal without -ch option
  } else {
    set com $comOK
  }
  list [list $args] $com
}
#_______________________

method ok {icon ttl msg args} {
  # Shows the *OK* dialog.
  #   icon - icon
  #   ttl - title
  #   msg - message
  #   args - options

  lassign [my PrepArgs {*}$args] args comOK
  my Query $icon $ttl $msg "ButOK OK $comOK" ButOK {} $args
}
#_______________________

method okcancel {icon ttl msg {defb OK} args} {
  # Shows the *OKCANCEL* dialog.
  #   icon - icon
  #   ttl - title
  #   msg - message
  #   defb - button to be selected
  #   args - options

  lassign [my PrepArgs {*}$args] args
  my Query $icon $ttl $msg \
    {ButOK OK 1 ButCANCEL Cancel 0} But$defb {} $args
}
#_______________________

method yesno {icon ttl msg {defb YES} args} {
  # Shows the *YESNO* dialog.
  #   icon - icon
  #   ttl - title
  #   msg - message
  #   defb - button to be selected
  #   args - options

  lassign [my PrepArgs {*}$args] args
  my Query $icon $ttl $msg \
    {ButYES Yes 1 ButNO No 0} But$defb {} $args
}
#_______________________

method yesnocancel {icon ttl msg {defb YES} args} {
  # Shows the *YESNOCANCEL* dialog.
  #   icon - icon
  #   ttl - title
  #   msg - message
  #   defb - button to be selected
  #   args - options

  lassign [my PrepArgs {*}$args] args
  my Query $icon $ttl $msg \
    {ButYES Yes 1 ButNO No 2 ButCANCEL Cancel 0} But$defb {} $args
}
#_______________________

method retrycancel {icon ttl msg {defb RETRY} args} {
  # Shows the *RETRYCANCEL* dialog.
  #   icon - icon
  #   ttl - title
  #   msg - message
  #   defb - button to be selected
  #   args - options

  lassign [my PrepArgs {*}$args] args
  my Query $icon $ttl $msg \
    {ButRETRY Retry 1 ButCANCEL Cancel 0} But$defb {} $args
}
#_______________________

method abortretrycancel {icon ttl msg {defb RETRY} args} {
  # Shows the *ABORTRETRYCANCEL* dialog.
  #   icon - icon
  #   ttl - title
  #   msg - message
  #   defb - button to be selected
  #   args - options

  lassign [my PrepArgs {*}$args] args
  my Query $icon $ttl $msg \
    {ButABORT Abort 1 ButRETRY Retry 2 ButCANCEL \
    Cancel 0} But$defb {} $args
}
#_______________________

method misc {icon ttl msg butts {defb ""} args} {
  # Shows the *MISCELLANEOUS* dialog.
  #   icon - icon
  #   ttl - title
  #   msg - message
  #   butts - list of buttons
  #   defb - button to be selected
  #   args - options
  # The *butts* is a list of pairs "title of button" "number/ID of button"

  foreach {nam num} $butts {
    set but But[namespace tail $num] ;# for "num" set as a command
    lappend apave_msc_bttns $but "$nam" $num
    if {$defb eq {}} {
      set defb $num
    }
  }
  lassign [my PrepArgs {*}$args] args
  my Query $icon $ttl $msg $apave_msc_bttns But$defb {} $args
}

## ________________________ Progress for splash _________________________ ##

method progress_Begin {type wprn ttl msg1 msg2 maxvalue args} {
  # Creates and shows a progress window. Fit for splash screens.
  #   type - any word(s)
  #   wprn - parent window
  #   ttl - title message
  #   msg1 - top message
  #   msg2 - bottom message
  #   maxvalue - maximum value
  #   args - additional attributes of the progress bar
  # If type={}, widgetType method participates too in progress_Go, and also
  # progress_End puts out a little statistics.
  # See also: APaveBase::widgetType, progress_Go, progress_End

  set ::apave::_AP_VARS(win) .proSplashScreen
  set qdlg $::apave::_AP_VARS(win)
  set atr1 "-maximum 100 -value 0 -mode determinate -length 300 -orient horizontal"
  set widlist [list \
    "fra - - - - pack {-h 10}" \
    ".Lab1SplashScreen - - - - pack {-t {$msg1}}" \
    ".ProgSplashScreen - - - - pack {$atr1 $args}" \
    ".Lab2SplashScreen - - - - {pack -anchor w} {-t {$msg2}}" \
    ]
  set win [my makeWindow $qdlg.fra $ttl]
  set widlist [my paveWindow $qdlg.fra $widlist]
  ::tk::PlaceWindow $win widget $wprn
  my showWindow $win 0 1
  update
  set ::apave::_AP_VARS(ProSplash,type) $type
  set ::apave::_AP_VARS(ProSplash,win) $win
  set ::apave::_AP_VARS(ProSplash,wid1) [my Lab1SplashScreen]
  set ::apave::_AP_VARS(ProSplash,wid2) [my ProgSplashScreen]
  set ::apave::_AP_VARS(ProSplash,wid3) [my Lab2SplashScreen]
  set ::apave::_AP_VARS(ProSplash,val1) 0
  set ::apave::_AP_VARS(ProSplash,val2) 0
  set ::apave::_AP_VARS(ProSplash,value) 0
  set ::apave::_AP_VARS(ProSplash,curvalue) 0
  set ::apave::_AP_VARS(ProSplash,maxvalue) $maxvalue
  set ::apave::_AP_VARS(ProSplash,after) [list]
  # 'after' should be postponed, as 'update' messes it up
  rename ::after ::ProSplash_after
; proc ::after {args} {
    lappend ::apave::_AP_VARS(ProSplash,after) $args
  }
}
#_______________________

method progress_Go {value {msg1 ""} {msg2 ""}} {
  # Updates a progress window.
  #   value -  current value of the progress bar
  #   msg1 - top message
  #   msg2 - bottom message
  # Returns current percents (value) of progress.
  # If it reaches 100, the progress_Go may continue from 0.
  # See also: progress_Begin

  set ::apave::_AP_VARS(ProSplash,val1) $value
  incr ::apave::_AP_VARS(ProSplash,val2)
  set val [expr {min(100,int(100*$value/$::apave::_AP_VARS(ProSplash,maxvalue)))}]
  if {$val!=$::apave::_AP_VARS(ProSplash,value)} {
    set ::apave::_AP_VARS(ProSplash,value) $val
    catch {  ;# there might be no splash widgets, then let it run dry
      $::apave::_AP_VARS(ProSplash,wid2) configure -value $val
      if {$msg1 ne {}} {
        $::apave::_AP_VARS(ProSplash,wid1) configure -text $msg1
      }
      if {$msg2 ne {}} {
        $::apave::_AP_VARS(ProSplash,wid3) configure -text $msg2
      }
      update
    }
  }
  return $val
}
#_______________________

method progress_End {} {
  # Destroys a progress window.
  # See also: progress_Begin

  variable ::apave::_AP_VARS
  catch {
    destroy $::apave::_AP_VARS(ProSplash,win)
    rename ::after {}
    rename ::ProSplash_after ::after
    foreach aftargs $::apave::_AP_VARS(ProSplash,after) {
      after {*}$aftargs
    }
    if {$::apave::_AP_VARS(ProSplash,type) eq {}} {
      puts "Splash statistics: \
        \n  \"maxvalue\": $::apave::_AP_VARS(ProSplash,maxvalue) \
        \n  curr.value: $::apave::_AP_VARS(ProSplash,val1) \
        \n  steps made: $::apave::_AP_VARS(ProSplash,val2)"
    }
    unset ::apave::_AP_VARS(ProSplash,type)
    unset ::apave::_AP_VARS(ProSplash,win)
    unset ::apave::_AP_VARS(ProSplash,wid1)
    unset ::apave::_AP_VARS(ProSplash,wid2)
    unset ::apave::_AP_VARS(ProSplash,wid3)
    unset ::apave::_AP_VARS(ProSplash,val1)
    unset ::apave::_AP_VARS(ProSplash,val2)
    unset ::apave::_AP_VARS(ProSplash,value)
    unset ::apave::_AP_VARS(ProSplash,curvalue)
    unset ::apave::_AP_VARS(ProSplash,maxvalue)
    unset ::apave::_AP_VARS(ProSplash,after)
  }
}

## ________________________ Text utilities _________________________ ##

method pasteText {txt} {
  # Removes a selection at pasting.
  #   txt - text's path
  # The absence of this feature is very perpendicular of Tk's paste.

  set err [catch {$txt tag ranges sel} sel]
  if {!$err && [llength $sel]==2} {
    lassign $sel pos1 pos2
    set pos [$txt index insert]
    if {[$txt compare $pos >= $pos1] && [$txt compare $pos <= $pos2]} {
      $txt delete $pos1 $pos2
    }
  }
}
#_______________________

method doubleText {txt {dobreak 1}} {
  # Doubles a current line or a selection of text widget.
  #   txt - text's path
  #   dobreak - if true, means "return -code break"
  # The *dobreak=true* allows to break the Tk processing of keypresses
  # such as Ctrl+D.
  # If not set, the text widget is identified as `my TexM`.

  if {$txt eq {}} {set txt [my TexM]}
  set err [catch {$txt tag ranges sel} sel]
  if {!$err && [llength $sel]==2} {
    lassign $sel pos pos2
    set pos3 insert  ;# single selection
  } else {
    lassign [my GetLinePosition $txt insert] pos pos2  ;# current line
    set pos3 $pos2
  }
  set duptext [$txt get $pos $pos2]
  if {$pos3 ne {insert} && $pos2==[$txt index end]} {
    # current line is the last one: duplicate it properly
    set duptext \n[string range $duptext 0 end-1]
  }
  $txt insert $pos3 $duptext
  if {$dobreak} {return -code break}
}
#_______________________

method deleteLine {txt {dobreak 1}} {
  # Deletes a current line of text widget.
  #   txt - text's path
  #   dobreak - if true, means "return -code break"
  # The *dobreak=true* allows to break the Tk processing of keypresses
  # such as Ctrl+Y.
  # If not set, the text widget is identified as `my TexM`.

  if {$txt eq {}} {set txt [my TexM]}
  lassign [my GetLinePosition $txt insert] linestart lineend
  $txt delete $linestart $lineend
  if {$dobreak} {return -code break}
}
#_______________________

method linesMove {txt to {dobreak 1}} {
  # Moves a current line or lines of selection up/down.
  #   txt - text's path
  #   to - direction (-1 means "up", +1 means "down")
  #   dobreak - if true, means "return -code break"
  # The *dobreak=true* allows to break the Tk processing of keypresses
  # such as Ctrl+Y.
  # If not set, the text widget is identified as `my TexM`.

; proc NewRow {ind rn} {
    set i [string first . $ind]
    set row [string range $ind 0 $i-1]
    return [incr row $rn][string range $ind $i end]
  }
  if {$txt eq {}} {set txt [my TexM]}
  set err [catch {$txt tag ranges sel} sel]
  lassign [$txt index insert] pos  ;# position of caret
  if {[set issel [expr {!$err && [llength $sel]==2}]]} {
    lassign $sel pos1 pos2         ;# selection's start & end
    set l1 [expr {int($pos1)}]
    set l2 [expr {int($pos2)}]
    set pos21 [$txt index "$pos2 linestart"]
    if {[$txt get $pos21 $pos2] eq {}} {incr l2 -1}
    set lfrom [expr {$to>0 ? $l2+1 : $l1-1}]
    set lto   [expr {$to>0 ? $l1-1 : $l2-1}]
  } else {
    set lcurr [expr {int($pos)}]
    set lfrom [expr {$to>0 ? $lcurr+1 : $lcurr-1}]
    set lto   [expr {$to>0 ? $lcurr-1 : $lcurr-1}]
  }
  set lend [expr {int([$txt index end])}]
  if {$lfrom>0 && $lfrom<$lend} {
    incr lto
    lassign [my GetLinePosition $txt $lfrom.0] linestart lineend
    set duptext [$txt get $linestart $lineend]
    ::apave::undoIn $txt
    $txt delete $linestart $lineend
    $txt insert $lto.0 $duptext
    ::tk::TextSetCursor $txt [NewRow $pos $to]
    if {$issel} {
      $txt tag add sel [NewRow $pos1 $to] [NewRow $pos2 $to]
    }
    if {[lsearch -glob [$txt tag names] tagCOM*]>-1} {
      catch {::hl_tcl::my::Modified $txt insert $lto.0 $lto.end}
    }
    ::apave::undoOut $txt
    if {$dobreak} {return -code break}
  }
}
#_______________________

method selectedWordText {txt} {
  # Returns a word under the cursor or a selected text.
  #   txt - the text's path

  set seltxt {}
  if {![catch {$txt tag ranges sel} seltxt]} {
    if {[set forword [expr {$seltxt eq {}}]]} {
      set pos  [$txt index "insert wordstart"]
      set pos2 [$txt index "insert wordend"]
      set seltxt [string trim [$txt get $pos $pos2]]
      if {![string is wordchar -strict $seltxt]} {
        # when cursor just at the right of word: take the word at the left
        set pos  [$txt index "insert -1 char wordstart"]
        set pos2 [$txt index "insert -1 char wordend"]
      }
    } else {
      lassign $seltxt pos pos2
    }
    catch {
      set seltxt [$txt get $pos $pos2]
      if {[set sttrim [string trim $seltxt]] ne {}} {
        if {$forword} {set seltxt $sttrim}
      }
    }
  }
  return $seltxt
}
#_______________________

method InitFindInText { {ctrlf 0} {txt {}} } {
  # Initializes the search in the text.
  #   ctrlf - "1" means that the method is called by Ctrl+F
  #   txt - path to the text widget

  if {$txt eq {}} {set txt [my TexM]}
  if {$ctrlf} {  ;# Ctrl+F moves cursor 1 char ahead
    ::tk::TextSetCursor $txt [$txt index "insert -1 char"]
  }
  if {[set seltxt [my selectedWordText $txt]] ne {}} {
    set Foundstr $seltxt
  }
}
#_______________________

method findInText {{donext 0} {txt ""} {varFind ""} {dobell yes}} {
  # Finds a string in text widget.
  #   donext - "1" means 'from a current position'
  #   txt - path to the text widget
  #   varFind - variable
  #   dobell - if yes, bells
  # Returns yes, if found (or nothing to find), otherwise returns "no";
  # also, if there was a real search, the search string is added.

  if {$txt eq {}} {
    set txt [my TexM]
    set sel $Foundstr
  } elseif {$donext && [set sel [my get_HighlightedString]] ne {}} {
    # find a string got with alt+left/right
  } elseif {$varFind eq {}} {
    set sel $Foundstr
  } else {
    set sel [set $varFind]
  }
  if {$donext} {
    set pos [$txt index insert]
    if {{sel} in [$txt tag names $pos]} {
      set pos [$txt index "$pos + 1 chars"]
    }
    set pos [$txt search -- $sel $pos end]
  } else {
    set pos {}
    my set_HighlightedString {}
  }
  if {![string length "$pos"]} {
    set pos [$txt search -- $sel 1.0 end]
  }
  if {[string length "$pos"]} {
    ::tk::TextSetCursor $txt $pos
    $txt tag add sel $pos [$txt index "$pos + [string length $sel] chars"]
    focus $txt
    set res yes
  } else {
    if {$dobell} bell
    set res no
  }
  list $res $sel
}
#_______________________

method GetLinkLab {m} {
  # Gets a link for label.
  #   m - label with possible link (between <link> and </link>)
  # Returns: list of "pure" message and link for label.

  if {[set i1 [string first "<link>" $m]]<0} {
    return [list $m]
  }
  set i2 [string first "</link>" $m]
  set link [string range $m $i1+6 $i2-1]
  set m [string range $m 0 $i1-1][string range $m $i2+7 end]
  list $m [list -link $link]
}
#_______________________

method popupFindCommands {pop {txt {}} {com1 ""} {com2 ""}} {
  # Returns find commands for a popup menu on a text.
  #   pop - path to the menu
  #   txt - path to the text
  #   com1 - user's command "find first"
  #   com2 - user's command "find next"

  set accF3 [::apave::KeyAccelerator [::apave::getTextHotkeys F3]]
  if {$com1 eq {}} {set com1 "[self] InitFindInText 0 $txt; focus \[[self] Entfind\]"}
  if {$com2 eq {}} {set com2 "[self] findInText 1 $txt"}
  return "\$pop add separator
    \$pop add command [my iconA find] -accelerator Ctrl+F -label \"Find First\" \\
      -command {$com1}
    \$pop add command [my iconA none] -accelerator $accF3 -label \"Find Next\" \\
      -command {$com2}"
}
#_______________________

method popupBlockCommands {pop {txt {}}} {
  # Returns block commands for a popup menu on a text.
  #   pop - path to the menu
  #   txt - path to the text

  set accD [::apave::KeyAccelerator [::apave::getTextHotkeys CtrlD]]
  set accY [::apave::KeyAccelerator [::apave::getTextHotkeys CtrlY]]
  return "\$pop add separator
    \$pop add command [my iconA add] -accelerator $accD -label \"Double Selection\" \\
      -command \"[self] doubleText {$txt} 0\"
    \$pop add command [my iconA delete] -accelerator $accY -label \"Delete Line\" \\
      -command \"[self] deleteLine {$txt} 0\"
    \$pop add command [my iconA up] -accelerator Alt+Up -label \"Line(s) Up\" \\
      -command \"[self] linesMove {$txt} -1 0\"
    \$pop add command [my iconA down] -accelerator Alt+Down -label \"Line(s) Down\" \\
      -command \"[self] linesMove {$txt} +1 0\""
}
#_______________________

method askForSave {wtxt {doask ""}} {
  # For a text, sets/gets "ask for save changes" flag.
  #   wtxt - text's path
  #   doask - flag
  # If the flag argument omitted, returns the flag else sets it.
  # See also: constructor

  set prop _AskForSave_$wtxt
  if {$doask eq {}} {
    set res [::apave::getProperty $prop]
    if {![string is false -strict $res]} {set res 1}
  } else {
    set res [::apave::setProperty $prop $doask]
  }
  return $res
}

## ________________________ Highlighting _________________________ ##

method popupHighlightCommands {{pop ""} {txt ""}} {
  # Returns highlighting commands for a popup menu on a text.
  #   pop - path to the menu
  #   txt - path to the text

  set accQ [::apave::KeyAccelerator [::apave::getTextHotkeys AltQ]]
  set accW [::apave::KeyAccelerator [::apave::getTextHotkeys AltW]]
  set res "\$pop add separator
    \$pop add command [my iconA upload] -accelerator $accQ \\
    -label \"Highlight First\" -command \"[self] seek_highlight %w 2\"
    \$pop add command [my iconA download] -accelerator $accW \\
    -label \"Highlight Last\" -command \"[self] seek_highlight %w 3\"
    \$pop add command [my iconA previous] -accelerator Alt+Left \\
    -label \"Highlight Previous\" -command \"[self] seek_highlight %w 0\"
    \$pop add command [my iconA next] -accelerator Alt+Right \\
    -label \"Highlight Next\" -command \"[self] seek_highlight %w 1\"
    \$pop add command [my iconA none] -accelerator Dbl.Click \\
    -label \"Highlight All\" -command \"[self] highlight_matches %w\""
  if {$txt ne {}} {set res [string map [list %w $txt] $res]}
  return $res
}
#_______________________

method set_HighlightedString {sel} {
  # Saves a string got from highlighting by Alt+left/right/q/w.
  #   sel - the string to be saved

  set HLstring $sel
  if {$sel ne {}} {set Foundstr $sel}
}
#_______________________

method get_HighlightedString {} {
  # Returns a string got from highlighting by Alt+left/right/q/w.

  if {[info exists HLstring]} {
    return $HLstring
  }
  return {}
}
#_______________________

method set_highlight_matches {w} {
  # Creates bindings to highlight matches in a text.
  #   w - path to the text

  if {![winfo exists $w]} return
  $w tag configure hilited -foreground #1f0000 -background #ffa073
  $w tag configure hilited2 -foreground #1f0000 -background #ff6b85
  $w tag lower hilited sel
  bind $w <Double-ButtonPress-1> [list [self] highlight_matches $w]
  ::apave::bindToEvent $w <KeyRelease> [self] unhighlight_matches $w
  bind $w <Alt-Left> "[self] seek_highlight $w 0 ; break"
  bind $w <Alt-Right> "[self] seek_highlight $w 1 ; break"
  foreach k [::apave::getTextHotkeys AltQ] {
    bind $w <$k> [list [self] seek_highlight $w 2]
  }
  foreach k [::apave::getTextHotkeys AltW] {
    bind $w <$k> [list [self] seek_highlight $w 3]
  }
}
#_______________________

method get_highlighted {txt} {
  # Gets a selected word after double-clicking on a text.
  #   w - path to the text

  set err [catch {$txt tag ranges sel} sel]
  lassign $sel pos pos2
  if {!$err && [llength $sel]==2} {
    set sel [$txt get $pos $pos2]  ;# single selection
  } else {
    if {$err || [string trim $sel] eq {}} {
      set pos  [$txt index "insert wordstart"]
      set pos2 [$txt index "insert wordend"]
      set sel [string trim [$txt get $pos $pos2]]
      if {![string is wordchar -strict $sel]} {
        # when cursor just at the right of word: take the word at the left
        # e.g. if "_" stands for cursor then "word_" means selecting "word"
        set pos  [$txt index "insert -1 char wordstart"]
        set pos2 [$txt index "insert -1 char wordend"]
        set sel [string trim [$txt get $pos $pos2]]
      }
      set slen [string length $sel]
      if {!$slen} {incr slen; set pos2 [$txt index "$pos2 +1c"]}
      set pos [$txt index "$pos2 -$slen char"]
      set sel [string trim [$txt get $pos $pos2]]
    }
  }
  list $sel $pos $pos2
}
#_______________________

method highlight_matches {txt} {
  # Highlights matches of selected word in a text.
  #   txt - path to the text

  lassign [my get_highlighted $txt] sel pos pos2
  if {$sel eq {}} return
  after idle "[self] highlight_matches_real $txt $pos $pos2"
  my set_HighlightedString $sel
  set lenList {}
  set posList [$txt search -all -count lenList -- "$sel" 1.0 end]
  foreach pos2 $posList len $lenList {
    if {$len eq {}} {set len [string length $sel]}
    set pos3 [$txt index "$pos2 + $len chars"]
    if {$pos2 == $pos} {
      lappend matches2 $pos2 $pos3
    } else {
      lappend matches1 $pos2 $pos3
    }
  }
  catch {
    $txt tag remove hilited 1.0 end
    $txt tag remove hilited2 1.0 end
    $txt tag add hilited {*}$matches1
    $txt tag add hilited2 {*}$matches2
  }
  set ::apave::_AP_VARS(HILI,$txt) yes
}
#_______________________

method unhighlight_matches {txt} {
  # Unhighlights matches of selected word in a text.
  #   w - path to the text

  if {[info exists ::apave::_AP_VARS(HILI,$txt)] && $::apave::_AP_VARS(HILI,$txt)} {
    $txt tag remove hilited 1.0 end
    $txt tag remove hilited2 1.0 end
    set ::apave::_AP_VARS(HILI,$txt) no
  }
}
#_______________________

method seek_highlight {txt mode} {
  # Seeks the selected word forward/backward/to first/to last in a text.
  #   w - path to the text
  #   mode - 0 (search backward), 1 (forward), 2 (first), 3 (last)

  my unhighlight_matches $txt
  lassign [my get_highlighted $txt] sel pos pos2
  if {$sel eq {}} return
  my set_HighlightedString $sel
  switch $mode {
    0 { ;# backward
      set nc [expr {[string length $sel] - 1}]
      set pos [$txt index "$pos - $nc chars"]
      set pos [$txt search -backwards -- $sel $pos 1.0]
    }
    1 { ;# forward
      set pos [$txt search -- $sel $pos2 end]
    }
    2 { ;# to first
      set pos [$txt search -- $sel 1.0 end]
    }
    3 { ;# to last
      set pos [$txt search -backwards -- $sel end 1.0]
    }
  }
  if {[string length "$pos"]} {
    ::tk::TextSetCursor $txt $pos
    $txt tag add sel $pos [$txt index "$pos + [string length $sel] chars"]
  }
}
#_______________________

method highlight_matches_real {txt pos1 pos2} {
  # Highlights a selected word in a text, esp. fow Windows.
  # Windows thinks a word is edged by spaces only: not in real case.
  #   txt - path to the text
  #   pos1 - starting position of real selection
  #   pos2 - ending position of real selection

  $txt tag remove sel 1.0 end
  if {[$txt get $pos1] eq "\n"} {
    # if a word at line start, Windows select an empty line above
    lassign [split $pos1 .] l c
    set pos1 [incr l].$c
  }
  catch {::tk::TextSetCursor $txt $pos1}
  $txt tag add sel $pos1 $pos2
}

## ________________________ Query's auxiliaries _________________________ ##

method varName {wname} {
  # Gets a variable name associated with a widget's name of "input" dialogue.
  #   wname - widget's name

  return [namespace current]::var$wname
}
#_______________________

method FieldName {name} {
  # Gets a field name.

  return fraM.fra$name.$name
}
#_______________________

method GetVarsValues {lwidgets} {
  # Gets values of entries passed (or set) in -tvar.
  #   lwidgets - list of widget items

  set res [set vars [list]]
  foreach wl $lwidgets {
    set ownname [my ownWName [lindex $wl 0]]
    set vv [my varName $ownname]
    set attrs [lindex $wl 6]
    if {[string match "ra*" $ownname]} {
      # only for widgets with a common variable (e.g. radiobuttons):
      foreach t {-var -tvar} {
        if {[set v [::apave::getOption $t {*}$attrs]] ne {}} {
          array set a $attrs
          set vv $v
        }
      }
    }
    if {[info exist $vv] && [lsearch $vars $vv]==-1} {
      lappend res [set $vv]
      lappend vars $vv
    }
  }
  return $res
}
#_______________________

method SetGetTexts {oper w iopts lwidgets} {
  # Sets/gets contents of text fields.
  #   oper - "set" to set, "get" to get contents of text field
  #   w - window's name
  #   iopts - equals to "" if no operation
  #   lwidgets - list of widget items

  if {$iopts eq {}} return
  foreach widg $lwidgets {
    set wname [lindex $widg 0]
    set name [my ownWName $wname]
    if {[string range $name 0 1] eq "te"} {
      set vv [my varName $name]
      if {$oper eq "set"} {
        my displayText $w.$wname [set $vv]
      } else {
        set $vv [string trimright [$w.$wname get 1.0 end]]
      }
    }
  }
}
#_______________________

method GetLinePosition {txt ind} {
  # Gets a line's position.
  #   txt - text widget
  #   ind - index of the line
  # Returns a list containing a line start and a line end.

  set linestart [$txt index "$ind linestart"]
  set lineend   [expr {$linestart + 1.0}]
  list $linestart $lineend
}
#_______________________

method AppendButtons {widlistName buttons neighbor pos defb timeout win modal ONCLOSE} {
  # Adds buttons to the widget list from a position of neighbor widget.
  #   widlistName - variable name for widget list
  #   buttons - buttons to add
  #   neighbor - neighbor widget
  #   pos - position of neighbor widget
  #   defb - default button
  #   timeout  - timeout (to count down seconds and invoke a button)
  #   win - dialogue's path
  #   modal - yes if the window is modal
  #   ONCLOSE - command to run at closing the dialog
  # Returns list of "Help" button's name and command.

  upvar $widlistName widlist
  set Defb1 [set Defb2 [set bhlist {}]]
  foreach {but txt res} $buttons {
    set com "[self] res $Dlgpath"
    if {[info commands $res] eq {}} {
      set com "$com $res"
    } else {
      if {$res eq {destroy}} {
        # for compatibility with old modal windows
        if {$modal} {set res "$com 0"} {set res "destroy $win"}
      }
      set com $res  ;# "res" is set as a command
    }
    if {$but eq {butHELP}} {
      # Help button contains the command in "res"
      set com [string map "%w $win" $res]
      set bhlist [list $but $com]
    } elseif {$Defb1 eq {}} {
      set Defb1 $but
    } elseif {$Defb2 eq {}} {
      set Defb2 $but
    }
    if {$ONCLOSE ne {}} {append com " ; $ONCLOSE"}
    if {[set _ [string first "::" $txt]]>-1} {
      set tt " -tip {[string range $txt $_+2 end]}"
      set txt [string range $txt 0 $_-1]
    } else {
      set tt {}
    }
    if {$timeout ne {} && ($defb eq $but || $defb eq {})} {
      set tmo "-timeout {$timeout}"
    } else {
      set tmo {}
    }
    if {$but eq {butHELP}} {
      set neighbor [lindex $widlist end 1]
      set widlist [lreplace $widlist end end]
      lappend widlist [list $but $neighbor T 1 1 {-st w} \
        "-t \"$txt\" -com \"$com\"$tt $tmo -tip F1"]
      set h h_Help
      lappend widlist [list $h $but L 1 94 {-st we}]
      set neighbor $h
    } else {
      lappend widlist [list $but $neighbor $pos 1 1 {-st we} \
        "-t \"$txt\" -com \"$com\"$tt $tmo"]
      set neighbor $but
    }
    set pos L
  }
  lassign [my LowercaseWidgetName $Dlgpath.fra.$Defb1] Defb1
  lassign [my LowercaseWidgetName $Dlgpath.fra.$Defb2] Defb2
  return $bhlist
}

## ________________________ Query the terrible _________________________ ##

method Query {icon ttl msg buttons defb inopts argdia {precom ""} args} {
  # Makes a query (or a message) and gets the user's response.
  #   icon    - icon name (info, warn, ques, err)
  #   ttl     - title
  #   msg     - message
  #   buttons - list of triples "button name, text, ID"
  #   defb    - default button (OK, YES, NO, CANCEL, RETRY, ABORT)
  #   inopts  - options for input dialog
  #   argdia - list of dialog's options
  #   precom - command(s) performed before showing the dialog
  #   args - additional options (message's font etc.)
  # The *argdia* may contain additional options of the query, like these:
  #   -checkbox text (-ch text) - makes the checkbox's text visible
  #   -geometry +x+y (-g +x+y) - sets the geometry of dialog
  #   -color cval    (-c cval) - sets the color of message
  # If "-geometry" option is set (even equaling "") the Query procedure
  # returns a list with chosen button's ID and a new geometry.
  # Otherwise it returns only the chosen button's ID.
  # See also:
  # [aplsimple.github.io](https://aplsimple.github.io/en/tcl/pave/index.html)

  set wdia $Winpath.dia
  append wdia [lindex [split [self] :] end] ;# be unique per apave object
  set qdlg [set Dlgpath $wdia[incr Indexdlg]]
  # remember the focus (to restore it after closing the dialog)
  set focusback [focus]
  set focusmatch {}
  # options of dialog
  lassign {} chmsg geometry optsLabel optsMisc optsFont optsFontM optsHead \
    root rotext head hsz binds postcom onclose ONCLOSE timeout tab2 \
    tags cc themecolors optsGrid addpopup minsize savetext
  set wasgeo [set textmode [set stay [set waitvar 0]]]
  set readonly [set hidefind [set scroll [set modal 1]]]
  set wrap word
  set curpos {1.0}
  set CheckNomore 0
  foreach {opt val} {*}$argdia {
    if {$opt in {-c -color -fg -bg -fgS -bgS -cc -hfg -hbg}} {
      # take colors by their variables
      if {[info exist $val]} {set val [set $val]}
    }
    switch -- $opt {
      -H - -head {
        set head [string map {$ \$ \" \'\' \{ ( \} )} $val]
      }
      -help {
        set buttons "butHELP Help {$val} $buttons"
      }
      -ch - -checkbox {set chmsg "$val"}
      -g - -geometry {
        set geometry $val
        if {[set wasgeo [expr {[string first "pointer" $val]<0}]]} {
          lassign [::apave::splitGeometry $geometry] - - gx gy
        }
      }
      -c - -color {append optsLabel " -foreground {$val}"}
      -a { ;# additional grid options of message labels
        append optsGrid " $val" }
      -onclose {
        set ONCLOSE [string map [list %w $qdlg] $val]
        lappend args $opt $ONCLOSE
      }
      -centerme - -ontop - -themed - -resizable - -checkgeometry - -comOK - -transient {
        lappend args $opt $val ;# options delegated to showModal method
      }
      -parent - -root { ;# obsolete, used for compatibility
        lappend args -centerme $val
      }
      -t - -text {set textmode $val}
      -tags {
        upvar 2 $val _tags
        set tags $_tags
      }
      -ro - -readonly {set readonly [set hidefind $val]}
      -rotext {set hidefind 0; set rotext $val}
      -w - -width {set charwidth $val}
      -h - -height {set charheight $val}
      -fg {append optsMisc " -foreground {$val}"}
      -bg {append optsMisc " -background {$val}"}
      -fgS {append optsMisc " -selectforeground {$val}"}
      -bgS {append optsMisc " -selectbackground {$val}"}
      -cc {append optsMisc " -insertbackground {$val}"}
      -my - -myown {append optsMisc " -myown {$val}"}
      -pos {set curpos "$val"}
      -hfg {append optsHead " -foreground {$val}"}
      -hbg {append optsHead " -background {$val}"}
      -hsz {append hsz " -size $val"}
      -minsize {set minsize "-minsize {$val}"}
      -focus {set focusmatch "$val"}
      -theme {append themecolors " {$val}"}
      -post {set postcom $val}
      -popup {set addpopup [string map [list %w $qdlg.fra.texM] "$val"]}
      -timeout - -focusback - -scroll - -tab2 - -stay - -modal - -waitvar - -wrap {
        set [string range $opt 1 end] $val
      }
      -savetext {set savetext $val}
      default {
        append optsFont " $opt $val"
        if {$opt ne "-family"} {
          append optsFontM " $opt $val"
        }
      }
    }
  }
  if {[set wprev [::apave::InfoFind $wdia $modal]] ne {}} {
    catch {
      wm withdraw $wprev
      wm deiconify $wprev
      puts "$wprev already exists: selected now"
    }
    return 0
  }
  set optsFont [string trim $optsFont]
  set optsHeadFont $optsFont
  set fs [my basicFontSize]
  set textfont "-family {[my basicTextFont]}"
  if {$optsFont ne {}} {
    if {[string first "-size " $optsFont]<0} {
      append optsFont " -size $fs"
    }
    if {[string first "-size " $optsFontM]<0} {
      append optsFontM " -size $fs"
    }
    if {[string first "-family " $optsFont]>=0} {
      set optsFont "-font \{$optsFont"
    } else {
      set optsFont "-font \{$optsFont -family {[my basicDefFont]}"
    }
    append optsFont "\}"
  } else {
    set optsFont "-font {[font actual apaveFontDef] -size $fs}"
    set optsFontM "-size $fs"
  }
  set msgonly [expr {$readonly || $hidefind || $chmsg ne {}}]
  if {!$textmode || $msgonly} {
    set textfont "-family {[my basicDefFont]}"
    if {!$textmode} {
      set msg [string map [list \\ \\\\ \{ \\\\\{ \} \\\\\}] $msg]
    }
  }
  set optsFontM [string trim $optsFontM]
  set optsFontM "-font \{$optsFontM $textfont\}"
  # layout: add the icon
  if {$icon ni {{} -}} {
    set widlist [list [list labBimg - - 99 1 \
      {-st n -pady 7} "-image [::apave::iconImage $icon]"]]
    set prevl labBimg
  } else {
    set widlist [list [list labimg - - 99 1]]
    set prevl labimg ;# this trick would hide the prevw at all
  }
  set prevw labBimg
  if {$head ne {}} {
    # set the dialog's heading (-head option)
    if {$optsHeadFont ne {} || $hsz ne {}} {
      if {$hsz eq {}} {set hsz "-size [::apave::obj basicFontSize]"}
      set optsHeadFont [string trim "$optsHeadFont $hsz"]
      set optsHeadFont "-font \"$optsHeadFont\""
    }
    set optsFont {}
    set prevp L
    set head [string map {\\n \n} $head]
    foreach lh [split $head "\n"] {
      set labh "labheading[incr il]"
      lappend widlist [list $labh $prevw $prevp 1 99 {-st we} \
        "-t \"$lh\" $optsHeadFont $optsHead"]
      set prevw [set prevh $labh]
      set prevp T
    }
  } else {
    # add the upper (before the message) blank frame
    lappend widlist [list h_1 $prevw L 1 1 {-pady 3}]
    set prevw [set prevh h_1]
    set prevp T
  }
  # add the message lines
  set il [set maxw 0]
  if {$readonly && $rotext eq {}} {
    # only for messaging (not for editing/viewing texts):
    set msg [string map {\\\\n \\n \\n \n} $msg]
  }
  foreach m [split $msg \n] {
    set m [string map {$ \$ \" \'\'} $m]
    if {[set mw [string length $m]] > $maxw} {
      set maxw $mw
    }
    incr il
    if {!$textmode} {
      lassign [my GetLinkLab $m] m link
      lappend widlist [list Lab$il $prevw $prevp 1 7 \
        "-st w -rw 1 $optsGrid" "-t \"$m \" $optsLabel $optsFont $link"]
    }
    set prevw Lab$il
    set prevp T
  }
  if {$inopts ne {}} {
    # here are widgets for input (in fraM frame)
    set io0 [lindex $inopts 0]
    lset io0 1 $prevh
    lset inopts 0 $io0
    foreach io $inopts {
      lappend widlist $io
    }
    set prevw fraM
  } elseif {$textmode} {
    # here is text widget (in fraM frame)
  ; proc vallimits {val lowlimit isset limits} {
      set val [expr {max($val,$lowlimit)}]
      if {$isset} {
        upvar $limits lim
        lassign $lim l1 l2
        set val [expr {min($val,$l1)}] ;# forced low
        if {$l2 ne {}} {set val [expr {max($val,$l2)}]} ;# forced high
      }
      return $val
    }
    set il [vallimits $il 1 [info exists charheight] charheight]
    incr maxw
    set maxw [vallimits $maxw 20 [info exists charwidth] charwidth]
    rename vallimits {}
    lappend widlist [list fraM $prevh T 10 12 {-st nswe -pady 3 -rw 1}]
    lappend widlist [list TexM - - 1 12 {pack -side left -expand 1 -fill both -in \
      $qdlg.fra.fraM} [list -h $il -w $maxw {*}$optsFontM {*}$optsMisc \
      -wrap $wrap -textpop 0 -tabnext "$qdlg.fra.[lindex $buttons 0] *but0"]]
    if {$scroll} {
      lappend widlist {sbv texM L 1 1 {pack -in $qdlg.fra.fraM}}
    }
    set prevw fraM
  }
  # add the lower (after the message) blank frame
  lappend widlist [list h_2 $prevw T 1 1 {-pady 0 -ipady 0 -csz 0}]
  # underline the message
  lappend widlist [list seh $prevl T 1 99 {-st ew}]
  # add left frames and checkbox (before buttons)
  lappend widlist [list h_3 seh T 1 1 {-pady 0 -ipady 0 -csz 0}]
  if {$textmode} {
    # binds to the special popup menu of the text widget
    set wt "\[[self] TexM\]"
    set binds "set pop $wt.popupMenu
      bind $wt <Button-3> \{[self] themePopup $wt.popupMenu; tk_popup $wt.popupMenu %X %Y \}"
    if {$msgonly} {
      append binds "
        menu \$pop
          \$pop add command [my iconA copy] -accelerator Ctrl+C -label \"Copy\" \\
          -command \"event generate $wt <<Copy>>\""
      if {$hidefind || $chmsg ne {}} {
        append binds "
          \$pop configure -tearoff 0
          \$pop add separator
          \$pop add command [my iconA none] -accelerator Ctrl+A \\
          -label \"Select All\" -command \"$wt tag add sel 1.0 end\"
            bind $wt <Control-a> \"$wt tag add sel 1.0 end; break\""
      }
    }
  }
  set appendHL no
  if {$chmsg eq {}} {
    if {$textmode} {
      set noIMG "[my iconA none]"
      if {$hidefind} {
        lappend widlist [list h__ h_3 L 1 4 {-cw 1}]
      } else {
        lappend widlist [list labfnd h_3 L 1 1 "-st e" "-t {$::apave::msgarray(find)}"]
        lappend widlist [list Entfind labfnd L 1 1 \
          {-st ew -cw 1} "-tvar [namespace current]::Foundstr -w 10"]
        lappend widlist [list labfnd2 Entfind L 1 1 "-cw 2" "-t {}"]
        lappend widlist [list h__ labfnd2 L 1 1]
        append binds "
          bind \[[self] Entfind\] <Return> {[self] findInText}
          bind \[[self] Entfind\] <KP_Enter> {[self] findInText}
          bind \[[self] Entfind\] <FocusIn> {\[[self] Entfind\] selection range 0 end}
          bind $qdlg <F3> {[self] findInText 1}
          bind $qdlg <Control-f> \"[self] InitFindInText 1; focus \[[self] Entfind\]; break\"
          bind $qdlg <Control-F> \"[self] InitFindInText 1; focus \[[self] Entfind\]; break\""
      }
      if {$readonly} {
        if {!$hidefind} {
          append binds "
            \$pop add separator
            \$pop add command [my iconA find] -accelerator Ctrl+F -label \\
            \"Find First\" -command \"[self] InitFindInText; focus \[[self] Entfind\]\"
            \$pop add command $noIMG -accelerator F3 -label \"Find Next\" \\
            -command \"[self] findInText 1\"
            $addpopup
            [[self] popupHighlightCommands \$pop $wt]
            \$pop add separator
            \$pop add command [my iconA exit] -accelerator Esc -label \"Close\" \\
            -command \"\[[self] paveoptionValue Defb1\] invoke\"
          "
          after idle "[self] set_highlight_matches $wt"
        } else {
          set appendHL yes
        }
      } else {
        # make bindings and popup menu for text widget
        after idle "[self] set_highlight_matches $wt"
        append binds "
          [my setTextBinds $wt]
          menu \$pop
            \$pop add command [my iconA cut] -accelerator Ctrl+X -label \"Cut\" \\
            -command \"event generate $wt <<Cut>>\"
            \$pop add command [my iconA copy] -accelerator Ctrl+C -label \"Copy\" \\
            -command \"event generate $wt <<Copy>>\"
            \$pop add command [my iconA paste] -accelerator Ctrl+V -label \"Paste\" \\
            -command \"event generate $wt <<Paste>>\"
            [[self] popupBlockCommands \$pop $wt]
            [[self] popupHighlightCommands \$pop $wt]
            [[self] popupFindCommands \$pop $wt]
            $addpopup
            \$pop add separator
            \$pop add command [my iconA SaveFile] -accelerator Ctrl+W \\
            -label \"Save and Close\" -command \"[self] res $qdlg 1\"
          "
      }
      set onclose "[namespace current]::exitEditor $qdlg"
      oo::objdefine [self] export InitFindInText
    } else {
      lappend widlist [list h__ h_3 L 1 4 {-cw 1}]
    }
  } else {
    lappend widlist [list chb h_3 L 1 1 \
      {-st w} "-t {$chmsg} -var [namespace current]::CheckNomore"]
    lappend widlist [list h_ chb L 1 1]
    lappend widlist [list sev h_ L 1 1 {-st nse -cw 1}]
    lappend widlist [list h__ sev L 1 1]
    set appendHL $textmode
  }
  if {$appendHL} {
    after idle "[self] set_highlight_matches $wt"
    append binds "
    [[self] popupHighlightCommands \$pop $wt]"
  }
  # add the buttons
  lassign [my AppendButtons widlist $buttons h__ L $defb $timeout $qdlg $modal $ONCLOSE] \
    bhelp bcomm
  # make the dialog's window
  set wtop [my makeWindow $qdlg.fra $ttl]
  if {$bhelp ne {}} {
    bind $qdlg <F1> $bcomm
  }
  # pave the dialog's window
  if {$tab2 eq {}} {
    set widlist [my paveWindow $qdlg.fra $widlist]
  } else {
    # pave with the notebook tabs (titl1 title2 [title3...] widlist2 [widlist3...])
    lassign $tab2 ttl1 ttl2 widlist2 ttl3 widlist3 ttl4 widlist4 ttl5 widlist5
    foreach nt {3 4 5} {
      set ttl ttl$nt
      set wdl widlist$nt
      if {[set _ [set $ttl]] ne {}} {
        set $ttl [list f$nt "-t {$_}"]
        set $wdl [list $qdlg.fra.nbk.f$nt "[set $wdl]"]
      }
    }
    set widlist0 [list [list nbk - - - - {pack -side top -expand 1 -fill both} [list \
      f1 "-t {$ttl1}" \
      f2 "-t {$ttl2}" \
      {*}$ttl3 \
      {*}$ttl4 \
      {*}$ttl5 \
    ]]]

    set widlist1 [list]
    foreach it $widlist {
      lassign $it w nei pos r c opt atr
      set opt [string map {$qdlg.fra $qdlg.fra.nbk.f1} $opt]
      lappend widlist1 [list $w $nei $pos $r $c $opt $atr]
    }
    set widlist [my paveWindow $qdlg.fra $widlist0 \
      $qdlg.fra.nbk.f1 $widlist1 \
      $qdlg.fra.nbk.f2 $widlist2 \
      {*}$widlist3 \
      {*}$widlist4 \
      {*}$widlist5 \
    ]
    set tab2 nbk.f1.
  }
  if {$precom ne {}} {
    {*}$precom  ;# actions before showModal
  }
  if {$themecolors ne {}} {
    # themed colors are set as sequentional '-theme' args
    if {[llength $themecolors]==2} {
      # when only 2 main fb/bg colors are set (esp. for TKE)
      lassign [::apave::parseOptions $optsMisc -foreground black \
        -background white -selectforeground black \
        -selectbackground gray -insertbackground black] v0 v1 v2 v3 v4
      # the rest colors should be added, namely:
      #   tfg2 tbg2 tfgS tbgS tfgD tbgD tcur bclr help fI bI fM bM fW bW bHL2
      lappend themecolors $v0 $v1 $v2 $v3 $v3 $v1 $v4 $v4 $v3 $v2 $v3 $v0 $v1 black #ffff9e $v1
    }
    catch {
      my themeWindow $qdlg $themecolors no
    }
  }
  # after creating widgets - show dialog texts if any
  my SetGetTexts set $qdlg.fra $inopts $widlist
  lassign [my LowercaseWidgetName $qdlg.fra.$tab2$defb] focusnow
  if {$textmode} {
    set wtxt [my TexM]
    my displayTaggedText $wtxt msg $tags
    if {$defb eq "ButTEXT"} {
      if {$readonly} {
        lassign [my LowercaseWidgetName $Defb1] focusnow
      } else {
        set focusnow $wtxt
        catch "::tk::TextSetCursor $focusnow $curpos"
        foreach k {w W} \
          {catch "bind $focusnow <Control-$k> {[self] res $qdlg 1; break}"}
      }
    }
    if {$readonly} {
      my readonlyWidget $wtxt true false
    }
    if {$savetext ne {}} {
      my askForSave $wtxt $savetext
    }
  }
  if {$focusmatch ne {}} {
    foreach w $widlist {
      lassign $w widname
      lassign [my LowercaseWidgetName $widname] wn rn
      if {[string match $focusmatch $rn]} {
        lassign [my LowercaseWidgetName $qdlg.fra.$wn] focusnow
        break
      }
    }
  }
  catch "$binds"
  set args [::apave::removeOptions $args -focus]
  set ::apave::querydlg $qdlg
  my showModal $qdlg -modal $modal -waitvar $waitvar -onclose $onclose \
    -focus $focusnow -geometry $geometry {*}$minsize {*}$args
  if {![winfo exists $qdlg] || (!$modal && !$waitvar)} {
    return 0
  }
  set pdgeometry [wm geometry $qdlg]
  # the dialog's result is defined by "pave res" + checkbox's value
  set res [set result [my res $qdlg]]
  set chv $CheckNomore
  if { [string is integer $res] } {
    if {$res && $chv} { incr result 10 }
  } else {
    set res [expr {$result ne {} ? 1 : 0}]
    if {$res && $chv} { append result 10 }
  }
  if {$textmode && !$readonly} {
    set focusnow [my TexM]
    set textcont [$focusnow get 1.0 end]
    if {$res && $postcom ne {}} {
      {*}$postcom textcont [my TexM] ;# actions after showModal
    }
    set textcont " [$focusnow index insert] $textcont"
  } else {
    set textcont {}
  }
  if {$res && $inopts ne {}} {
    my SetGetTexts get $qdlg.fra $inopts $widlist
    set inopts " [my GetVarsValues $widlist]"
  } else {
    set inopts {}
  }
  if {$textmode && $rotext ne {}} {
    set $rotext [string trimright [[my TexM] get 1.0 end]]
  }
  if {!$stay} {
    destroy $qdlg
    update
    # pause a bit and restore the old focus
    if {$focusback ne {} && [winfo exists $focusback]} {
      set w ".[lindex [split $focusback .] 1]"
      after 50 [list if "\[winfo exist $focusback\]" "focus -force $focusback" elseif "\[winfo exist $w\]" "focus $w"]
    } else {
      after 50 list focus .
    }
  }
  if {$wasgeo} {
    lassign [::apave::splitGeometry $pdgeometry] w h x y
    catch {
      # geometry option can contain pointer/root etc.
      if {abs($x-$gx)<30} {set x $gx}
      if {abs($y-$gy)<30} {set y $gy}
    }
    return [list $result ${w}x$h$x$y $textcont [string trim $inopts]]
  }
  return "$result$textcont$inopts"
}

# ________________________ EOC APaveDialog _________________________ #

}

# _____________________________ EOF _____________________________________ #

apavedialog.tcl