_osd_widgets.tcl 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. namespace eval osd_widgets {
  2. set help_text \
  3. {The command 'osd_widgets::msx_init' takes one parameter, this parameter will be used as
  4. our base layer which will be scaled according to the MSX resultion adjusted for
  5. 'set adjust', 'scale factor' and 'horizontal_stretch'.
  6. All these compensation factors ('set adjust', ...) can change over time. So it
  7. is needed to 'regularly' (e.g. in a 'after frame' callback) re-adjust the msx
  8. layer. This can be done with the 'osd_widgets::msx_update' proc.
  9. Example: osd_widgets::msx_init baselayer
  10. osd create rectangle baselayer.box -x 10 -y 10 -h 16 -w 16 -rgb 0xffffff
  11. ...
  12. osd_widgets::msx_update baselayer
  13. This will display a white 16x16 box at MSX location x,y == 10,10.}
  14. set_help_text osd_widgets::msx_init $help_text
  15. set_help_text osd_widgets::msx_update $help_text
  16. proc msx_init {name} {
  17. osd create rectangle $name -scaled true -alpha 0
  18. msx_update $name
  19. }
  20. proc msx_update {name} {
  21. # compensate for horizontal-stretch and set-adjust
  22. set hstretch $::horizontal_stretch
  23. set xsize [expr {320.0 / $hstretch}]
  24. set xoffset [expr {($hstretch - 256) / 2 * $xsize}]
  25. set ysize 1
  26. set lines [expr {([vdpreg 9] & 128) ? 212 : 192}]
  27. set yoffset [expr {(240 - $lines) / 2 * $ysize}]
  28. set adjreg [vdpreg 18]
  29. set hadj [expr {(($adjreg & 15) ^ 7) - 7}]
  30. set vadj [expr {(($adjreg >> 4) ^ 7) - 7}]
  31. set xoffset [expr {$xoffset + $xsize * $hadj}]
  32. set yoffset [expr {$yoffset + $ysize * $vadj}]
  33. osd configure $name -x $xoffset -y $yoffset -w $xsize -h $ysize
  34. }
  35. set_help_text create_power_bar\
  36. {The command 'osd_widgets::create_power_bar' supports the following parameters:
  37. -name == Name of the power bar
  38. -w == Width of the power bar (in pixels)
  39. -h == Height of the power bar
  40. -barcolor == Powerbar color
  41. -background == When power declines this color is shown
  42. -edgecolor == This is the edge color (try white when I doubt which color to use)
  43. Colors must have the following hexadecimal format 0xRRGGBBAA.
  44. The power bar is initially created outside the viewable area, so we need to invoke
  45. the 'update_power_bar' command to make it visible. Use 'hide_power_bar' to
  46. remove it again.}
  47. set_help_text update_power_bar\
  48. {The command 'update_power_bar' uses the following parameters:
  49. -name == Name of the power bar
  50. -x == vertical position of the power bar
  51. -y == horizontal position of the power bar
  52. -power == fill rate of the power bar in decimal percentages (10% == 0.1)
  53. -text == text to be printed above the power bar}
  54. proc create_power_bar {name w h barcolor background edgecolor} {
  55. osd create rectangle $name -rely 999 -relw $w -relh $h -rgba $background
  56. osd create rectangle $name.top -x -1 -y -1 -relw 1 -w 2 -h 1 -rgba $edgecolor
  57. osd create rectangle $name.bottom -x -1 -rely 1 -relw 1 -w 2 -h 1 -rgba $edgecolor
  58. osd create rectangle $name.left -x -1 -w 1 -relh 1 -rgba $edgecolor
  59. osd create rectangle $name.right -relx 1 -w 1 -relh 1 -rgba $edgecolor
  60. osd create rectangle $name.bar -relw 1 -relh 1 -rgba $barcolor -z 18
  61. osd create text $name.text -x 0 -y -6 -size 4 -rgba $edgecolor
  62. }
  63. proc update_power_bar {name x y power text} {
  64. if {$power > 1.0} {set power 1.0}
  65. if {$power < 0.0} {set power 0.0}
  66. osd configure $name -relx $x -rely $y
  67. osd configure $name.bar -relw $power
  68. osd configure $name.text -text "$text"
  69. }
  70. proc hide_power_bar {name} {
  71. osd configure $name -rely 999
  72. }
  73. set_help_text toggle_fps \
  74. {Enable/disable a frames per second indicator in the top-left corner of the screen.}
  75. variable fps_after
  76. proc toggle_fps {} {
  77. variable fps_after
  78. if {[info exists fps_after]} {
  79. after cancel $osd_widgets::fps_after
  80. osd destroy fps_viewer
  81. unset fps_after
  82. } else {
  83. osd create rectangle fps_viewer -x 5 -y 5 -z 0 -w 63 -h 20 -rgba 0x00000080
  84. osd create text fps_viewer.text -x 5 -y 3 -z 1 -rgba 0xffffffff
  85. proc fps_refresh {} {
  86. variable fps_after
  87. osd configure fps_viewer.text -text [format "%2.1fFPS" [openmsx_info fps]]
  88. set fps_after [after realtime .5 [namespace code fps_refresh]]
  89. }
  90. fps_refresh
  91. }
  92. return ""
  93. }
  94. set_help_text osd_widgets::text_box\
  95. {The 'osd_widgets::text_box' widget supports the same properties as a 'rectangle' widget with the following additions:
  96. -text: defines the text to be printed, can have multiple lines (separated by 'new line' characters).
  97. -textcolor: defines the color of the text
  98. -textsize: defines the font size of the text}
  99. variable widget_handlers
  100. variable opaque_duration 2.5
  101. variable fade_out_duration 2.5
  102. variable fade_in_duration 0.4
  103. proc text_box {name args} {
  104. variable widget_handlers
  105. variable opaque_duration
  106. # Default values in case nothing is given
  107. set txt_color 0xffffffff
  108. set txt_size 6
  109. # Process arguments
  110. set rect_props [list]
  111. foreach {key val} $args {
  112. switch -- $key {
  113. -text {set message $val}
  114. -textrgba {set txt_color $val}
  115. -textsize {set txt_size $val}
  116. default {lappend rect_props $key $val}
  117. }
  118. }
  119. if {$message eq ""} return
  120. # For handheld devices set minimal text size to 9
  121. # TODO: does this belong here or at some higher level?
  122. if {($::scale_factor == 1) && ($txt_size < 9)} {
  123. set txt_size 9
  124. }
  125. # Destroy widget (if it already existed)
  126. osd destroy $name
  127. # Guess height of rectangle
  128. osd create rectangle $name {*}$rect_props -h [expr {4 + $txt_size}]
  129. osd create text $name.text -x 2 -y 2 -size $txt_size -rgb $txt_color \
  130. -text $message -wrap word -wraprelw 1.0 -wrapw -4
  131. # Adjust height of rectangle to actual text height (depends on newlines
  132. # and text wrapping).
  133. catch {
  134. lassign [osd info $name.text -query-size] x y
  135. osd configure $name -h [expr {4 + $y}]
  136. }
  137. # if the widget was still active, kill old click/opaque handler
  138. if {[info exists widget_handlers($name)]} {
  139. lassign $widget_handlers($name) click opaque
  140. after cancel $click
  141. after cancel $opaque
  142. }
  143. set click [after "mouse button1 down" "osd_widgets::click_handler $name"]
  144. set opaque [after realtime $opaque_duration "osd_widgets::timer_handler $name"]
  145. set widget_handlers($name) [list $click $opaque]
  146. return ""
  147. }
  148. proc click_handler {name} {
  149. if {[osd::is_cursor_in $name]} {
  150. kill_widget $name
  151. }
  152. return ""
  153. }
  154. proc kill_widget {name} {
  155. variable widget_handlers
  156. lassign $widget_handlers($name) click opaque
  157. after cancel $click
  158. after cancel $opaque
  159. unset widget_handlers($name)
  160. osd destroy $name
  161. }
  162. proc timer_handler {name} {
  163. variable widget_handlers
  164. variable opaque_duration
  165. variable fade_out_duration
  166. variable fade_in_duration
  167. # clicking it might have killed it already
  168. if {![osd exists $name]} {
  169. return
  170. }
  171. # if already faded out... don't poll again and clean up
  172. if {[osd info $name -fadeCurrent] == 0.0} {
  173. kill_widget $name
  174. return
  175. }
  176. # If the cursor is over the widget, we fade-in fast and leave the widget
  177. # opaque for some time (= don't poll for some longer time). Otherwise
  178. # we fade-out slow and more quickly poll the cursor position.
  179. lassign $widget_handlers($name) click opaque
  180. if {[osd::is_cursor_in $name]} {
  181. osd configure $name -fadePeriod $fade_in_duration -fadeTarget 1.0
  182. set opaque [after realtime $opaque_duration "osd_widgets::timer_handler $name"]
  183. } else {
  184. osd configure $name -fadePeriod $fade_out_duration -fadeTarget 0.0
  185. set opaque [after realtime 0.25 "osd_widgets::timer_handler $name"]
  186. }
  187. set widget_handlers($name) [list $click $opaque]
  188. }
  189. proc volume_control {incr_val} {
  190. if {![osd exists volume]} {
  191. osd create rectangle volume -x 0 -y 0 -h 32 -w 320 -rgba 0x000000a0 -scaled true
  192. osd create rectangle volume.bar -x 16 -y 16 -h 8 -w 290 -rgba 0x000000c0 -borderrgba 0xffffffff -bordersize 1
  193. osd create rectangle volume.bar.meter -x 1 -y 1 -h 6 -w 288 -rgba "0x00aa33e8 0x00dd66e8 0x00cc55e8 0x00ff77e8"
  194. osd create text volume.text -x 16 -y 3 -size 10 -rgba 0xffffffff
  195. }
  196. incr ::master_volume $incr_val
  197. if {$::master_volume == 0} {set ::mute on} else {set ::mute off}
  198. osd configure volume.bar.meter -w [expr {($::master_volume / 100.00) * 288}]
  199. osd configure volume.text -text [format "Volume: %03d" $::master_volume]
  200. osd configure volume -fadePeriod 5 -fadeTarget 0 -fadeCurrent 1
  201. }
  202. # only export stuff that is useful in other scripts or for the console user
  203. namespace export toggle_fps
  204. namespace export msx_init
  205. namespace export msx_update
  206. namespace export box
  207. namespace export text_box
  208. namespace export create_power_bar
  209. namespace export update_power_bar
  210. namespace export hide_power_bar
  211. namespace export volume_control
  212. };# namespace osd_widgets
  213. # only import stuff to global that is useful outside of scripts (i.e. for the console user)
  214. namespace import osd_widgets::toggle_fps
  215. namespace import osd_widgets::volume_control