Advertisement
urbasus

pantree

Apr 18th, 2020
1,842
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
TCL 4.26 KB | None | 0 0
  1. # Pantree documentation
  2. #
  3. # Purpose
  4. # Make nested paned windows simpler to setup and maintain.
  5. # Main pain point to address is the combined complexity from:
  6. # - Geometry specification
  7. # - Window addressing
  8. # - Content definition
  9. #
  10. # Design
  11. # There are two APIs:
  12. # - The pantree proc(edure)
  13. # - The recipe dict(orionary)
  14. #
  15. # Pantree proc parses a list specifying:
  16. # - Split orientation; v(ertical) or h(orizontal)
  17. # - Frame content; either a recipe or a pantree specification (recursion)
  18. # - Initial weights of frame content, increasing with a '+' postfix
  19. #
  20. # A recipe is a proc creating a window. Recipes are user defined.
  21. #
  22. # Example
  23. # This pantree specification:
  24. # h d+ {v t+ x}
  25. #
  26. # Results in a window layout looking something like this:
  27. # /-------\
  28. # |dddd|tt|
  29. # |dddd|tt|
  30. # |dddd|tt|
  31. # |dddd|--|
  32. # |dddd|xx|
  33. # \-------/
  34. #
  35. # Detailed explanation:
  36. # - User defined recipes: d=diagram, t=table, x=text
  37. #   - Names may be any number of characters, but must not include characters [.+] or collide with split words [vh]
  38. # - 'h' is a split horizontally oriented. What follows is a list of nested pantree specifications
  39. # - 'd+' is a recipe of type 'd' (diagram), weight 2 (+ means 'plus 1')
  40. # - {h t++ x} is a pantree specification
  41. #   - 'v' is a split vertically oriented
  42. #   - 't++' is a recipe of type 't' (table), weight 3 (++ means 'plus 2')
  43. #   - 'x' is a recipe of type 'x' (text), weight 1
  44. #
  45. # Window addressing starts at 1.
  46. # Vertical split count from left most window.
  47. # Horizontal split count from top most window.
  48. # When nesting pantree creates child windows addressable by 'x.y' where 'x' is the parent address and 'y' is the name of a the child window.
  49. #
  50. # In the example the addresses for frame contents are:
  51. # - d=1
  52. # - t=2.1
  53. # - x=2.2
  54. #
  55. # APIs
  56. #
  57. # pantree, procedure
  58. # pantree root spec
  59. #
  60. # root: Name of the panedwindow to create, e.g. ".my_pantree".
  61. #
  62. # spec: Pantree specification.
  63. #
  64. # Returns: Weight of spec. Used internally.
  65. #
  66. # recipe, dictionary
  67. # Key is the identifier for a recipe used in a pantree spec.
  68. # Value is a procedure taking a single window name argument.
  69. # An example of a recipe creating a button with text:
  70. # proc mybutton name { ttk::button $name -text hello }
  71. #
  72. # Deployment
  73. # It's recommended to copy pantree.tcl into your project, since:
  74. # - Pantree has no package dependencies.
  75. # - API and implementation is unlikely to change.
  76. # - Pantree can be loaded any number of times into the same source, under any namespace.
  77. #
  78. # Other
  79. #
  80. # 'Pantree' is short for 'tree of panned windows'
  81. #
  82. # A pantree can be made of a single user defined recipe
  83. #
  84. # It's perfectly fine having window weight ratios of 9/19, you just need many many '+'
  85.  
  86. # Source code
  87.  
  88. # Copyright Andreas Urban...
  89. # License MIT...
  90.  
  91. # Documentation: See README.txt
  92.  
  93. package require Tcl 8.6
  94. package require Tk
  95.  
  96. proc pantree {root spec} {
  97.     variable recipe
  98.     set subs [lassign $spec weighted_content]
  99.     set content [regsub -all \\+ $weighted_content {}]
  100.     set weight [expr {[string length $weighted_content] - [string length $content] + 1}]
  101.     if {$content == {v} || $content == {h}} {
  102.         if {[llength $subs] < 2} { error {pantree spec has too few subs} }
  103.         set address 1
  104.         set split_type [dict get {v vertical h horizontal} $content]
  105.         ttk::panedwindow $root -orient $split_type
  106.         set sub_weights {}
  107.         foreach sub $subs {
  108.             set full_address "${root}.${address}"
  109.             $root add $full_address -weight [pantree $full_address $sub]
  110.             incr address
  111.         }
  112.     } elseif {[dict exists $recipe $content]} {
  113.         [dict get $recipe $content] $root
  114.     } else {
  115.         error "content '$content' is invalid"
  116.     }
  117.     return $weight;
  118. }
  119.  
  120. set recipe [dict create]
  121.  
  122. # Test section
  123. wm geometry . 1920x1080; # 53%
  124. #wm geometry . 320x240; # 77%
  125.  
  126. proc mybutton name {
  127.     ttk::button $name -text {hello button}
  128. }
  129.  
  130. proc mylabel name {
  131.     ttk::label $name -text {hello label} -background orange
  132. }
  133.  
  134. proc mytext name {
  135.     ttk::label $name -text {hello text} -background green
  136. }
  137.  
  138. dict append recipe t mytext
  139. dict append recipe l mylabel
  140. dict append recipe b mybutton
  141.  
  142. pantree .my_pantree {h t+ {v l+ b}}
  143.  
  144. place .my_pantree -relwidth 1.0 -relheight 1.0
  145.  
  146. update
  147.  
  148. puts "left width: '[winfo width .my_pantree.1]"
  149. puts "right width: '[winfo width .my_pantree.2]"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement