Installing Shen/tk
When you download the Standard Library the README file in that download will tell you how to configure
for Shen/tk. Here it is in brief.
Installing the Standard Library
Move the folder StLib to your Shen home directory. Enter Shen.
To install (cd "StLib") and type (load "install.shen"). If you can, save your image to an
executable file - say shen-tk.exe. Exit.
Configuring for Shen/tk
In order to run Shen/tk you need to install TCL/tk. We recommend Active State TCL which is free for
non-commercial applications.
1. Create two empty text files shen-to-tcl.txt and tcl-to-shen.txt in the home directory.
2. Now go to StLib and look in the file Tk/root.tcl. You will see two lines.
set in {C:/Users/shend/OneDrive/Desktop/Shen/S38.3/shen-to-tcl.txt}
set out {C:/Users/shend/OneDrive/Desktop/Shen/S38.3/tcl-to-shen.txt}
You need to change these paths to the paths appropriate to your installation.
3. In Windows create a batch file with the following contents.
START \B shen-tk.exe
C:\ActiveTcl\bin\wish.exe "C:\Users\shend\OneDrive\Desktop\Shen\S38.1\StLib\Tk\root.tcl" |
The last line is appropriate to my computer; you will have to change it for your installation.
Now click on the batch file and Shen/tk will open with a root window from TCL/tk.
Note that the root window cannot be killed without ending your connection to TCL/tk. This
is not true of other windows. To exit cleanly without repercussions type (tk.exit) to the
REPL.
4. To test under type checking. Enter
(tc +)
(tk.types +)
(tk.widget .b button)
(tk.pack [.b])
(tk.putw .b -text "Hello World")
(tk.putw .b -command (freeze (pr "Hello World")))
(tk.tcl->shen) |
Clicking the button should print 'Hello World'. The file test.shen in the folder Tk contains
more examples.
Exiting Shen/tk
When you call up Shen/tk, a TCL event loop is run in the background. When you exit Shen/tk
this program still continues to run in the background. This means that if you enter Shen/tk again, the
old program will still be running and it will eat your input. So before killing the Tk window and Shen, make
sure you kill the background TCL process by (tk.exit). If you do not you will have to kill the process in
the task manager.
Creating a Button In Shen/tk
The basic command for creating a widget is as follows.
(tk.widget <name> <type> <options>)
Here is an example.
This specifies a button called .b. Nothing appears in the root window because the button
has to be packed.
The button appears but with nothing on it. A basic command for adding features to a widget is
(tk.putw <name> <attribute> <value>)
Here is an example.
(tk.putw .b -text "Hello World") |
This says that the -text attribute that shows the text on the button is to be set to "Hello World".
When this is done you will see this text appears on the button. You could have done this in one step by using
the options in the widget function.
(tk.widget .b button -text "Hello World") |
achieves the same result. Study TCL/tk to see the full list of attribute/value combinations.
Clicking on this button produces no result. A command has to be attached to the button.
Try
(tk.putw .b -command (freeze (pr "Hello World "))) |
If you click on this then nothing happens. However if you type
then 'Hello World' is printed off. tk.tcl->shen looks for an output from TCL/tl in the file
tcl-to-shen.txt. If there is no input, then this function hangs, waiting until there is. If you
enter (tk.tcl->shen) again then it hangs until you click the button.
Unless you are operating an event loop (see later), when you want to execute the result of clicking
a button you need to invoke tk.tcl->shen. This is because clicking a button is an event initiated within TCL/tk
and is not an event initiated within Shen. Many of the other commands listed below, are initiated within Shen,
even though they request information from TCL/tk. Hence these commands do not require tk.tcl->shen.
Here are some other buttons.
(tk.widget .b1 button
-text "Drink Me"
-fg "green"
-bg "yellow"
-command (freeze (pr "I'm shrinking!")))
(tk.widget .b2 button
-text "Bang"
-height 100
-width 50
-command (freeze (pr "bang!")))
(tk.pack [.b1 .b2]) |
| |
The function (tk.getw <name> <attribute>) will returns the value of an attribute;
thus (tk.getw .b2 -text) returns "Bang".
You can find on the official TCL/tk site a list of attributes of buttons.
Labels and Other Buttons
Labels are like buttons except they do not sustain commands and are by default flat and not raised.
Other styles of button found in TCL/tk are checkbuttons and radiobuttons. Shen/tk 1.0
has not assimilated checkbutton or radiobuttons, but a fair facsimile to checkbuttons can be created using
buttons.
(define mycheckbutton
{symbol --> button}
Widget -> (let Button (tk.widget Widget button)
Relief (tk.putw Button -relief sunken)
BG (tk.putw Button -bg "white")
Text (tk.putw Button -text " ")
Command (tk.putw Button -command (freeze (toggle Button)))
Button))
(define toggle
{button --> string}
Widget -> (if (= (tk.getw Widget -text) " ")
(tk.putw Widget -text "X")
(tk.putw Widget -text " ")))
|
Now we can create a checkbutton that toggles on and off. Under (tk.tcl->shen), when depressed an
X appears and when released it disappears.
(mycheckbutton .b6)
(tk.pack [.b6]) |
Entries and Textboxes
An entry is a widget into which a single line of information can be entered (such as a name for
instance). This creates an entry .e.
(tk.widget .e entry)
(tk.pack [.e])
|
| |
If I type my name Mark Tarver into the entry then (tk.getw .e -text) will retrieve the
value "Mark Tarver". I can change that value either by overtyping the contents of the entry or ordering Shen/tk
to change the value e.g. (tk.putw .e -text "John Tarver").
You can find on the official TCL/tk site a list of attributes of entries.
A textbox is similar to an entry except it sustains multiple lines. This creates a textbox .t.
(tk.widget .t text)
(tk.pack [.t])
|
| |
If I type my name Mark Tarver into the textbox then (tk.getw .t -text) will retrieve the
value "Mark Tarver". I can change that value either by overtyping the contents of the textbox or ordering Shen/tk
to change the value e.g. (tk.putw .t -text "John Tarver").
You can find on the official TCL/tk site a list of attributes of textboxes.
Dialog Windows
TCL/tk contains dialog windows which are pop-up windows designed for specific tasks such as:
- Choosing files.
- Choosing colours.
- Giving warnings.
- Giving choices.
The command (tk.openfile <options>) will open a dialog window that enables you to choose a file by clicking on
it. When the file is chosen, the path to the file is returned. See here for a list of options to
this dialog window.
The command (tk.savefile <options>) will open a dialog window that enables you to choose a file by clicking on
it and will also offer an entry for you to type in a path. When the file or a path is typed in chosen, the path is returned.
See here for a list of options to
this dialog window.
The command (tk.opencolour <options>) will open a dialog
window that enables you to choose a colour. When a colour is chosen a string containing the RGB values of the
chosen colour is returned. See here for a list of options to
this dialog window.
A message box is a dialog window that gives warnings or presents choices. The syntax is
(tk.messagebox <options>). An example is (tk.messagebox -message <message>) where <message>
is one of
- abortretryignore
- ok
- okcancel
- retrycancel
- yesno
- yesnocancel
Here are two examples.
(tk.messagebox -title "Overwrite?"
-type yesnocancel
-icon warning
-message "Overwrite file?")
|
|
|
(tk.messagebox -type ok
-title "Query Result"
-message "Found 1000 matches")
|
| |
The value returned is dependent, in most cases, on the user response.
Canvases
The command (tk.widget <canvasname> canvas <options>) creates a canvas which allows shapes
to be drawn. You can find on the official TCL/tk site a list of attributes of canvases.
The basic command for drawing shapes on a canvas is (tk.draw <canvasname> <shape> <coordinates>
<options>). Amongst the choices for shapes are:
- line
- arc
- rectangle
- oval
- polygon
This reference gives the list of shapes and attributes.
<coordinates> is a list of Cartesian coordinates given as natural numbers. In the case of lines
this list will be an even list of more than two coordinates giving the origin of a line and its destination(s).
Note that TCL/tk takes the 0 0 origin as marking the top left of the canvas rather than the bottom left.
These commands create a canvas with a line and an arc.
(tk.widget .c canvas -height 200 -width 200)
(tk.pack [.c])
(tk.draw .c line [0 0 100 100 150 105])
(tk.draw .c arc [10 20 50 50] -fill maroon)
|
| |
The Geometry Manager
The basic facilities for arranging widgets in a window are given by tk.pack and grid.
The syntax is (tk.pack <widgets> <options>) and (tk.grid <list of lists of widgets> <options>).
The full list of options for tk.pack is given here
and for grid here.
The grid command receives a list [L1 ...Ln] where
- each Li is a list of widgets
- for any Li and Lj the length of Li and Lj should be the same.
The widgets are then packed into a rectangular arrangment that reflects
the structure of [L1 ...Ln]. Note that requirement 2. is optional but that when it is not met
the packing is generally not optimal in appearance. Here are four buttons packed into a
rectangular arrangement seperated in the x and y axes.
(tk.widget .b1 button -text "1")
(tk.widget .b2 button -text "2")
(tk.widget .b3 button -text "3")
(tk.widget .b4 button -text "4")
(tk.grid [[.b1 .b2] [.b3 .b4]] -padx 10 -pady 10)
|
| |
Frames
A frame .f is created by the command (tk.widget .f frame <options>). Widgets can be packed into
a frame just as in a window. A frame is then packed into a window. A frame therefore is a means of gluing
together several widgets into a whole.
This example shows a frame .f1 that encloses two buttons, .f1.b1 and .f1.b2. The composite names
show that these widgets are embedded in .f1. The frame shows an orange background. The buttons inside the frame
are packed from left to right. The buttons outside the frame are packed without any packing specification
and so they are packed from top to bottom.
(tk.widget .f1 frame -relief groove -borderwidth 10 -background orange)
(tk.widget .f1.b1 button -text "Inside frame f1")
(tk.widget .f1.b2 button -text "Also inside frame f1")
(tk.pack [.f1.b1 .f1.b2] -side left)
(tk.pack [.f1])
(tk.widget .b1 button -text "Outside frame f1")
(tk.widget .b2 button -text "Also outside frame f1")
(tk.pack [.b1 .b2]) |
| |
The attributes of frames are given here
.
tk.unpack unpacks a widget, so that (tk.unpack [.b1 .b2]) will remove widgets .b1 .b2 from the window.
The Web
(tk.url <url>) returns the contents of a web page as designated by it's URL which is
encased in a string. These contents are returned as a list of code points (integers). The type of url is
string --> (list number).
(tk.url "https://shenlanguage.org/Shentk.html")
[60 104 116 109 108 62 13 10 32 32 32 32 32 32 32 32 32 32 32 32 ... etc] : (list number) |
There are are several utility functions designed to work with tk.url . tk.url->text of type
(list number) --> (list string) will return the text component of the url output, removing the HTML markup.
As shown below, this is not 100% effective since (e.g.) scripting language commands may enter the result but
it eliminates more than 95% of the markup.
(time (let ASCII (tk.url "https://shenlanguage.org/")
Text (tk.url->text ASCII)
Text))
run time: 0.13999998569488525 secs
["The" "Shen" "Group" "var" "sc" "_" "project" "=" "12669375" ";" "var" "sc" "_" "invisible" "=" "1" ";"
"var" "sc" "_" "security" "=" """ "a31d15ef" """ ";" "&" "nbsp" ";" "The" "Shen" "Group" "&" "nbsp" ";"
"&" "nbsp" ";" "Home" "Learn" "Download" "Community" "Open" "Science" "Donate" "Contact" "Our" "mission"
"is" "to" "bring" "the" "power" "of" "Shen" "technology" "to" "every" "major" "programming" "platform"
"used" "by" "industry" "and" "deliver" "to" "programmers" "the" "great" "power" "of" "Shen" "." "The"
"word" "'" "Shen" "'" "means" "'" "highest" "spirit" "'" "in" "Chinese" "and" "indicates" "our" "goal"
"is" "to" "transcend" "the" "divisions" "between" "computer" "languages" "." "Since" "2021" "Shen" "has"
"been" "based" "on" "the" "S" "series" "kernels" "." "Features" "pattern" "matching" "," "lambda" "calculus"
"consistency" "," "macros" "for" "defining" "domain" "specific" "languages" "," "optional" "lazy"
"evaluation" "," "static" "type" "checking" "based" "on" "sequent" "calculus" "," "one" "of" "the" "most"
"powerful" "systems" "for" "typing" "in" "functional" "programming" "," "an" "integrated" "fully"
"functional" "Prolog" "," "an" "inbuilt" "compiler" "-" "compiler" "," "a" "BSD" "kernel" "under" "15"
"languages" "(" "Lisp" "," "Python" "," "Javascript" "," "C" "." "." "." ")" "and" "operating" "systems"
"(" "Windows" "," "Linux" "," "OS" "/" "X" ")" "," "is" "extensively" "documented" "in" "a" "book" "has"
... etc] : (list string) |
The function tk.sentences of type (list string) --> number --> (list (list string)) takes
the output of url->text and organises it into a list of sentences, where a sentence is a list of strings.
The numeric input to sentences is a natural number which limits the length of a sentence. sentences
is often quite effective at eliminating the remaining junk left behind by url->text .
(time (let ASCII (tk.url "https://en.wikipedia.org/wiki/Leeds")
Text (tk.url->text ASCII)
Sentences (tk.text->sentences Text 50)
Sentences))
run time: 0.20300006866455078 secs
[["SuggestedEditSession" """ "]" ";" "(" "RLQ" "=" "window"]
["For" "the" "district" "," "see" "City" "of" "Leeds"]
["For" "other" "uses" "," "see" "Leeds" "(" "disambiguation" ")"]
["It" "is" "the" "largest" "settlement" "in" "Yorkshire" "and" "the" "administrative" "centre" "of"
"the" "City" "of" "Leeds" "Metropolitan" "Borough" "," "which" "is" "the" "second" "most" "populous"
"district" "in" "the" "United" "Kingdom"] ["It" "is" "built" "around" "the" "River" "Aire" "and"
"is" "in" "the" "eastern" "foothills" "of" "the" "Pennines"] ["The" "city" "was" "a" "small" "manorial"
"borough" "in" "the" "13th" "century" "and" "a" "market" "town" "in" "the" "16th" "century"]
["An" "inhabitant" "of" "Leeds" "is" "locally" "known" "as" "a" "Loiner" "," "a" "word" "of"
"uncertain" "origin" "." "&" "#" "91" ";" "23" "&" "#" "93" ";" "The" "term" "Leodensian" "is"
"also" "used" "," "from" "the" "city" "'" "s" "Latin" "name"] ["Economic" "development"
"[" "edit" "]" "The" "Leeds" "and" "Liverpool" "Canal" "at" "Granary" "Wharf" "The" "Leeds"
"Corn" "Exchange" "opened" "in" "1864"] ["Leeds" "developed" "as" "a" "market" "town" "in" "the"
"Middle" "Ages" "as" "part" "of" "the" "local" "agricultural" "economy"] ["The" "new" "charter"
"incorporated" "the" "entire" "parish" "," "including" "all" "eleven" "townships" "," "as" "the"
"Borough" "of" "Leeds" "and" "withdrew" "the" "earlier" "charter"] ... etc] : (list (list string)) |
tk.links of type (list number) --> (list string) will return the list of hyperlinks
found in the url output.
(time (tk.links (tk.url "https://shenlanguage.org/")))
run time: 0.07799983024597168 secs
["https://www.statcounter.com/counter/counter.js"
"https://statcounter.com/"
"https://c.statcounter.com/12669375/0/a31d15ef/1/"
"https://shenlanguage.org/logo3.gif"
"https://shenlanguage.org/index.html"
"https://shenlanguage.org/learn.html"
"https://shenlanguage.org/download.html"
"https://shenlanguage.org/community.html"
"https://shenlanguage.org/opensci.html"
"https://shenlanguage.org/donate.html"
"https://shenlanguage.org/contact.html"
"https://shenlanguage.org/s-series.html "
"https://shenlanguage.org/reviews.html "
"https://www.amazon.co.uk/Book-Shen-Fourth-Mark-Tarver/dp/1915012112 "
"https://shenlanguage.org/lpc.html "
"https://shenlanguage.org/logiclab.html "
"https://shenlanguage.org/logiclab.html "
"https://shenlanguage.org/lpc.html "
"https://shenlanguage.org/THORN.pdf "
"https://www.youtube.com/channel/UCZrMxRSqe0LITKewwhK2nvA/videos "
"https://shenlanguage.org/yggdrasil.html "] : (list string) |
The Event Loop
The 0-place function tk.event-loop creates an event loop in which Shen/tk waits to receive
commands from TCL/tk. With the event loop activated tk.tcl->shen is not needed for button-driven events to be
detected. Note that widgets such as message boxes that receive information from TCL/tk are not affected
by the existence of the event loop since they temporarily suspend its action in order to prevent the data
being consumed. An error, whether originating from a message from TCL/tk or arising from Shen code, will
cause the loop to be broken and exit to occur.
The following program creates two buttons and enters the event loop. Clicking on .hello
causes hello world to be printed. clicking on .abort causes the event loop to be broken.
(tk.widget .hello -text "Hello World" -command (freeze (output "hello world~%")))
(tk.widget .abort -text "Abort" -command (freeze (error "aborted")))
(tk.pack [.hello .abort])
(tk.event-loop) |