Files
itgmania212121/Themes/_fallback/BGAnimations/ScreenSystemLayer error.lua
T

222 lines
6.7 KiB
Lua

-- If you are a common themer, DO NOT INCLUDE THIS FILE IN YOUR THEME.
-- This layer is purely for error reporting, so that you can see errors on screen easily while running stepmania.
-- If you include this file in your theme, you will not benefit from any improvements in error reporting.
-- If you want a different background behind the errors, then include "ScreenSystemLayer errorbg.lua" in your theme.
-- If you want to adjust how long errors stay on screen for, call the "SetErrorMessageTime" function. (see usage notes in comments above that function)
-- Minor text formatting functions from Kyzentun.
-- TODO: Figure out why BitmapText:maxwidth doesn't do what I want.
local function width_limit_text(text, limit, natural_zoom)
natural_zoom= natural_zoom or 1
if text:GetWidth() * natural_zoom > limit then
text:zoomx(limit / text:GetWidth())
else
text:zoomx(natural_zoom)
end
end
local function width_clip_text(text, limit)
local full_text= text:GetText()
local fits= text:GetZoomedWidth() <= limit
local prev_max= #full_text - 1
local prev_min= 0
if not fits then
while prev_max - prev_min > 1 do
local new_max= math.round((prev_max + prev_min) / 2)
text:settext(full_text:sub(1, 1+new_max))
if text:GetZoomedWidth() <= limit then
prev_min= new_max
else
prev_max= new_max
end
end
text:settext(full_text:sub(1, 1+prev_min))
end
end
local function width_clip_limit_text(text, limit, natural_zoom)
natural_zoom= natural_zoom or text:GetZoomY()
local text_width= text:GetWidth() * natural_zoom
if text_width > limit * 2 then
text:zoomx(natural_zoom * .5)
width_clip_text(text, limit)
else
width_limit_text(text, limit, natural_zoom)
end
end
local text_actors= {}
local line_height= 12 -- A good line height for Common Normal at .5 zoom.
local line_width= SCREEN_WIDTH - 20
local next_message_actor= 1
local show_requested= false
local min_message_time= {show= 1, hide= .03125}
local default_message_time= {show= 4, hide= .125}
local message_time= {}
for k, v in pairs(default_message_time) do
message_time[k]= v
end
-- Example usage:
-- "SetErrorMessageTime('show' 5)" sets errors to show for 5 seconds before beginning to hide.
-- "SetErrorMessageTime('hide' .5)" sets errors to hide one error every .5 seconds after the show time has passed.
function SetErrorMessageTime(which, t)
if not min_message_time[which] then
MESSAGEMAN:Broadcast(
"ScriptError", {
Message= "Attempted to set invalid overlay message time field: " ..
tostring(which)})
return
end
if t < min_message_time[which] then
MESSAGEMAN:Broadcast(
"ScriptError", {
Message= "Attempted to set overlay message " .. which ..
" time to below minimum of " .. min_message_time[which] .. "."})
return
end
message_time[which]= t
end
function GetErrorMessageTime(which)
return message_time[which]
end
function GetErrorMessageTimeMin(which)
return min_message_time[which]
end
function GetErrorMessageTimeDefault(which)
return default_message_time[which]
end
local frame_args= {
Name="Error frame",
InitCommand= function(self)
self:y(-SCREEN_HEIGHT)
end,
ScriptErrorMessageCommand = function(self, params)
show_requested= false
self:stoptweening()
self:visible(true)
local covered_height= math.min(line_height * next_message_actor, SCREEN_HEIGHT)
self:y(-SCREEN_HEIGHT + covered_height)
self:sleep(message_time.show)
self:queuecommand("DecNextActor")
-- Shift the text on all the actors being shown up by one.
for i= next_message_actor, 1, -1 do
if text_actors[i] then
text_actors[i]:visible(true)
if i > 1 and text_actors[i-1] then
text_actors[i]:settext(text_actors[i-1]:GetText())
else
-- Someone long ago decided that it was a good idea for "::" to be
-- a synonym for "\n", so that strings in metrics could have line
-- breaks.
-- So replace "::" with ":" so we don't have unwanted line breaks.
text_actors[i]:settext(params.Message:gsub("::", ":"))
end
width_clip_limit_text(text_actors[i], line_width)
end
end
if next_message_actor <= #text_actors then
next_message_actor= next_message_actor + 1
end
end,
ToggleErrorsMessageCommand= function(self, params)
if show_requested then
self:playcommand("HideErrors")
else
self:playcommand("ShowErrors")
end
end,
ShowErrorsMessageCommand= function(self, params)
show_requested= true
for i, mactor in ipairs(text_actors) do
if mactor:GetText() ~= "" then
mactor:visible(true)
next_message_actor= next_message_actor + 1
end
end
next_message_actor= next_message_actor - 1
local covered_height= math.min(line_height * next_message_actor, SCREEN_HEIGHT)
self:stoptweening()
self:visible(true)
self:linear(message_time.hide)
self:y(-SCREEN_HEIGHT + covered_height)
end,
HideErrorsMessageCommand= function(self, params)
if not show_requested then return end
show_requested= false
self:stoptweening()
next_message_actor= 1
self:linear(message_time.hide)
self:y(-SCREEN_HEIGHT)
self:queuecommand("HideText")
end,
ClearErrorsMessageCommand= function(self, params)
-- This is so that someone using ShowErrorsMessageCommand can clear ones
-- they've dealt with.
-- Only allow clearing errors that we have scrolled off screen.
for i, mactor in ipairs(text_actors) do
if not mactor:GetVisible() then
mactor:settext("")
end
end
end,
DecNextActorCommand= function(self)
self:linear(message_time.hide)
self:y(self:GetY()-line_height)
if text_actors[next_message_actor] then
text_actors[next_message_actor]:visible(false)
end
next_message_actor= next_message_actor - 1
if next_message_actor > 1 then
self:queuecommand("DecNextActor")
else
self:queuecommand("Off")
end
end,
HideTextCommand= function(self)
for i, mactor in ipairs(text_actors) do
mactor:visible(false)
end
end,
OffCommand= cmd(visible,false),
Def.Quad {
Name= "errorbg",
InitCommand= function(self)
self:setsize(SCREEN_WIDTH, SCREEN_HEIGHT)
self:horizalign(left)
self:vertalign(top)
self:diffuse(color("0,0,0,0"))
self:diffusealpha(.85)
end,
}
}
-- Create enough text actors that we can fill the screen.
local num_text= SCREEN_HEIGHT / line_height
for i= 1, num_text do
frame_args[#frame_args+1]= LoadFont("Common","Normal") .. {
Name="Text" .. i,
InitCommand= function(self)
-- Put them in the list in reverse order so the ones at the bottom of the screen are used first.
text_actors[num_text-i+1]= self
self:horizalign(left)
self:vertalign(top)
self:x(SCREEN_LEFT + 10)
self:y(SCREEN_TOP + (line_height * (i-1)) + 2)
self:shadowlength(1)
self:zoom(.5)
self:visible(false)
end,
OffCommand= cmd(visible,false),
}
end
Trace("Loaded error layer.")
return Def.ActorFrame(frame_args)