Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch make-themes-reloadable Excluding Merge-Ins
This is equivalent to a diff from b21a014f8d to 619d1c3371
|
2024-08-22
| ||
| 08:59 | Merge and integrate the make-themes-reloadable branch check-in: 14d6a14000 user: alexa tags: trunk | |
| 08:58 | Go back to using an Atomic, but this time an `Atomic(Theme?)`. My earlier suspicion seems to be correct. Closed-Leaf check-in: 619d1c3371 user: alexa tags: make-themes-reloadable | |
| 08:55 | Reorganize some stuff check-in: dd1d312062 user: alexa tags: make-themes-reloadable | |
| 08:34 | Merge from trunk check-in: ef831f2480 user: alexa tags: make-themes-reloadable | |
| 08:29 | Allocate fewer strings check-in: b21a014f8d user: alexa tags: trunk | |
| 08:26 | Allocate a bit less check-in: 0cb9c4bf16 user: alexa tags: trunk | |
Changes to src/common.cr.
| ︙ | ︙ | |||
149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
Exit
StopAfterCurrent
ReloadSongConfigs
ToggleInterpolation
ToggleChorus
SeekForward
SeekBackward
end
enum ProgramState
Run
Quit
end
| > | 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
Exit
StopAfterCurrent
ReloadSongConfigs
ToggleInterpolation
ToggleChorus
SeekForward
SeekBackward
ReloadTheme
end
enum ProgramState
Run
Quit
end
|
| ︙ | ︙ |
Changes to src/config/theme.cr.
| ︙ | ︙ | |||
63 64 65 66 67 68 69 |
Config.confField(vuBarChar, String, DEF_VU_BAR_CHAR.to_s, key: "vu-bar-character")
Config.confField(vuTipChar, String, DEF_VU_TIP_CHAR.to_s, key: "vu-tip-character")
Config.confField(vuColors, Array(ThemeColor), DEF_VU_COLORS, key: "vu-colors")
Config.confField(vuClipColor, ThemeColor, DEF_VU_CLIP_COLOR, key: "vu-clip-color")
Config.confField(vuClippedChannelTime, UInt8, DEF_CLIPPED_CHANNEL_TIME, key: "vu-clipped-channel-time")
| > > > > > > | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
Config.confField(vuBarChar, String, DEF_VU_BAR_CHAR.to_s, key: "vu-bar-character")
Config.confField(vuTipChar, String, DEF_VU_TIP_CHAR.to_s, key: "vu-tip-character")
Config.confField(vuColors, Array(ThemeColor), DEF_VU_COLORS, key: "vu-colors")
Config.confField(vuClipColor, ThemeColor, DEF_VU_CLIP_COLOR, key: "vu-clip-color")
Config.confField(vuClippedChannelTime, UInt8, DEF_CLIPPED_CHANNEL_TIME, key: "vu-clipped-channel-time")
@[YAML::Field(ignore: true)]
getter name : String = ""
protected def name=(@name : String)
end
def initialize(@name = "")
end
def after_initialize
{% begin %}
raise ThemeError.new("Unsupported theme: version is too high") if @version > THEME_FORMAT_VERSION
case @version
|
| ︙ | ︙ | |||
141 142 143 144 145 146 147 |
else
raise ThemeError.new("Unsupported theme version")
end
{% end %}
end
def dup
| | | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
else
raise ThemeError.new("Unsupported theme version")
end
{% end %}
end
def dup
ret : Theme = Theme.new(@name)
ret.bgColor = self.bgColor
ret.headerColor = self.headerColor
ret.errColor = self.errColor
ret.curSongColor = self.curSongColor
ret.prevSongColor = self.prevSongColor
ret.nextSongColor1 = self.nextSongColor1
ret.nextSongColor2 = self.nextSongColor2
|
| ︙ | ︙ | |||
185 186 187 188 189 190 191 |
# Attempts to load a theme file from disk.
def self.load(resolver, aName : String|Array(String)) : Theme
name : String = case aName
in String then aName
in Array(String) then aName.sample
end
| | | > > | > > | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# Attempts to load a theme file from disk.
def self.load(resolver, aName : String|Array(String)) : Theme
name : String = case aName
in String then aName
in Array(String) then aName.sample
end
return Theme.new(DEF_THEME_NAME) if name == DEF_THEME_NAME
# All theme files use the same format: theme-<name of theme>.yaml
path = resolver.configDir.join(THEMES_DIR_NAME).join("theme-#{name}.yaml")
if File.exists?(path)
File.open(path, "r") do |file|
RemiLib.log.log("Loading user theme: #{name}")
ret = Theme.from_yaml(file)
ret.name = name
return ret
end
end
# Check system-wide
path = BENBEN_SYSTEM_DATA_DIR.join(SHORT_NAME, THEMES_DIR_NAME, "theme-#{name}.yaml")
if File.exists?(path)
File.open(path, "r") do |file|
RemiLib.log.log("Loading system-wide theme: #{name}")
ret = Theme.from_yaml(file)
ret.name = name
return ret
end
end
raise ThemeError.new("Cannot find theme: #{name}")
end
# Generates a list of all available themes.
|
| ︙ | ︙ | |||
233 234 235 236 237 238 239 |
ret[match[1]] = true
end
end
end
ret.keys
end
| > > > > > > > > > > > > | | > | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
ret[match[1]] = true
end
end
end
ret.keys
end
def self.reloadTheme : Theme?
Benben.dlog!("Attempting to reload theme config for '#{Benben.theme.name}'")
newTheme = Theme.load(Benben.resolver, Benben.theme.name)
Benben.dlog!("Loaded theme config for '#{Benben.theme.name}': #{newTheme}")
Benben.theme = newTheme
Benben.dlog!("Theme configuration reloaded and set, global theme is now #{Benben.theme}")
newTheme
rescue err : Exception
RemiLib.log.error("Could not reload theme: #{err}")
Benben.ui.queueError("Could not reload theme: #{err}")
nil
end
end
end
|
Changes to src/main.cr.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 | RemiLib.classSetonce! logFile : File? # The loaded configuration file. @@config : EphemeralConfig = EphemeralConfig.new class_property config # The loaded UI theme. | > > > | > > > > > > > > > > > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
RemiLib.classSetonce! logFile : File?
# The loaded configuration file.
@@config : EphemeralConfig = EphemeralConfig.new
class_property config
# The loaded UI theme.
@@theme : Atomic(Theme?) = Atomic(Theme?).new(nil)
#@@themeMut : Mutex = Mutex.new
def self.theme : Theme
#@@themeMut.synchronize { @@theme.not_nil! }
@@theme.get.not_nil!
end
def self.theme=(newTheme : Theme) : Theme
#@@themeMut.synchronize { @@theme = newTheme }
@@theme.set(newTheme)
newTheme
end
#class_property! theme
# Used to find the configuration file and data files.
@@resolver = RemiConf::Resolver.xdg(SHORT_NAME)
class_getter resolver
# Holds the original screen attributes.
@@originalAttrs : LibC::Termios?
|
| ︙ | ︙ |
Changes to src/uis/orig/banner.cr.
| ︙ | ︙ | |||
54 55 56 57 58 59 60 |
# Initializes offsets for the banner lines. This must be called before
# any animation is performed.
abstract def initOffsets : Nil
# Refreshes the border lines.
def refreshBorderLines(force : Bool = false) : Nil
if force
| | < | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# Initializes offsets for the banner lines. This must be called before
# any animation is performed.
abstract def initOffsets : Nil
# Refreshes the border lines.
def refreshBorderLines(force : Bool = false) : Nil
if force
color = OrigUI.theme.maxBannerLineColor - 1
SLScreen.drawHline(0, 0, color: color)
SLScreen.drawHline(0, @bottomBorderY, color: color)
else
# See if it's time to animate the border lines.
if @borderLinesTimeout < Time.local
# The animation hasn't finished. First update the lines that go
# above/below the banner. We go through all banner line colors
# twice, hence the *2 and %2 below.
if @doBorderColorChange == 0 && @borderColorOff < OrigUI.theme.numBannerLineColors * 2
color = (Theme::BANNER_LINES_START + (@borderColorOff % OrigUI.theme.numBannerLineColors))
SLScreen.drawHline(0, 0, color: color)
SLScreen.drawHline(0, @bottomBorderY, color: color)
@borderColorOff += 1
end
@doBorderColorChange = (@doBorderColorChange + 1) % 2 # Every third frame
# Did we finish the entire loop?
if @borderColorOff >= OrigUI.theme.numBannerLineColors * 2
# Reset, wait for next redraw
@borderLinesTimeout = Time.local + BANNER_LINES_TIMEOUT
@doBorderColorChange = 0
@borderColorOff = 0
end
end
end
|
| ︙ | ︙ |
Changes to src/uis/orig/orig.cr.
| ︙ | ︙ | |||
26 27 28 29 30 31 32 | module Benben alias Slang = RemiSlang alias SLScreen = RemiSlang::Screen alias SLInput = RemiSlang::Input class OrigUI < UI | > > > > > > > | > > > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
module Benben
alias Slang = RemiSlang
alias SLScreen = RemiSlang::Screen
alias SLInput = RemiSlang::Input
class OrigUI < UI
enum Mode
Playing
Paused
PlayingStopAfterCurrent
PausedStopAfterCurrent
Undefined
end
##
## Constants
##
# How often the CPU usage is refreshed, in milliseconds.
CPU_USAGE_UPDATE_FREQ = 1000
# How long a message is displayed.
MESSAGE_TIME = 5.seconds
|
| ︙ | ︙ | |||
64 65 66 67 68 69 70 |
HELP_MESSAGE_MIDI = %|
n - Next p - Prev x - Toggle Chorus a - Vol up
q - Quit e - EQ c - Toggle soft clip z - Vol down
s - Toggle stereo enhancer Space - Pause/Unpause
R - Redraw screen S - Stop after song C - Reload song configs
|.strip.lines
| | < < < < < < > > > | > > > | > > > > > > > > | > > | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
HELP_MESSAGE_MIDI = %|
n - Next p - Prev x - Toggle Chorus a - Vol up
q - Quit e - EQ c - Toggle soft clip z - Vol down
s - Toggle stereo enhancer Space - Pause/Unpause
R - Redraw screen S - Stop after song C - Reload song configs
|.strip.lines
INFO_LINE_HEADER = "Info: "
##
## Theme
##
@@theme : Atomic(Theme?) = Atomic(Theme?).new(nil)
#@@themeMut : Mutex = Mutex.new
def self.theme : Theme
@@theme.get.not_nil!
#@@themeMut.synchronize { @@theme.not_nil! }
end
def self.theme=(newTheme : Theme) : Theme
@@theme.set(newTheme)
#@@themeMut.synchronize { @@theme = newTheme }
newTheme
end
##
## Fields
##
# Current terminal attributes.
property currentAttrs : LibC::Termios?
# Mutex for thread-sensitive UI code.
getter uiLock : Mutex = Mutex.new
# Screen info
getter lastWidth : Int32 = 0
getter lastHeight : Int32 = 0
|
| ︙ | ︙ | |||
137 138 139 140 141 142 143 |
# Message handling
@messageTimeout : Time?
@errorQueue : Deque(String) = Deque(String).new(1)
@messageQueue : Deque(String) = Deque(String).new(1)
def initialize
| | | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# Message handling
@messageTimeout : Time?
@errorQueue : Deque(String) = Deque(String).new(1)
@messageQueue : Deque(String) = Deque(String).new(1)
def initialize
OrigUI.theme = Theme.new(Benben.theme)
@animations = Benben.config.uiConfig.animationsEnabled?
@banner = Banner.getBanner(@animations)
@mainAreaStartRow = @banner.size
@tagDisplay = TagDisplay.new(@mainAreaStartRow)
@playQueue = PlayQueue.new(@mainAreaStartRow + 8)
|
| ︙ | ︙ | |||
528 529 530 531 532 533 534 535 536 537 538 539 540 541 |
when 'S' then Benben.manager.sendToAllKeyChans(KeyCommand::StopAfterCurrent)
when 'C' then Benben.manager.sendToAllKeyChans(KeyCommand::ReloadSongConfigs)
when 'i' then Benben.manager.sendToAllKeyChans(KeyCommand::ToggleInterpolation)
when 'x' then Benben.manager.sendToAllKeyChans(KeyCommand::ToggleChorus)
when 'R' then Benben.manager.sendToAllKeyChans(KeyCommand::ForceRedraw)
when 'q' then Benben.manager.sendToAllKeyChans(KeyCommand::Exit)
when 'h' then Benben.manager.sendToAllKeyChans(KeyCommand::Help)
{% if flag?(:benben_manual_gc) %}
when 'G' then GC.collect
{% end %}
end
{% end %}
end
| > | 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 |
when 'S' then Benben.manager.sendToAllKeyChans(KeyCommand::StopAfterCurrent)
when 'C' then Benben.manager.sendToAllKeyChans(KeyCommand::ReloadSongConfigs)
when 'i' then Benben.manager.sendToAllKeyChans(KeyCommand::ToggleInterpolation)
when 'x' then Benben.manager.sendToAllKeyChans(KeyCommand::ToggleChorus)
when 'R' then Benben.manager.sendToAllKeyChans(KeyCommand::ForceRedraw)
when 'q' then Benben.manager.sendToAllKeyChans(KeyCommand::Exit)
when 'h' then Benben.manager.sendToAllKeyChans(KeyCommand::Help)
when 'T' then Benben.manager.sendToAllKeyChans(KeyCommand::ReloadTheme)
{% if flag?(:benben_manual_gc) %}
when 'G' then GC.collect
{% end %}
end
{% end %}
end
|
| ︙ | ︙ | |||
632 633 634 635 636 637 638 639 640 641 642 643 644 645 |
@mainVolume = newVol
vu.resetClips
updateVolume
when .reload_song_configs?
queueMessage("Reloading song configs")
Benben.config.loadSongConfigs
when .force_redraw?
Benben.dlog!("Redrawing entire screen due to request")
redrawWholeScreen
when .stop_after_current?
@stopAfterCurrent = !@stopAfterCurrent
| > > > > > > > > > > > | 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 |
@mainVolume = newVol
vu.resetClips
updateVolume
when .reload_song_configs?
queueMessage("Reloading song configs")
Benben.config.loadSongConfigs
when .reload_theme?
Benben.dlog!("UI is attempting to reload the theme")
if newTheme = Benben::Theme.reloadTheme
Benben.dlog!("Same? #{newTheme} == #{Benben.theme}")
OrigUI.theme = Theme.new(newTheme)
initColors
initVu
queueRedrawWholeScreen
queueMessage("Theme reloaded")
end
when .force_redraw?
Benben.dlog!("Redrawing entire screen due to request")
redrawWholeScreen
when .stop_after_current?
@stopAfterCurrent = !@stopAfterCurrent
|
| ︙ | ︙ |
Changes to src/uis/orig/theme.cr.
| ︙ | ︙ | |||
104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
@bgColor = getColorStr(@config.bgColor)
@fgColor = getColorStr(@config.fgColor)
@bannerColor = getColorStr(@config.bannerColor)
@pbarChar = @config.progressBarChar
@pbarSpaceChar = @config.progressBarSpaceChar
@maxBannerLineColor = BANNER_LINES_START + @config.bannerLines.size
end
# Converts *color* into a color string recognized by S-Lang.
private def getColorStr(color : Benben::ThemeColor) : String
case color
in UInt8 then "color#{color}"
in Tuple(UInt8, UInt8, UInt8)
sprintf("#%02X%02X%02X", color[0], color[1], color[2])
| > > > > > > > > > > | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
@bgColor = getColorStr(@config.bgColor)
@fgColor = getColorStr(@config.fgColor)
@bannerColor = getColorStr(@config.bannerColor)
@pbarChar = @config.progressBarChar
@pbarSpaceChar = @config.progressBarSpaceChar
@maxBannerLineColor = BANNER_LINES_START + @config.bannerLines.size
end
private def printDebugThemeInfo : Nil
Benben.dlog!("UI Theme is from: #{@config}")
Benben.dlog!("UI Theme bg color: #{@bgColor} (#{@config.bgColor})")
Benben.dlog!("UI Theme fg color: #{@fgColor} (#{@config.fgColor})")
Benben.dlog!("UI Theme banner color: #{@bannerColor} (#{@config.bannerColor})")
Benben.dlog!("UI Theme header color: #{getColorStr(@config.headerColor)} (#{@config.headerColor})")
Benben.dlog!("UI Theme error color: #{getColorStr(@config.errColor)} (#{@config.errColor})")
Benben.dlog!("UI Theme song color: #{getColorStr(@config.curSongColor)} (#{@config.curSongColor})")
end
# Converts *color* into a color string recognized by S-Lang.
private def getColorStr(color : Benben::ThemeColor) : String
case color
in UInt8 then "color#{color}"
in Tuple(UInt8, UInt8, UInt8)
sprintf("#%02X%02X%02X", color[0], color[1], color[2])
|
| ︙ | ︙ | |||
155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
@pbarColors = [] of Int32
@config.progressBarColors.each do |col|
@pbarColors << (PBAR_COLOR_START + @pbarColors.size)
SLScreen.defineColor(@pbarColors[-1], getColorStr(col), @bgColor)
end
@maxPbarColorIdx = (@pbarColors.size - 1).to_f32!
end
# Resets the progress bar color to the lowest color.
def resetBarColor : Nil
@curBarColor = 0.0f32
end
| > > | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
@pbarColors = [] of Int32
@config.progressBarColors.each do |col|
@pbarColors << (PBAR_COLOR_START + @pbarColors.size)
SLScreen.defineColor(@pbarColors[-1], getColorStr(col), @bgColor)
end
@maxPbarColorIdx = (@pbarColors.size - 1).to_f32!
printDebugThemeInfo
end
# Resets the progress bar color to the lowest color.
def resetBarColor : Nil
@curBarColor = 0.0f32
end
|
| ︙ | ︙ |