load_icons.tcl 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. namespace eval load_icons {
  2. set_help_text load_icons \
  3. {Load a different set of OSD icons.
  4. usage: load_icons [<name> [<position>]]
  5. <name> is the name of a directory (share/skins/<name>) that
  6. contains the icon images. If this parameter is not given,
  7. a list of available skins will be printed.
  8. <position> can be one of the following 'bottom', 'top', 'left'
  9. or 'right'. The default depends on the selected skin.
  10. example: load_icons set1 top
  11. }
  12. set_tabcompletion_proc load_icons [namespace code tab_load_icons]
  13. proc tab_load_icons {args} {
  14. set num [llength $args]
  15. if {$num == 2} {
  16. set r1 [glob -nocomplain -tails -type d -directory $::env(OPENMSX_USER_DATA)/skins *]
  17. set r2 [glob -nocomplain -tails -type d -directory $::env(OPENMSX_SYSTEM_DATA)/skins *]
  18. concat $r1 $r2
  19. } elseif {$num == 3} {
  20. list "top" "bottom" "left" "right"
  21. }
  22. }
  23. variable icon_list
  24. variable last_change
  25. variable current_osd_leds_set
  26. variable current_osd_leds_pos
  27. variable current_fade_delay_active
  28. variable current_fade_delay_non_active
  29. variable fade_id
  30. proc trace_icon_status {name1 name2 op} {
  31. variable last_change
  32. global $name1
  33. set icon [string trimleft $name1 ":"]
  34. set now [openmsx_info realtime]
  35. set last_change($icon) $now
  36. redraw_osd_icons $icon $now
  37. }
  38. proc redraw_osd_icons {icon now} {
  39. variable last_change
  40. variable current_fade_delay_active
  41. variable current_fade_delay_non_active
  42. variable fade_id
  43. global $icon
  44. # handle 'unset' variables (when current msx machine got deleted)
  45. if {[catch {set value [set $icon]}]} {set value false}
  46. if {$value} {
  47. set widget osd_icons.${icon}_on
  48. set widget2 osd_icons.${icon}_off
  49. set fade_delay $current_fade_delay_active($icon)
  50. } else {
  51. set widget osd_icons.${icon}_off
  52. set widget2 osd_icons.${icon}_on
  53. set fade_delay $current_fade_delay_non_active($icon)
  54. }
  55. osd configure $widget2 -fadeCurrent 0 -fadeTarget 0
  56. catch {after cancel $fade_id($icon)}
  57. if {$fade_delay == 0} {
  58. # remains permanently visible (no fading)
  59. osd configure $widget -fadeCurrent 1 -fadeTarget 1
  60. } else {
  61. set target [expr {$last_change($icon) + $fade_delay}] ;# at this time we start fading out
  62. set remaining [expr {$target - $now}] ;# time remaining from now to target
  63. set cmd "osd configure $widget -fadeTarget 0"
  64. if {$remaining > 0} {
  65. # before target time, no fading yet (still fully visible)
  66. osd configure $widget -fadeCurrent 1 -fadeTarget 1
  67. # schedule fade-out in the future
  68. set fade_id($icon) [after realtime $remaining $cmd]
  69. } else {
  70. # already after target, fade-out now
  71. eval $cmd
  72. }
  73. }
  74. }
  75. proc load_icons {{set_name "-show"} {position_param "default"}} {
  76. variable icon_list
  77. variable current_osd_leds_set
  78. variable current_osd_leds_pos
  79. variable current_fade_delay_active
  80. variable current_fade_delay_non_active
  81. if {$set_name eq "-show"} {
  82. # Show list of available skins
  83. set user_skins \
  84. [glob -tails -types d -directory $::env(OPENMSX_USER_DATA)/skins *]
  85. set system_skins \
  86. [glob -tails -types d -directory $::env(OPENMSX_SYSTEM_DATA)/skins *]
  87. return [lsort -unique [concat $user_skins $system_skins]]
  88. }
  89. # Check skin directory
  90. # All files belonging to this skin must come from this directory.
  91. # So we don't allow mixing individual files for one skin from the
  92. # system and from the user directory. Though fallback images are
  93. # again searched in both system and user dirs.
  94. set skin_set_dir [data_file "skins/$set_name"]
  95. if {![file isdirectory $skin_set_dir]} {
  96. error "No such icon skin: $set_name"
  97. }
  98. # Check position
  99. if {$position_param ni [list "top" "bottom" "left" "right" "default"]} {
  100. error "Invalid position: $position_param"
  101. }
  102. # Defaut icon positions
  103. set xbase 0
  104. set ybase 0
  105. set xwidth 50
  106. set yheight 30
  107. set xspacing 60
  108. set yspacing 35
  109. set horizontal 1
  110. set fade_delay 5
  111. set fade_duration 5
  112. set scale 2
  113. set position $position_param
  114. # but allow to override these values by the skin script
  115. set icons $icon_list ;# the 'none' skin needs this
  116. set script $skin_set_dir/skin.tcl
  117. if {[file isfile $script]} {source $script}
  118. set invscale [expr {1.0 / $scale}]
  119. set xbase [expr {$xbase * $invscale}]
  120. set ybase [expr {$ybase * $invscale}]
  121. set xwidth [expr {$xwidth * $invscale}]
  122. set yheight [expr {$yheight * $invscale}]
  123. set xspacing [expr {$xspacing * $invscale}]
  124. set yspacing [expr {$yspacing * $invscale}]
  125. # change according to <position> parameter
  126. if {$position eq "default"} {
  127. # script didn't set a default, so we choose a "default default"
  128. set position "bottom"
  129. }
  130. if {$position eq "left"} {
  131. set horizontal 0
  132. } elseif {$position eq "right"} {
  133. set horizontal 0
  134. set xbase [expr {320 - $xwidth}]
  135. } elseif {$position eq "bottom"} {
  136. set ybase [expr {240 - $yheight}]
  137. }
  138. set vertical [expr {!$horizontal}]
  139. proc __try_dirs {skin_set_dir file fallback} {
  140. # don't touch already resolved pathnames
  141. if {[file normalize $file] eq $file} {return $file}
  142. # first look in specified skin-set directory
  143. set f1 [file normalize $skin_set_dir/$file]
  144. if {[file isfile $f1]} {return $f1}
  145. # look for the falback image in the skin directory
  146. set f2 [file normalize $skin_set_dir/$fallback]
  147. if {[file isfile $f2]} {return $f2}
  148. # if it's not there look in the root skin directory
  149. # (system or user directory)
  150. set f3 [file normalize [data_file "skins/$file"]]
  151. if {[file isfile $f3]} {return $f3}
  152. # still not found, look for the fallback image in system and
  153. # user root skin dir
  154. set f4 [file normalize [data_file "skins/$fallback"]]
  155. if {[file isfile $f4]} {return $f4}
  156. return ""
  157. }
  158. # Calculate default parameter values ...
  159. for {set i 0} {$i < [llength $icons]} {incr i} {
  160. set icon [lindex $icons $i]
  161. set xcoord($icon) [expr {$i * $xspacing * $horizontal}]
  162. set ycoord($icon) [expr {$i * $yspacing * $vertical}]
  163. set fade_delay_active($icon) $fade_delay
  164. set fade_delay_non_active($icon) $fade_delay
  165. set fade_duration_active($icon) $fade_duration
  166. set fade_duration_non_active($icon) $fade_duration
  167. switch -glob $icon {
  168. led_* {
  169. set base [string tolower [string range $icon 4 end]]
  170. set image_on "${base}-on.png"
  171. set image_off "${base}-off.png"
  172. set fallback_on "led-on.png"
  173. set fallback_off "led-off.png"
  174. }
  175. throttle {
  176. set image_on ""
  177. set image_off "${icon}.png"
  178. set fallback_on ""
  179. set fallback_off ""
  180. set current_fade_delay_non_active($icon) 0
  181. }
  182. default {
  183. set image_on "${icon}.png"
  184. set image_off ""
  185. set fallback_on ""
  186. set fallback_off ""
  187. set fade_delay_active($icon) 0
  188. }
  189. }
  190. set active_image($icon) [__try_dirs $skin_set_dir $image_on $fallback_on ]
  191. set non_active_image($icon) [__try_dirs $skin_set_dir $image_off $fallback_off]
  192. }
  193. # ... but allow to override these calculated values (again) by the skin script
  194. if {[file isfile $script]} {source $script}
  195. # Note: The actual width and height are irrelevant since this is only
  196. # an anchor to relatively position the icons to, but by checking
  197. # for a zero or non-zero value the orientation can be queried.
  198. osd configure osd_icons -x $xbase -y $ybase -w $horizontal -h $vertical
  199. foreach icon $icon_list {
  200. osd configure osd_icons.${icon}_on \
  201. -x $xcoord($icon) \
  202. -y $ycoord($icon) \
  203. -fadePeriod $fade_duration_active($icon) \
  204. -image [__try_dirs $skin_set_dir $active_image($icon) ""] \
  205. -scale $invscale
  206. osd configure osd_icons.${icon}_off \
  207. -x $xcoord($icon) \
  208. -y $ycoord($icon) \
  209. -fadePeriod $fade_duration_non_active($icon) \
  210. -image [__try_dirs $skin_set_dir $non_active_image($icon) ""] \
  211. -scale $invscale
  212. }
  213. # Also try to load "frame.png"
  214. osd destroy osd_frame
  215. set framefile "$skin_set_dir/frame.png"
  216. if {[file isfile $framefile]} {
  217. osd create rectangle osd_frame -z 0 -x 0 -y 0 -w 320 -h 240 \
  218. -scaled true -image $framefile
  219. }
  220. # If successful, store in settings (order of assignments is important!)
  221. set current_osd_leds_set $set_name
  222. set ::osd_leds_set $set_name
  223. set current_osd_leds_pos $position_param
  224. set ::osd_leds_pos $position_param
  225. foreach icon $icon_list {
  226. set current_fade_delay_active($icon) $fade_delay_active($icon)
  227. set current_fade_delay_non_active($icon) $fade_delay_non_active($icon)
  228. }
  229. # Force redrawing of all icons
  230. set now [openmsx_info realtime]
  231. foreach icon $icon_list {
  232. redraw_osd_icons $icon $now
  233. }
  234. return ""
  235. }
  236. proc trace_osd_icon_vars {name1 name2 op} {
  237. variable current_osd_leds_set
  238. variable current_osd_leds_pos
  239. # avoid executing load_icons multiple times
  240. # (because of the assignments to the settings in that proc)
  241. if {($::osd_leds_set eq $current_osd_leds_set) &&
  242. ($::osd_leds_pos eq $current_osd_leds_pos)} {
  243. return
  244. }
  245. load_icons $::osd_leds_set $::osd_leds_pos
  246. }
  247. proc machine_switch_osd_icons {} {
  248. variable icon_list
  249. set now [openmsx_info realtime]
  250. foreach icon $icon_list {
  251. trace remove variable ::$icon "write unset" [namespace code trace_icon_status]
  252. trace add variable ::$icon "write unset" [namespace code trace_icon_status]
  253. redraw_osd_icons $icon $now
  254. }
  255. after machine_switch [namespace code machine_switch_osd_icons]
  256. }
  257. # Available icons. Icons are also drawn in this order (by default)
  258. set icon_list [list "led_power" "led_caps" "led_kana" "led_pause" "led_turbo" "led_FDD" \
  259. "pause" "throttle" "mute" "breaked"]
  260. # create OSD widgets
  261. osd create rectangle osd_icons -scaled true -alpha 0 -z 1
  262. set now [openmsx_info realtime]
  263. foreach icon $icon_list {
  264. variable last_change
  265. osd create rectangle osd_icons.${icon}_on -fadeCurrent 0 -fadeTarget 0 -fadePeriod 5.0
  266. osd create rectangle osd_icons.${icon}_off -fadeCurrent 0 -fadeTarget 0 -fadePeriod 5.0
  267. trace add variable ::$icon "write unset" load_icons::trace_icon_status
  268. set last_change($icon) $now
  269. }
  270. namespace export load_icons
  271. } ;# namespace load_icons
  272. namespace import load_icons::*
  273. # Restore settings from previous session
  274. # default is set1, but if only scale_factor 1 is supported, use handheld
  275. if {[lindex [openmsx_info setting scale_factor] 2 1] == 1} {
  276. user_setting create string osd_leds_set "Name of the OSD icon set" "handheld"
  277. } else {
  278. user_setting create string osd_leds_set "Name of the OSD icon set" "set1"
  279. }
  280. user_setting create string osd_leds_pos "Position of the OSD icons" "default"
  281. set load_icons::current_osd_leds_set $osd_leds_set
  282. set load_icons::current_osd_leds_pos $osd_leds_pos
  283. trace add variable osd_leds_set write load_icons::trace_osd_icon_vars
  284. trace add variable osd_leds_pos write load_icons::trace_osd_icon_vars
  285. after machine_switch load_icons::machine_switch_osd_icons
  286. load_icons $osd_leds_set $osd_leds_pos