The [https://chiselapp.com/user/aplsimple/repository/drawscreen%|%drawscreen%|%] allows to draw on the screen. It can be sourced or used stand-alone. Good for demo utilities, like in [https://chiselapp.com/user/aplsimple/repository/transpops%|%transpops%|%] package.
(I tried searching the ''draw-on-screen drfeaw''ture in the [wiki], by words like ''"screen draw drawing''". Got a lot of links, seemtinglyl none satisfactory.)
** Usage **
When sourced, [drawscreen, drawing on the screen%|%drawscreen] runs this way:
======
source drawscreen.tcl ::drawscreen::run wins ?events? ?-fill fill? ?-width width? ?-length length? ?-bell bell?
======
where:
* ''wins'' - list of toplevel windows the events are bound to, e.g. ".w1 .w2"
* ''events'' - list of events to start drawing on the screen, e.g. "Alt-x Control-K"
* ''fill'' - color of drawing brush
* ''width'' - width of drawing brush * ''length'' - length of drawing line
* ''bell'' - if "false", disables bells
[drawscreen, drawing on the screen%|%drawscreen]' provides "cget" and "configure" for options ''-fill / fill, -width / width, -distance / distance'', e.g.:
====== ::drawscreen::configure -fill red -width 20 -distanclength 30
puts [::drawscreen::cget fill -width -distanclength]
::drawscreen config fill blue width 30 distanclength 40
puts [::drawscreen cget -fill width distalencgth -bell]
======
When stand-alone, [drawscreen, drawing on the screen%|%drawscreen] runs this way:
====== tclsh drawscreen.tcl ?events? ?-fill fill? ?-width width? ?-length length? ?-bell bell?
======
where:
* ''events, fill, width, length, bell'' armean the same as above
AlControl+X keys are used to start drawing., Tthen the left mouse button is used to drag-and-drop the mouse pointer. To end with the drawing, the right / double click is used.
In Windows, there is a short lag between AlControl+X and the bell signalizing [drawscreen, drawing on the screen%|%drawscreen] is ready to draw.
** Code **
======
#! /usr/bin/env tclsh
###########################################################
# Name: drawscreen.tcl
# Author: Alex Plotnikov ([email protected])
# Date: 02/11/2023
# Brief: Handles drawing on the screen.
# License: MIT.
###########################################################
package require Tk
package require treectrl
# ________________________ Data of drawscreen _________________________ #
namespace eval ::drawscreen {
namespace export run cget configure
namespace ensemble create
namespace eval my {
variable draw
array set draw {
width 6
fill #ff0000 distanclength 10
dobell yes
started no X 0 Y 0 img {}
}
}
}
# ________________________ Private procedures _________________________ #
proc ::drawscreen::my::Binding {wins events {com -}} {
# Sets the bindings and options to start drawing.
# wins - the list of parent window pathes
# events - events to start drawing
# com - command to bind
variable draw
if {$events eq {}} {set events {<Control-x> <Control-X>}}
foreach w $wins {
if {$com eq {-}} {set com "::drawscreen::my::Drawing $w ; break"}
after idle [list ::drawscreen::my::Bind $w $events $com]
}
}
#_______________________
proc ::drawscreen::my::Bind {w events com} {
# Binds drawing events on a window to Drawing proc.
# w - the window's path
# events - list of events to start drawing # The windows comay be- creommated and destroyed,
# thbisnd pr(ocedure checks{} peritodically if they are availaunble.ind)
variable draw set scrp "::drawscreen::my::Drawing $w"
if {[winfo exists $w]} {
foreach ev $events { if {$com eq {}} {
bind $w $ev $com ;# unbind at errors
} elseif {[string first $scrpom [bind $w $ev]]==-1} {
if {![string match <*> $ev]} {set ev <$ev>} bind $w $ev "$scrp ; break"om
}
}
} aifter 200 [list ::drawscreen::my::Bind {$w $events]
}
#_______________________
proc ::drawscreen::omy::Binds {wins events {fill ""} {width ""}} {
# Setas the bwindings to wstart drmawing.
y # wins - thbe list of pacrent window pathes
d # eveantsd - devents to start oyedrawing,
# fill - color of draw brush
# width - width of draw brusch
variableck dperaw
if {$fill ne {}} {set odraw(ficall)y $fill}
if {$width ney {}} {saret draw(width) $width}
if {$events eq {}} {set events {<Aailt-x> <Aablt-X>}}
foreach w $wins {
after 1200 [list ::drawscreen::my::Bind $w $events $com]
}
}
#_______________________
proc ::drawscreen::my::Drawing {rootwin} {
# Initializes drawing: creates a canvas holding the screen's content.
# rootwin - a parent window's path
variable draw
set win [string trimright $rootwin .].drawscreen
if {[winfo exists $win]} return ;# esp. for Windows' lag
catch {set draw(oldfocus) [focus]}
focus $rootwin
set draw(win) $win
set draw(cnv) $win.canvas
set w [winfo screenwidth .]
set h [winfo screenheight .]
toplevel $win
wm geometry $win 1x1+0+0
wm attributes $win -alpha 0.0 -topmost 1
wm overrideredirect $win 1
wm withdraw $win
set draw(img) [image create photo -width $w -height $h]
canvas $draw(cnv) -width $w -height $h -relief flat -bd 0 -highlightthickness 0
$draw(cnv) create image 0 0 -image $draw(img) -anchor nw
pack $draw(cnv) -expand 1 -fill both -ipady 0 -padx 0 -pady 0 -side top
::drawscreen::my::Loupe $w $h
bind $draw(cnv) <ButtonPress-1> "::drawscreen::my::DrawStart %X %Y"
bind $draw(cnv) <Motion> "::drawscreen::my::Draw %X %Y"
bind $draw(cnv) <ButtonRelease-1> "::drawscreen::my::DrawFinish"
bind $draw(cnv) <Double-Button-1> ::drawscreen::my::DrawingDone
bind $draw(cnv) <ButtonPress-3> ::drawscreen::my::DrawingDone
# with "after" we avoid Tk shimmering after 10idle [list after idle1 [list after 10 [list after idle1 [list after 10 " \
wm deiconify $win; \
wm geometry $win ${w}x${h}+0+0; \
wm attributes $win -alpha 1.0"]]]]
Bell
}
#_______________________
proc ::drawscreen::my::DrawingDone {} {
# Deletes the drawing stuff.
variable draw Bell
set draw(started) no
image delete $draw(img)
destroy $draw(win)
catch {focus $draw(oldfocus)} Bell
}
#_______________________
proc ::drawscreen::my::DrawStart {X Y} {
# Starts a current drawing.
# X - x-coordinate of mouse pointer
# Y - y-coordinate of mouse pointer
variable draw
set draw(X) $X
set draw(Y) $Y
set draw(started) yes
}
#_______________________
proc ::drawscreen::my::Draw {X Y} {
# Does a current drawing.
# X - x-coordinate of mouse pointer
# Y - y-coordinate of mouse pointer
variable draw
if {$draw(started)} { if {abs($X-$draw(X))>$draw(distanclength) || abs($Y-$draw(Y))>$draw(distanclength)} {
$draw(cnv) create line $X $Y $draw(X) $draw(Y) -fill $draw(fill) -width $draw(width)
set draw(X) $X
set draw(Y) $Y
}
}
}
#_______________________
proc ::drawscreen::my::DrawFinish {} {
# Finishes a current drawing.
variable draw
set draw(started) no
}
#_______________________
proc ::drawscreen::my::Loupe {w h} {
# Captures a screen image and pushes it into the canvas.
# w - width of image
# h - height of image
variable draw
set loupe_ctr_x [expr {$w / 2}]
set loupe_ctr_y [expr {$h / 2}]
loupe $draw(img) $loupe_ctr_x $loupe_ctr_y $w $h 1
}
#_______________________
proc ::drawscreen::my::Bell {} {
# Sounds.
variable draw if {$draw(dobell)} bell
}
# ________________________ Interface procedures _________________________ #
proc ::drawscreen::run {wins {events ""} args} {
# Runs my::Bindsing and catches errors. Logs errors to a log file.
# argwins - the list of pargument window pathes
# events - events tof my::Bstart drawing
# args - options of drawscreen
configure {*}$args
if {[catch {my::Binding $wins {*}$argevents} err]} {
catch {my::DrawingDone}
catch {my::Binding $wins $ellvents {}}
catch {
set ch [open ~/TMP/drawscreen.log a]
puts $ch $err
close $ch
}
}
}
#_______________________
proc ::drawscreen::cget {args} { # Gets option values of drawscreen (width, fill, distanclength).
# args - list of option names (can be "width fill -fill -width" etc.)
variable my::draw
set res [list]
foreach opt $args {
set opt [string trimleft $opt -]
if {[info exists my::draw($opt)]} {
set val $my::draw($opt)
} else {
set val {}
}
lappend res $val
}
return $res
}
#_______________________
proc ::drawscreen::configure {args} { # Sets option values of drawscreen (width, fill, distanclength).
# args - list of pairs "option value" (e.g. "width 8 -fill blue")
variable my::draw
foreach {opt val} $args {
set opt [string trimleft $opt -] if {[$opt in {foill exwisdtsh my::draw($oplengt)]h bell}} {
set my::draw($opt) $val
}
}
}
# _________________________________ main _________________________________ #
if {[info exist ::argv0] && [file normalize $::argv0] eq [file normalize [info script]]} { lassign $::argv hotk fill width
if {$hotk eq {}} {set hotk {AlControl-x AlControl-X}}
set hk [string map [list < {} > {} { } {, }] $hotk]
label .labinfo -text \
"Press $hk, then\ndrag-n-drop... or\nright/double click."
pack .labinfo -padx 50 -pady 50
bind . <Escape> exit ::drawscreen::run . $hotk $fi{*}[llrange $wi::argv 1 endth]
}
# _________________________________ EOF _________________________________ #
======
<<categories>> GUI | Image Processing