1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
|
#! /usr/bin/env tclsh
package require Tk 8.5-
# Copyright (c) 2005-2023 Keith Nash.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
### This demo explores vertical scrolling on the Mac
### For a short example, see ntextExample.tcl
### To explore ntext indentation, try ntextDemoIndent.tcl
### To explore the ntext options, try ntextDemoBindings.tcl
### For corner cases in scrolling, try ntextDemoScroll.tcl
# This string defines the text that will be displayed in each widget:
set message {Ntext tries to offer a user experience that is as close as possible to the native "look and feel" of each platform.
This example demonstrates the Mac bindings for keyboard navigation, and in particular the use of the keyboard for vertical scrolling. The description below will not agree with the behavior of the application unless you are running it on a Mac.
If you are using a Mac, one of the sets of radiobuttons in the control panel (right) will not be disabled (this set of buttons is not present on non-Mac platforms). These radiobuttons allow you to set the value of ::ntext::classicParagraphs, which controls the response to the keyboard events described in (5) below.
The key names are those used in Tk bindings (see the Tk manual page for the bind command).
The "modifiers" Shift, Control, Option, or Command are applied to an event if the corresponding "modifier key" is held down while an ordinary key is pressed.
The keys that generate each modifier are:
Shift - left or right shift key
Control - left or right "ctrl" key
Option - left or right "alt ⌥" key
Command - left or right "⌘" key
The ordinary (non-modifier) keys relevant here are Up, Down, Prior, Next, Home, and End.
On a full Apple keyboard, these navigation keys are in the block that lies between the main part of the keyboard, and the numeric keypad.
The layout of this part of the keyboard is:
F14 F15 F16
fn ↖ ⇞
⌦ ↘ ⇟
↑
← ↓ →
The "fn" key may instead be labeled "help". The "⌦" key is also labeled "delete".
The same layout, but now using the Tk names for the keys, is:
F14 F15 F16
Help Home Prior
Delete End Next
Up
Left Down Right
On reduced Apple keyboards, the nine keys F14 to Next are absent; the four cursor keys Up, Left, Down, Right are squeezed into the lower right of the keyboard.
There are five sets of bindings that use the keyboard for vertical scrolling.
(1) Prior and Next keys
<Prior> and <Next> scroll the text widget vertically without moving the insert mark (the "cursor").
<Control-Prior> and <Control-Next> scroll the text widget vertically, AND move the insert mark.
<Shift-Prior> and <Shift-Next> scroll the text widget vertically, AND move the insert mark, AND extend the selection.
<Option-Prior> and <Option-Next> scroll the text widget vertically, AND move the insert mark - the same as <Control-Prior> and <Control-Next> respectively.
<Command-Prior> and <Command-Next> do nothing.
The Shift modifier has no effect in any cases except <Shift-Prior> and <Shift-Next>.
(2) Home and End keys
<Home> and <End> scroll to the top and bottom of the text widget respectively, without moving the insert mark.
<Shift-Home> and <Shift-End> scroll to the top and bottom of the text widget respectively, AND move the insert mark, AND extend the selection.
<Control-Home> and <Control-End> do nothing.
<Command-Home> and <Command-End> do nothing.
<Option-Home> and <Option-End> do nothing.
(3) Up and Down keys, with Command modifier
<Command-Up> and <Command-Down> scroll to the top and bottom of the text widget respectively, AND move the insert mark.
<Command-Shift-Up> and <Command-Shift-Down> scroll to the top and bottom of the text widget respectively, AND move the insert mark, AND extend the selection.
On other platforms these operations are bound to the keys <Control-Home>, <Control-End>, <Control-Shift-Home>, <Control-Shift-End> respectively.
(4) Up and Down keys, with Control modifier
On recent versions of macOS, these keystrokes are intercepted by the windowing system. To avoid confusion, Ntext defines these keystrokes to have no effect on any version of macOS.
(5) Up and Down keys, with Option modifier
if {::ntext::classicParagraphs == 0} (the default value)
<Option-Up> goes to the previous SLL.
<Shift-Option-Up> goes to the previous SLL, AND also extends the selection.
<Option-Down> goes to the next ELL.
<Shift-Option-Down> goes to the next ELL, AND also extends the selection.
where
SLL = start of a logical line
ELL = end of a logical line
and a logical line is a single line of text that may have been wrapped around (when the text widget has option -wrap word or -wrap char) into multiple "display lines"
This behavior is the same as for the Mac application TextEdit.
if {::ntext::classicParagraphs == 1}
The behavior differs from that of other Mac applications.
<Option-Up>, <Option-Down> scroll the text widget up and down, AND move the insert mark to the start of the previous/next "paragraph".
<Shift-Option-Up>, <Shift-Option-Down> scroll the text widget up and down, AND move the insert mark to the start of the previous/next "paragraph", AND extend the selection.
The start of a paragraph is the first non-blank character after a blank line.
On non-Mac platforms, these actions are bound in Ntext and Text to the events <Control-Up>, <Control-Down>, <Shift-Control-Up>, <Shift-Control-Down>. The Control- bindings are also defined in the Text binding tag on the Mac, although on recent versions of macOS these keystrokes are intercepted by the windowing system).
}
# End of string for widget text.
package require ntext 1.0
# Whether Shift-Button-1 ignores changes made by the kbd to the insert mark:
set ::ntext::classicMouseSelect 0
# Whether Shift-Button-1 has a variable or fixed anchor:
set ::ntext::classicAnchor 0
# Whether the traditional "extra" bindings are activated (default is 0):
set ::ntext::classicExtras 0
# Whether to use new or classic word boundary detection:
set ::ntext::classicWordBreak 0
# Set to 0 to align wrapped display lines with the first display line of the logical line:
set ::ntext::classicWrap 0
# Set to 0 to follow Mac Aqua conventions on placement of the insert mark
# when a selection is cancelled by keyboard navigation:
# Has effect on all platforms. Default value is 0 on Aqua, 1 on other platforms.
set ::ntext::classicSelection 0
# Set to 0 to follow Mac Aqua conventions on vertical scrolling with the
# Up/Down cursor keys and Option ("Alt") modifier keys.
# Has effect only on Aqua.
set ::ntext::classicParagraphs 0
# ------------------------------------------------------------------------------
# Now begin constructing the GUI.
# ------------------------------------------------------------------------------
set col #e0dfde
. configure -bg $col
pack [frame .f -bg $col] -side right -anchor e
pack [frame .cp -bg $col -bd 2p -relief ridge] -anchor ne -in .f
pack [label .cp2 -bg $col -text "(These options are applied only\n to the right-hand text widget)"] -anchor n -pady 4p -in .f
pack [frame .rhf -bg $col] -side right -anchor nw
pack [scrollbar .rhf.scroll -bg $col] -side right -anchor nw -expand 1 -fill y
pack [text .rhf.new ] -padx 2 -side right -anchor nw
bindtags .rhf.new {.rhf.new Ntext . all}
.rhf.new configure -wrap word -undo 1 -yscrollcommand {.rhf.scroll set}
.rhf.new configure -width 61 -height 29 -font TkFixedFont -bg white
.rhf.new insert end " I use the Ntext bindings.\n\n$message"
.rhf.new edit separator
.rhf.scroll configure -command {.rhf.new yview}
pack [frame .lhf -bg $col] -side left -anchor ne
pack [scrollbar .lhf.scroll -bg $col] -side left -anchor nw -expand 1 -fill y
pack [text .lhf.classic ] -padx 2 -side left -anchor nw
.lhf.classic configure -width 61 -height 29 -wrap word -undo 1 -font TkFixedFont -bg #FFFFCC -yscrollcommand {.lhf.scroll set}
.lhf.classic insert end " I use the (default) Text bindings.\n\n$message"
.lhf.classic edit separator
.lhf.scroll configure -command {.lhf.classic yview}
# What is the largest font such that the demo will fit on the screen?
# Allow 100 pixels or 1 inch for desktop panels that are not counted in wm maxsize.
# Reduce the font if necessary.
set siz [font actual TkFixedFont -size]
set maxPts [expr { ([lindex [wm maxsize .] 1] - 6 - max (100., 72. * [tk scaling])) * $siz / ([winfo reqheight .lhf.classic] - 6) }]
set siz [expr { int(min($siz, $maxPts)) }]
font configure TkFixedFont -size $siz
set fam [font actual TkFixedFont -family]
set TitleFixedFont [list $fam $siz bold]
.lhf.classic tag add red 1.0 2.0
.rhf.new tag add blue 1.0 2.0
.lhf.classic tag configure red -foreground #A00000 -font $TitleFixedFont
.rhf.new tag configure red -foreground #A00000 -font $TitleFixedFont
.rhf.new tag configure blue -foreground #0000A0 -font $TitleFixedFont
# ------------------------------------------------------------------------------
# Highlight names of bindings and modifiers in the text.
# ------------------------------------------------------------------------------
foreach term {
<
>
Prior
Next
Up
Down
Left
Right
Home
End
Help
Delete
F14 F15 F16
Control
Command
Option
Shift
Control-
Command-
Option-
Shift-
} {
set first 1
set lenny [string length $term]
set nextPlace 1.0
while {1} {
set place [.rhf.new search -- $term $nextPlace end-1c]
if {$place eq {}} {
break
}
set nextPlace ${place}+${lenny}c
if {$first && $term in {F14 F15 F16}} {
# The first use of these terms is not as a binding name.
} else {
.lhf.classic tag add red $place $nextPlace
.rhf.new tag add red $place $nextPlace
}
set first 0
}
}
# ------------------------------------------------------------------------------
# The code below populates frame .cp and implements the
# control panel for selecting ntext configuration options.
# ------------------------------------------------------------------------------
set col2 #f0efee
set col3 #d0cfce
font configure TkDefaultFont -size $siz
set fam [font actual TkDefaultFont -family]
set TitleVariableFont [list $fam $siz bold]
proc radiobutton2 {w args} {
radiobutton23 $w 2 {*}$args
}
proc radiobutton3 {w args} {
radiobutton23 $w 3 {*}$args
}
proc radiobutton23 {w num args} {
if {$num == 2} {
set bg $::col2
set ab $::col3
} else {
set bg $::col3
set ab $::col2
}
frame $w -bg $bg
radiobutton $w.rb -bg $bg -activebackground $ab -highlightthickness 0 -padx 4p -pady 2p -anchor w {*}$args
pack $w.rb -expand 1 -fill both -pady 2p
return $w
}
label .cp.n:l -bg $col2 -text "Options for ntext bindings" -font $TitleVariableFont
grid .cp.n:l -ipady 2 -sticky ewn -columnspan 3
label .cp.h:l -bg $col3 -anchor e -text "classicMouseSelect: "
radiobutton3 .cp.h:off -text "Off" -variable ::ntext::classicMouseSelect -value 0
radiobutton3 .cp.h:on -text "On " -variable ::ntext::classicMouseSelect -value 1
grid .cp.h:l .cp.h:off .cp.h:on -ipady 2 -sticky ewns
label .cp.g:l -bg $col2 -anchor e -text "classicAnchor: "
radiobutton2 .cp.g:off -text "Off" -variable ::ntext::classicAnchor -value 0
radiobutton2 .cp.g:on -text "On " -variable ::ntext::classicAnchor -value 1
grid .cp.g:l .cp.g:off .cp.g:on -ipady 2 -sticky ewns
label .cp.k:l -bg $col3 -anchor e -text "classicExtras: "
radiobutton3 .cp.k:off -text "Off" -variable ::ntext::classicExtras -value 0
radiobutton3 .cp.k:on -text "On " -variable ::ntext::classicExtras -value 1
grid .cp.k:l .cp.k:off .cp.k:on -ipady 2 -sticky ewns
label .cp.m:l -bg $col2 -anchor e -text "classicSelection: "
radiobutton2 .cp.m:off -text "Off" -variable ::ntext::classicSelection -value 0
radiobutton2 .cp.m:on -text "On " -variable ::ntext::classicSelection -value 1
grid .cp.m:l .cp.m:off .cp.m:on -ipady 2 -sticky ewns
if {[tk windowingsystem] eq "aqua"} {
label .cp.p:l -bg $col3 -text "classicParagraphs: "
radiobutton3 .cp.p:off -text "Off" -variable ::ntext::classicParagraphs -value 0
radiobutton3 .cp.p:on -text "On " -variable ::ntext::classicParagraphs -value 1
grid .cp.p:l .cp.p:off .cp.p:on -ipady 2 -sticky ewns
}
set wordBreakChoice new
label .cp.j:l -bg $col2 -anchor e -text "classicWordBreak: "
radiobutton2 .cp.j:off -text "Off" -variable wordBreakChoice -value "new" -command setPattern
radiobutton2 .cp.j:unix -text "On (Unix)" -variable wordBreakChoice -value "unix" -command setPattern
radiobutton2 .cp.j:wind -text "On (Windows)" -variable wordBreakChoice -value "windows" -command setPattern
frame .cp.j:sp1 -bg $col2
frame .cp.j:sp2 -bg $col2
grid .cp.j:l .cp.j:off .cp.j:unix -ipady 2 -sticky ewns
grid .cp.j:sp1 .cp.j:sp2 .cp.j:wind -ipady 2 -sticky ewns
proc setPattern {} {
global wordBreakChoice
set platform $::tcl_platform(platform)
if {$wordBreakChoice eq "unix"} {
set ::tcl_platform(platform) unix
set ::ntext::classicWordBreak 1
} elseif {$wordBreakChoice eq "windows"} {
set ::tcl_platform(platform) windows
set ::ntext::classicWordBreak 1
} else {
set ::ntext::classicWordBreak 0
}
::ntext::initializeMatchPatterns
set ::tcl_platform(platform) $platform
}
# Disable all radiobuttons except .cp.p.on .cp.p.off which are relevant to this demo:
# And all labels except .cp2, .cp.p.l
foreach rb {
.cp.h:on.rb
.cp.h:off.rb
.cp.g:on.rb
.cp.g:off.rb
.cp.k:on.rb
.cp.k:off.rb
.cp.j:wind.rb
.cp.j:unix.rb
.cp.j:off.rb
.cp.m:on.rb
.cp.m:off.rb
.cp.h:l
.cp.g:l
.cp.k:l
.cp.j:l
.cp.m:l
} {
$rb configure -state disabled
}
|