Custom Toplevel Frame

Custom Toplevel Frames

- 26 October 2010 - Hello tcl'ers, I would like to share with you a method to create a custom toplevel frame, such as a rounded rectangular or full circular/elliptical one. A solution that I present here is for the Win OS, it's using dll's provided by the OS with the help of Ffidl to access it. To demonstrate how it is implemented in tG² , click here for a short movie. Enjoy!

Note: another enthousiast has already developed a solution for the X OS, see Managed and shaped toplevel.

# ------------------------------------------------------------------------------
# TopTcl_1.tcl for tG² is under BSD License, Copyright (C) 2010 by 'SeS'
# See https://wiki.tcl-lang.org/25888
# Permission is hereby granted, free of charge, to any person obtaining a copy of 
# this software and associated documentation files (the ``Software''), to deal in 
# the Software without restriction, including without limitation the rights to use, 
# copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 
# Software, and to permit persons to whom the Software is furnished to do so, 
# subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in all 
# copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR 
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ------------------------------------------------------------------------------

# ------------------------------------------------------------------------------
# Purpose        : creates alternative toplevel frame with optional transparent shadow
# ------------------------------------------------------------------------------
proc TopTcl {tParent TLT W H rndArc {shadowType 3} {sfg black}} {
  wm overrideredirect $tParent 1

  if {$shadowType > 0} {
    wm attribute $tParent -topmost 1
    toplevel ${tParent}copy 
    wm geometry ${tParent}copy 1x1+5000+5000
    wm overrideredirect ${tParent}copy 1
    wm attribute ${tParent}copy -alpha 0.5
    wm title ${tParent}copy "${tParent}copy_shadow"
    wm transient ${tParent}copy $tParent
  
    pack [frame ${tParent}copy.lab -bg $sfg -bd 0 -relief flat] -expand 1 -fill both
    update
    switch $TLT {
      "rrectangle" {dll_SetWindowRgn [getHwnd [wm title ${tParent}copy]] [dll_CreateRoundRectRgn 0 0 $W $H $rndArc $rndArc] True}
      "elliptic"   {dll_SetWindowRgn [getHwnd [wm title ${tParent}copy]] [dll_CreateEllipticRgn  [lindex $rndArc 0] [lindex $rndArc 1] $W $H] True}
    }
    bind $tParent <FocusOut>  "+; wm attribute ${tParent}copy -alpha 0.1"
    bind $tParent <FocusIn>   "+; wm attribute ${tParent}copy -alpha 0.5; eval \[bind $tParent <Configure>]"
    bind $tParent <Configure> "+; 
      set geo \[split \[split \[wm geometry $tParent] x\] +\]
      wm deiconify ${tParent}copy
      wm geometry ${tParent}copy \[lindex \$geo 0 0]x\[lindex \$geo 0 1]+\[expr \[lindex \$geo 1]+$shadowType]+\[expr \[lindex \$geo 2]+$shadowType]
    "
    wm title ${tParent}copy ""
  }
  
  switch $TLT {
    "rrectangle" {dll_SetWindowRgn [getHwnd [wm title $tParent]] [dll_CreateRoundRectRgn 0 0 $W $H $rndArc $rndArc] True}
    "elliptic"   {dll_SetWindowRgn [getHwnd [wm title $tParent]] [dll_CreateEllipticRgn  [lindex $rndArc 0] [lindex $rndArc 1] $W $H] True}
  }
  #enableMoveFromAnywhere $tParent; available in official release of tG²
}

# ------------------------------------------------------------------------------
# TopTcl_1.tcl wrapper has dependencies to ffidl package
# ------------------------------------------------------------------------------
package require Ffidl 0.6
ffidl::callout dll_CreateRoundRectRgn {int int int int int int} int [ffidl::symbol gdi32.dll CreateRoundRectRgn]
ffidl::callout dll_FindWindowTitle    {int pointer-utf8} int        [ffidl::symbol user32.dll FindWindowA]
ffidl::callout dll_SetWindowRgn       {int int pointer-utf8} int    [ffidl::symbol user32.dll SetWindowRgn]
ffidl::callout dll_CreateEllipticRgn  {int int int int} int         [ffidl::symbol gdi32.dll CreateEllipticRgn]
proc getHwnd {windowname} {return [dll_FindWindowTitle 0 $windowname]}

# ------------------------------------------------------------------------------
# TEST SCRIPT:
# ------------------------------------------------------------------------------
# Test conditions:
#   -WinXP OS
#   -ActiveState's tcl/tk v8.4.19 distribution, using "wish"
#   -Ffidl v0.6

set MainProgramSize [split [lindex [split [wm geo .] +] 0] x]
bind . <Escape> {exit}
TopTcl . rrectangle [lindex $MainProgramSize 0] [lindex $MainProgramSize 1] 20 10

  Comments

See also Shape. You can also do similar things - though possibly a little more limited than the above - using wm (at least on Windows):

. configure -background yellow
pack [label .l -text "Testing" -background red -foreground yellow -font "Arial 36 bold"]
wm attributes . -transparentcolor yellow
wm override . 1 ;# add code for dragging the window around
bind . <Escape> {exit}

SeS : thanks for the additional info MG, this is interesting, maybe I can combine/integrate this into tG²