'''See also [SVG widgets Part 1] , [SVG widgets Part 2] & [SVG widgets Part 3]'''
<<inlinehtml>>
<h1 style="text-align:center"><span style="font-size:14pt"><span style="font-family:"Times New Roman""><span style="font-size:24.0pt">Tcl/tk: SVG widgets. File Explorer and information Widgets. Part 4</span></span></span><img alt="" src="" /></h1>
<p> </p>
<p><br />
<button class="b1" style="border-radius: 5px; background-color: cyan; font-size: 18px; margin: 0 0 0 100px;"><a href="https://cloudtk-app.tcl-lang.org/cloudtk/VNC?session=new&Tk=SVG-widgets-Part-I" target="_blank">SVG-demo and TkConsole </a> </button>
<p> </p>
<div class="row">
<div class="col-xs-12">
<p><strong>By clicking on the button, an interactive demo is displayed in a new browser tab using <a class="mkup_a mkup_known" href="https://wiki.tcl-lang.org/page/CloudTk">CloudTk</a></strong>.</p>
<p><strong>This article is written by Vladimir Orlov.</strong></p>
<p><span style="font-size:12pt"><span style="font-family:"Times New Roman"">The "<strong><em>SVG widgets for Tcl/Tk</em></strong>" project addresses one of the primary criticisms leveled at the graphical interfaces of applications built using standard <em><strong>Tk</strong></em> widgets: their outdated design. Transitioning from classic <em><strong>Tk</strong></em> widgets to <em><strong>SVG</strong></em> widgets requires minimal effort; I confirmed this firsthand by rewriting the <em><strong>GUI</strong></em> for the <em><strong>cryptoarmpkcs</strong></em> digital signature utility. Distributions of this utility (named <em><strong>cryptoarmpkcs_svg</strong></em>) for <em><strong>Linux64</strong></em> and <em><strong>Win64</strong></em> platforms are <a href="https://github.com/a513/CryptoArmPKCS">available in the project repository</a>:</span></span></p>
<p><img alt="" src="https://habrastorage.org/webt/68/9c/38/689c38790ad881a645f9486cd7c6b05d.gif" /></p>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman"">This screenshot showcases the key features of the <strong><em>SVG</em></strong> widgets project, including the variety of widgets, the design of buttons and frames, and widget fill styles. You can run this example in the demo (using the "<em><strong>SVG-demo and TkConsole</strong></em>" button at the beginning of the article) by clicking the "<em><strong>Examples</strong></em>" button and selecting "<em><strong>SVGpkcs7</strong></em>" from the menu. It also features a scrolling text display reading «<em><strong>PKCS7 Utility (Public-Key Cryptography Standarts#7</strong></em>)». There is animation as well - rotating tokens; if they aren't spinning, simply click on the cyan-colored border. </span></span></p>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman"">However, not everything was perfect. When developing a GUI, one often needs to use a file browser to select files or folders (via <strong><em>tk_getSaveFile</em></strong>, <strong><em>tk_getOpenFile</em></strong>, or <strong><em>tk_chooseDirectory</em></strong>). While <strong><em>Windows</em></strong> and <strong><em>OS X</em></strong> launch their respective native file browsers, <strong><em>Linux</em></strong> platforms load the <strong><em>Tcl/Tk</em></strong> browser. What is the issue with this browser? It lacks basic file and folder operations, such as creating, deleting, or renaming items.</span></span></p>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman"">Consequently, a file browser based on SVG widgets was developed, resulting in the `tkfe_svg` package, which was subsequently added to the `svgwidgets` project:</span></span></p>
<p style="margin-left:0cm; margin-right:0cm"><img alt="" src="https://habrastorage.org/webt/d6/68/42/d668429f4a79f7044a9e6e7029d05bbe.png" style="height:419px; width:850px" /></p>
<div class="row">
<div class="col-xs-12"> </div>
</div>
<div>
<div style="background-color:#f7f7f7; border-radius:5px; border:1px solid #0077cc; padding:5px"># Loading the tkfe_svg package<br />
package require tkfe_svg<br />
# Replacing the native file explorer with tkfe_svg<br />
FE::fe_rename</div>
</div>
<div> </div>
<div>Now, when invoking a file dialog (<strong><em>tk_getSaveFile</em></strong>, <em><strong>tk_getOpenFile</strong></em>, or <strong><em>tk_chooseDirectory</em></strong>), the dialog<strong><em> GUI</em></strong> from the <em><strong>tkfe_svg</strong></em> package will be loaded.</div>
<div>To undo the action of the <em><strong>FE::fe_rename</strong></em> operator, simply execute the <em><strong>FE::fe_restore</strong></em> command.<br />
The <em><strong>tkfe_svg</strong></em> package contains three operators: <em><strong>::FE::tk_getopenfile</strong></em>, <em><strong>::FE::tk_getsavefile</strong></em>, and <em><strong>::FE::tk_choosedirectory.</strong></em> If the <em><strong>::FE::fe_rename</strong></em> operator is not used, these commands are called directly.</div>
<p>In addition to options similar to those of the native <em><strong>Tcl/T</strong></em>k file dialog, the tkfe_svg file dialog offers extra options. These allow you to specify, for example, the dialog's width (<em><strong>-width</strong></em>) and height (<em><strong>-height</strong></em>), or to arrange folders and files in separate windows (using the "<em><strong>-sepfolders 1</strong></em>" option) for the <em><strong>::FE::tk_getopenfile</strong></em> and <em><strong>::FE::tk_getsavefile</strong></em> operators.</p>
<div class="row"> </div>
<div style="background-color:#f7f7f7; border-radius:5px; border:1px solid #0077cc; padding:5px"># Loading the tkfe_svg package<br />
package require tkfe_svg<br />
# Replacing the native file explorer with tkfe_svg<br />
FE::fe_rename /> #Launch the file explorer to select a file.<br />
tk_getOpenFile -width 10c -height 7c -sepfolders 1<br />
#or<br />
#Restoring the native file explorer<br />
#::FE::fe_restore<br />
::FE::tk_getopenfile -width 10c -height 7c -sepfolders 1</div>
<p><img alt="" src="https://habrastorage.org/webt/ee/f9/58/eef958fe1db15854bcfab831e96eb74a.png" style="height:443px; width:850px" /></p>
<p>You can also configure the file explorer using the "<em><strong>Go configure</strong></em>" button; clicking it opens an intuitive configuration menu:</p>
<p><img alt="" src="https://habrastorage.org/webt/7d/b6/43/7db6431b0a4d1c10b301fda4f4f3f412.png" style="height:407px; width:850px" /></p>
<p>File manager settings are saved upon exit. To restore the default settings, you can execute the<em><strong> ::FE::fe_restore</strong></em> command.</p>
<p>While discussing <em><strong>SVG</strong></em> widgets, we somehow overlooked information widgets—even though they appeared on your screen if you viewed the demo examples:</p>
<p><img alt="" src="https://habrastorage.org/webt/82/22/54/8222542d96ab57b26a546a8296e3ffd9.png" style="width:850px" /></p>
<p>Information widgets are SVG widgets of the `mbutton` class, created <a href="https://wiki.tcl-lang.org/page/SVG+widgets+Part+2">using one of the following commands</a>:</p>
<p><em><strong>mbutton new <window-ID> [-type <type>] [args]</strong></em></p>
<p>or</p>
<p><em><strong>mbutton create <object-ID> <window-ID> [-type <type>] [args],</strong></em></p>
<p>where <strong><em><type></em></strong> takes one of the following values:<em><strong> yesno</strong></em> | <em><strong>msg</strong></em> | <strong><em>left</em></strong> | <em><strong>right</strong></em> | <em><strong>up</strong></em> | <em><strong>down</strong></em> | <em><strong>none</strong></em>.</p>
<p>Thus, there are seven types of information widgets: <em><strong>yesno</strong></em>, <em><strong>msg</strong></em>, <em><strong>left</strong></em>, <em><strong>right</strong></em>, <em><strong>up</strong></em>, <em><strong>down</strong></em>, and <em><strong>none</strong></em>. By default, a widget of type <em><strong>yesno</strong></em> is created.</p>
<p>The following example demonstrates how yesno and msg type SVG widgets are created and how they work:</p>
<div class="row"> </div>
<div>
<div style="background-color:#f7f7f7; border-radius:5px; border:1px solid #0077cc; padding:5px">
<p>package require svgwidgets<br />
set textanchor [list nw n ne]<br />
set mtype [list yesno msg yesno]<br />
set txt "\nAre you sure\n"<br />
append txt "sure your choice is correct\n"<br />
append txt "?\n"<br />
lassign {1 0 0} i wm hm<br />
set lmsg [list ]<br />
lassign {8 1.0 100 3 2} fsize fopaci x0 grad wstr<br />
foreach type $mtype {<br />
set tektxt "[set txt](window: .mb$i)"<br />
set msg [mbutton new .mb$i -place window -type $type -fontsize [expr {$fsize * $i}] -text $tektxt -strokewidth [expr {$wstr * $i}]]<br />
set i1 $i<br />
if {$i1 != 1} {<br />
set i [expr {$i - 0.9}]<br />
}<br />
$msg config -fillopacity [expr {$fopaci / $i}] -fillnormal gradient[set grad]<br />
lappend lmsg $msg<br />
set i $i1<br />
incr i<br />
incr grad<br />
}<br />
set i 1<br />
set mend [list]<br />
foreach m $lmsg {<br />
after 0 lappend mend \".mb[set i] \[$m place -x $x0 -y 100] \"<br />
#Strange comment "<br />
update idletasks<br />
after 100<br />
lassign "[winfo width .mb[set i]] [winfo rootx .mb[set i]]" mw mr<br />
set x0 [expr {$x0 + $mw + $mr + 40}]<br />
incr i<br />
}<br />
foreach w ".mb1 .mb2 .mb3" {<br />
if {[winfo exist $w]} {<br />
tkwait window $w<br />
}<br />
}<br />
puts "Result: [lsort $mend] "</p>
</div>
</div>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman"">If you run this example in the demonstration window, you will get the following image as output:</span></span></p>
<p style="margin-left:0cm; margin-right:0cm"><img alt="" src="https://habrastorage.org/webt/3a/41/34/3a4134a1c7655281541c24659890cffe.png" style="height:365px; width:850px" /></p>
<p style="margin-left:0cm; margin-right:0cm">After the "<em><strong>Yes</strong></em>" or "<em><strong>No</strong></em>" button is clicked on each widget, information indicating which button was clicked in which window will be printed to the console:</p>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman""><strong><em>Result: {.mb1 yes } {.mb2 yes } {.mb3 no }</em></strong></span></span></p>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman"">The appearance of information widgets—like that of all other <strong><em>SVG</em></strong> widgets—can be customized by specifying various options. For instance, widget stroke properties are defined using the options <strong><em>`-stroke</em></strong>` (stroke color), <strong><em>`-strokewidth</em></strong>` (stroke thickness), and `<strong><em>-strokeopacity</em></strong>` (stroke opacity, ranging from 0.0 to 1.0). Corner rounding is controlled by the <strong><em>`-rx</em></strong>` option. Font characteristics are set via the options <strong><em>`-fontsize</em></strong>` (font size), `<strong><em>-textstroke</em></strong>` (text outline color), and `<strong><em>-textfill</em></strong>` (font color).</span></span></p>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman"">Information widgets of the types *<strong><em>left</em></strong>*, *<strong><em>right</em></strong>*, *<strong><em>up</em></strong>*, *<em>down</em>*, and *<strong><em>none</em></strong>* can have a "<strong><em>tongue</em></strong>" (the `<strong><em>-tongue</em></strong>` option)—a feature we already encountered when examining the <a href="https://wiki.tcl-lang.org/page/SVG+widgets+Part+2">*<strong><em>cmenu</em></strong>* class widget</a>:</span></span></p>
<p style="margin-left:0cm; margin-right:0cm"><img alt="" src="https://habrastorage.org/webt/c2/fa/3b/c2fa3ba3457c713156b8caeac13bf539.png" style="height:383px; width:850px" /></p>
<p style="margin-left:0cm; margin-right:0cm">Here is the code for this demonstration:</p>
<div>
<div style="background-color:#f7f7f7; border-radius:5px; border:1px solid #0077cc; padding:5px">
<p>package require svgwidgets<br />
set textanchor [list nw n ne]<br />
set mtype [list down up left right none]<br />
set txt "Information for you.\n"<br />
append txt "Click me and\nthe widget will close.\n"<br />
lassign {1 0 0 } i wm hm<br />
set lmsg [list ]<br />
lassign {12 1.0 100 3 2} fsize fopaci x0 grad wstr<br />
set fsize [list 0 10 14 18 22 24]<br />
foreach type $mtype {<br />
set txt1 "[set txt](Type: $type)"<br />
set tfont [lindex $fsize $i]<br />
set msg [mbutton new .mb[set i] -place window -type [set type] -fontsize $tfont -text $txt1 -strokewidth [expr {$wstr * $i}]]<br />
set i1 $i<br />
if {$i1 != 1} {<br />
set i [expr {$i - 0.9}]<br />
}<br />
set opacity [expr {$fopaci / $i}]<br />
$msg config -fillopacity $opacity -fillnormal gradient0 -stroke chocolate<br />
lappend lmsg $msg<br />
set i $i1<br />
incr i<br />
incr grad<br />
}<br />
set i 1<br />
set x1 $x0<br />
foreach m $lmsg {<br />
if {$i < 4 } {<br />
set y0 100<br />
} elseif {$i == 4} {<br />
set y0 250<br />
set x0 [expr {$x1 + 30}] <br />
}<br />
after 0 $m place -x $x0 -y $y0<br />
update idletasks<br />
after 100<br />
if {$i > 4} {<br />
break<br />
}<br />
lassign "[[lindex $lmsg $i] config -width] [winfo rootx .mb[set i]]" mw mr<br />
set x0 [expr {$x0 + $mw + $mr + 10}]<br />
incr i<br />
if {$i == 5} { <br />
set x0 [expr {$x0 + 10}] <br />
[lindex $lmsg 4] config -strokeopacity 0.75<br />
}<br />
}<br />
foreach w ".mb1 .mb2 .mb3 .mb4 .mb5" {<br />
if {[winfo exist $w]} {<br />
tkwait window $w<br />
}<br />
}<br />
puts "Ended"</p>
</div>
</div>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman"">Information widgets can be created either in a separate window (<strong><em>toplevel</em></strong>) or on an <strong><em>SVG</em></strong> canvas (<strong><em>tkp::canvas</em></strong>). This placement is specified when the widget is created via the <strong><em>`-place</em></strong>` parameter, which can take the value `<strong><em>window</em></strong>` or `<strong><em>canvas</em></strong>` (the default).</span></span></p>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman"">It is advisable to use the `<strong><em>place</em></strong>` method to position information widgets:</span></span></p>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman""><strong><em><ID-mbutton> place -</em></strong><strong><em>x <X-coordinate> -y <Y-coordinate> [-in <window>]</em></strong></span></span></p>
<p style="margin-left:0cm; margin-right:0cm"> </p>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman"">To close an *<strong><em>mbutton</em></strong>* widget of the '<strong><em>yesno</em></strong>' or '<strong><em>msg</em></strong>' type, you must click either the "<strong><em>Yes</em></strong>" or "<strong><em>No</em></strong>" button. The returned value will be either "<strong><em>yes</em></strong>" or "<strong><em>no</em></strong>".</span></span></p>
<p style="margin-left:0cm; margin-right:0cm">Complete the following example:</p>
<div class="row">
<div>
<div style="background-color:#f7f7f7; border-radius:5px; border:1px solid #0077cc; padding:5px">
<p>package require svgwidgets<br />
set textanchor [list none nw n ne]<br />
set mtype [list yesno msg yesno]<br />
set txt "\nAre you sure\n"<br />
append txt "sure your choice is correct\n"<br />
append txt "?\n"<br />
lassign {1 0 0 } i wm hm<br />
set lmsg [list ]<br />
lassign {12 1.0 10 3 2} fsize fopaci x0 grad wstr<br />
set mret [list]<br />
toplevel .mb -bg yellow<br />
wm geometry .mb 700x400+200+50<br />
foreach type $mtype {<br />
set ta [lindex $textanchor $i]<br />
set msg [mbutton new .mb.mb[set i] -place canvas -type [set type] -fontsize [expr {$fsize * $i}] -text $txt -strokewidth [expr {$wstr * $i}] -textanchor [set ta]]<br />
$msg config -fillopacity [expr {$fopaci / $i}] -fillnormal gradient[set grad]<br />
lappend lmsg $msg<br />
set mw [winfo width .mb.mb[set i]]<br />
set mr [winfo rootx .mb.mb[set i]]<br />
set x0 [expr {$x0 + $mw + 40}]<br />
incr i<br />
incr grad<br />
update idletasks<br />
after 300<br />
set xx[set i] [$msg place -x $x0 -y 50 ]<br />
lappend mret [set xx[set i]]<br />
}<br />
puts "\nReturn: $mret\n"<br />
destroy .mb</p>
</div>
</div>
<div class="row"><br />
and you will see how it works:</div>
<div class="row"> </div>
<div class="row"><img alt="" src="https://habrastorage.org/webt/25/cb/9e/25cb9e1acf54363d2a0d5c927b293384.png" style="height:399px; width:850px" /></div>
</div>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman"">To align text within the widget, the <strong><em>`-textanchor</em></strong>` option is used; it can take one of the values <span style="font-family:"Arial Unicode MS""></span>`<strong><em>nw</em></strong>`, `<strong><em>n</em></strong>`, or `<strong><em>ne</em></strong>` (see the `<strong><em>textanchor</em></strong>` variable in the example).</span></span></p>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman"">To close other types of widgets, simply click on them. </span></span></p>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman"">The code below demonstrates this:</span></span></p>
<div>
<div style="background-color:#f7f7f7; border-radius:5px; border:1px solid #0077cc; padding:5px">
<p>package require svgwidgets<br />
set textanchor [list nw n ne]<br />
set mtype [list down up left right none]<br />
set txt "Information for you.\n"<br />
append txt "Click me and\nthe widget will close.\n"<br />
lassign {1 0 0 } i wm hm<br />
set lmsg [list ]<br />
lassign {12 1.0 10 3 2} fsize fopaci x0 grad wstr<br />
set mret [list]<br />
toplevel .mb -bg yellow<br />
wm geometry .mb 700x400+200+50<br />
cbutton create fr .mb.fr -type frame -bg gray80 -fillnormal gradient2<br />
pack .mb.fr -fill both -expand 1<br />
update<br />
after 300<br />
set fsize [list 10 14 18 22 24 28]<br />
foreach type $mtype {<br />
set txt1 "[set txt](Type: $type)"<br />
# set msg [mbutton new .mb.mb[set i] -place canvas -type [set type] -fontsize [expr {$fsize * $i / 2.0}] -text [set txt1] -strokewidth [expr {$wstr * $i}]]<br />
set msg [mbutton new .mb.mb[set i] -place canvas -type [set type] -fontsize [lindex $fsize $i] -text [set txt1] -strokewidth [expr {$wstr * $i}]]<br />
# $msg config -fillopacity [expr {$fopaci / $i}] -fillnormal gradient[set grad]<br />
# $msg config -fillopacity [expr {$fopaci / $i}] -fillnormal cyan<br />
$msg config -fillopacity [expr {1.5 * $fopaci / $i}] -fillnormal gradient0<br />
lappend lmsg $msg<br />
set mw [winfo width .mb.mb[set i]]<br />
set mr [winfo rootx .mb.mb[set i]]<br />
set x0 [expr {$x0 + $mw + 40}]<br />
incr i<br />
incr grad<br />
update idletasks<br />
# after 300<br />
set xx[set i] [$msg place -x $x0 -y 50 -in .mb.fr ]<br />
lappend mret [set xx[set i]]<br />
}<br />
puts "\nReturn: $mret\n"<br />
fr destroy<br />
destroy .mb</p>
<p> </p>
</div>
</div>
<p style="margin-left:0cm; margin-right:0cm"><img alt="" src="https://habrastorage.org/webt/23/e9/34/23e9340ae4b5d58b508619a8a8a9daee.png" style="height:438px; width:850px" /></p>
<p style="margin-left:0cm; margin-right:0cm"><span style="font-size:12pt"><span style="font-family:"Times New Roman"">In conclusion, a new version of the <a href="https://github.com/tcltk-depot/tkpath"><strong><em>tkpath</em></strong> package</a> — a core package for <strong><em>SVG</em></strong> widgets—has been released. Version 0.4.3 of <strong><em>tkpath</em></strong> (`<strong><em>package require tkpath 0.4.3</em></strong>`) includes the `<strong><em>tkp::loupe</em></strong>` function, making it possible to avoid using the <strong><em>treectrl</em></strong> package when using the <strong><em>svgwidgets</em></strong> package:</span></span></p>
<div>
<div style="background-color:#f7f7f7; border-radius:5px; border:1px solid #0077cc; padding:5px">
<p>if {[catch {package require tkpath}]} {<br />
package require tko<br />
}<br />
if {[info command ::tkp::loupe] == ""} {<br />
package require treectrl<br />
}</p>
</div>
</div>
<p> </p>
<p> </p>
</div>
</div>
<<inlinehtml>>
<<categories>> Useful Tk Widgets | Arts and Crafts of Tcl-Tk Programming | GUI