load_icons.tcl 11 KB

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