mfd.lua

--- Display for general shipboard use. Mimics a 16x52 DOS-esque terminal, because I like the aesthetic.
-- Yeah.
-- # That's **rad**.
--@classmod MFD

MFD = {}





--------------------------------------------------------------------------------
--- Initialisation methods.
-- For creating and Initialising MFD object.
-- @section Initialisation
--------------------------------------------------------------------------------

----------------------------------------
--- Creates a new intance of the MFD class.
-- @tparam string _instanceName Name for the consoles and such. Should be identical to object's unique name.
-- @tparam int _x X screen coordinate of MFD's top-left point.
-- @tparam int _y Y screen coordinate of MFD's top-left point.
-- @treturn table A new instance of the MFD class.
-- @usage myMFD = MFD:new("myMFD",423,406)
-- @todo Break off menu buttons and alert boxes into little objects.
function MFD:new( _instanceName, _x, _y )

    MFD.__index = MFD
    local self = setmetatable({}, MFD)

    self._instanceName = _instanceName

    ----------------------------------
    -- The container that holds all of the things
    self.container = Geyser.Label:new({
        name = self._instanceName..".container",
        x = _x, y = _y,
        width = 527, height = 312,
        color = "green",
    })

    self.container:setStyleSheet([[background-color: "near_black";]])

    ----------------------------------
    -- The console itself
    self.console = Geyser.MiniConsole:new({
        name = self._instanceName..".console",
        x = 5, y = 4,
        width = 520, height = 308,
        color = "black",
    }, self.container)

    self.console:setFontSize(12)
    self.console:clear()

    ----------------------------------

    self.alertBox1 = Geyser.Label:new({
        name = self._instanceName..".alertBox1",
        x = 100, y = 100,
        width = 200, height = 100,
        color = "cyan",
    }, self.container)
    --self.alertBox1:setStyleSheet([[background-color: #EEEEEE;]])

    ----------------------------------

    self.scanlines = Geyser.Label:new({
        name = self._instanceName..".scanlines",
        x = 0, y = 0,
        width = 527, height = 312,
        color = "cyan",
    }, self.container)
    self.scanlines:setStyleSheet([[background-color: #00000000;]])
    self.scanlines:setBackgroundImage(cloudDir .. [[GUI\images\MFD_scanlines.png]])
    self.scanlines:raise()
    self.scanlines:hide()

    ----------------------------------
    self.alertBox1:hide()

    self:cls()
    self:write("Done!", 24, 8)
    self:drawBorder()


    return self

end





------------------------------------------------------------------------------------------------
--- Notification methods.
-- For drawing notifications on-screen.
-- @section notification

--- Raises an on-screen notification, with multiple options for styling.
-- Raises a notification on screen, centered in lower-middle.
-- @tparam string text string The notification text to display.
-- @tparam int|float displayTime int How many seconds to show the notification. 0 leaves notification indefinitely.
-- @tparam int fontSize int The font size to use (default 12).
-- @tparam[opt] string bgColour Colour to use for alert background. Defaults to MFD's current primary if not set.
-- @tparam[opt] string fgColour Colour to use for foreground text.
-- @usage myMFD:notify("Testing...", 160, 50, 2, 12, "#004400", "yellow")
-- @todo Reduce external dependencies
--       MFD:notify(text,width,height,displayTime,fontSize,bgColour,fgColour)
function MFD:notify(text, displayTime, fontSize, bgColour, fgColour)

    if alertTimer then
        killTimer(alertTimer)
    end

    -- ! This is bad! Burn this global!
    if isNight and not bgColour then
        bgColour = bgColour or "#bd7a00"
    elseif not bgColour then
        bgColour = bgColour or "#00ff00"
    end

    local fontChoice = "Arial Rounded MT Bold"

    local MFD_width = tonumber(string.match(self.container.width, "%d+"))
    local MFD_height = tonumber(string.match(self.container.height, "%d+"))

    local alertCSS = [[
        background-color: ]]..bgColour..[[;
        font-size: ]]..tonumber(fontSize) .. [[px;
        font-family: "]]..fontChoice..[[", monospace;
        qproperty-alignment: 'AlignHCenter | AlignVCenter';
    ]]

    ----------------------------------

    -- Let's calculate how big we need the backing fill to be.
    -- We're going to do this by calculating the average dimensions of each character, at our font/size.
    local fontWidth, fontHeight = calcFontSize(fontSize, fontChoice)

    -- We'll then see how many linebreaks we have, and what the longest line is.
    local splitTable = string.split(string.gsub(text, "%<BR%>", "<br>"), "<br>") -- Make a little table out of the input line, split by linebreaks.
    local numColumns = 0 -- Number of columns in display text
    local numRows = 0 -- Number of rows in display text
    for k, v in ipairs(splitTable) do
        numColumns = math.max(string.len(v), numColumns) -- numColumns is set to the larger of the two values.
        numRows = k -- We're starting at index 1 because Lua is silly, so we can get away with this.
    end

    -- Multiply the number of rows and the number columns each by their respective character dimension.
    -- Then we have a box near-enough shaped to fit the text.
    -- Then, add some padding for ease of reading.
    local boxWidth = (fontWidth * numColumns) + 60 -- About 10px padding per side.
    local boxHeight = (fontHeight * numRows) + 20 -- About 10px padding per side.

    -- You did it! Gold star! ♥★

    ----------------------------------

    self.alertBox1:setStyleSheet(alertCSS)

    self.alertBox1:resize(boxWidth, boxHeight)
    self.alertBox1:move((MFD_width / 2) - (boxWidth / 2), ((MFD_height / 2) + (MFD_height / 4)) - (boxHeight / 2))

    self.alertBox1:raise()
    self.scanlines:raise()

    self.alertBox1:clear()
    self.alertBox1:show()
    self.alertBox1:echo(text, fgColour, tostring(fontSize))

    if displayTime > 0 then
        alertTimer = tempTimer(displayTime, function() self.alertBox1:hide() alertTimer = nil end)
    end

end





------------------------------------------------------------------------------------------------
--- Page methods.
-- Stuff for drawing full pages of text to the MFD screen in a single routine.
-- @section page

--- Writes UACS and related data to the screen.
-- @usage myMFD:writeNavPage()
-- @todo Make this thing useful at all.
function MFD:writeNavPage()

    self:cls()

    self:write("POSITION", 9, 1)
    self:write("Current easting:  ", 2, 3)
    self:write(string.format("%4d", uacs.easting), 20, 3, "turquoise")
    self:write("Current southing: ", 2, 4)
    self:write(string.format("%4d", uacs.southing), 20, 4, "turquoise")
    self:write("CEP: ", 2, 6)
    self:write(uacs.error, 7, 6, "turquoise")

    self:write("DESTINATION", 34, 1)
    self:write("Name: ", 28, 3)
    self:write("----------", 34, 3, "turquoise")
    self:write("Location: ", 28, 4)
    self:write(uacs.easting..","..uacs.southing, 38, 4, "turquoise")
    self:write("Distance: ", 28, 6)
    self:write(uacs.error, 7, 6, "turquoise")
    self:write("Bearing: ", 28, 6)
    self:write(uacs.error, 7, 6, "turquoise")

    --self:write("Current easting:  "..string.format("%4d",uacs.easting).." |", 1, 1)
    if not navUpdateResult then navUpdateResult = "..." end
    self:write("Calibration: "..navUpdateResult, 2, 12)

    self:drawBorderNav()

end





------------------------------------------------------------------------------------------------
--- Query methods.
-- Stuff for retrieving data to help us draw to the screen.
-- @section query

--- Retrieves current time of day from Time object, if present.
--  Defaults to green if no Time object.
-- @return HTML colour string, depending on Time:isNight().
-- @usage html_colour = MFD:getColour()
-- @todo Redirect to new clock object, this is stupid!
function MFD:getColour()

    if isNight then
        if isNight then
            return "orange"
        else
            return "green"
        end
    else
        return "green"
    end

end





------------------------------------------------------------------------------------------------
--- Output methods.
-- Stuff for outputting to the MFD screen.
-- @section drawing

--- Resets and erases the entire screen, and readies for writing.
-- Clears the entirety of the consoles, and fills it with spaces so write functions can successfully locate.
-- @usage myMFD:cls() myMFD:drawBorder()
function MFD:cls()
    self.console:clear()
    cecho(self._instanceName..".console", "<grey:near_black>"..string.rep(string.rep(" ", 52) .. "\n", 16))
end

-- Will overwrite any text beneath the border!
-- @tparam string colour *[optional]* Colour to draw border in, as HTML colour name.
-- @usage myMFD:drawBorder("cyan")
function MFD:drawBorder(colour)

    if not colour then colour = MFD.getColour() end

    self:write("╔══════════════════════════════════════════════════╗", 0, 0, colour)

    for i = 1, 14 do
        self:write("║", 0, i, colour)
        self:write("║", 51, i, colour)
    end

    self:write("╚══════════════════════════════════════════════════╝", 0, 15, colour)

end

--- Draws a basic border around the edges of the screen, arranged for Nav page.
-- Will overwrite any text beneath the border!
-- @tparam string colour *[optional]* Colour to draw border in, as HTML colour name.
-- @usage myMFD:drawBorderNav("forest_green")
function MFD:drawBorderNav(colour)

    self:write("╔════════════════════════╦╦════════════════════════╗", 0, 0, colour)

    self:write("║", 0, 1, colour)
    self:write("║", 25, 1, colour)
    self:write("║", 26, 1, colour)
    self:write("║", 51, 1, colour)

    self:write("╠════════════════════════╣╠════════════════════════╣", 0, 2, colour)

    for i = 3, 9 do
        self:write("║", 0, i, colour)
        self:write("║", 25, i, colour)
        self:write("║", 26, i, colour)
        self:write("║", 51, i, colour)
    end

    self:write("╠════════════════════════╩╩════════════════════════╣", 0, 10, colour)

    for i = 11, 14 do
        self:write("║", 0, i, colour)
        self:write("║", 51, i, colour)
    end

    self:write("╚══════════════════════════════════════════════════╝", 0, 15, colour)

end

--- Places an underscore at the given X,Y with optional blinking.
-- Purely aesthetic, serves no functional purpose.
-- @param inputX* ***num*** X coordinate of cursor position.
-- @param inputY* ***num*** Y coordinate of cursor position.
-- @param doBlink* ***bool*** Blink cursor at the rate of cursorRate if true.
-- @todo Actually make this do anything...
-- @usage myMFD:setCursor(25,12,true)
function MFD:setCursor(inputX, inputY, doBlink)

    --moveCursor("")

end

--- Writes text to the MFD.
--
-- Writes text of arbitrary length, position, and colour to the MFD. Overwrites existing text for the length of the string.
-- @tparam string writeText The text to be written to the MFD.
-- @tparam int writeX X position of cursor, where text will be inserted. 0-51
-- @tparam int writeY Y position of cursor, where text will be inserted. 0-15
-- @tparam[opt = "aaa"] string fgColour Colour to be used for the text foreground colour, as HTML colour name.
-- @tparam[opt = "aaa"] string bgColour Colour to be used for the text background colour, as HTML colour name.
-- @treturn bool True, if write successful.
-- @usage myMFD:write("Beginning Δcal routine...", 2, 2, "green", "dim_grey")
function MFD:write(writeText, writeX, writeY, fgColour, bgColour)

    local fgColour = fgColour or self:getColour()
    local bgColour = bgColour or "near_black"
    local printColour = "<"..fgColour..":"..bgColour..">"
    local writeTextLength = utf8.len(writeText)

    writeTextLength = math.max(writeTextLength, 0)

    if moveCursor(self._instanceName..".console", writeX, writeY) then
        selectSection(self._instanceName..".console", writeX, writeTextLength)
        creplace(self._instanceName..".console", printColour..writeText)
        return true
    end

    return false

end
generated by LDoc 1.4.3 Last updated 2021-01-24 20:08:44