-- lx-bundle:true

-- This file is part of Lx and Qui, created by Liqube <www.liqube.com>
-- Copyright Liqube Audio. All rights reserved.
-- Lx Interim License. See LICENSE for details.

--- Provide a reusable Lua-owned visual Panel Control
-- A Panel paints a surface but never becomes a Pane, Layout, or child-Control container
-- @module qui.panel

local qui = require("qui")
local colors = require("qui.colors")
local metrics = require("qui.metrics")
local theme = require("qui.theme")

local Panel = {}

--- Keep one Panel measurement inside a non-negative DIP range
-- @param value number|nil requested value
-- @param name string readable option name
-- @return number|nil value checked whole-DIP value
local function optional_dip(value, name)
	if value == nil then
		return nil
	end
	assert(type(value) == "number" and value >= 0 and value < math.huge,
		name .. " must be a non-negative number")

	return math.floor(value + 0.5)
end

--- Select the shared Panel surface color used by every ordinary instance
-- @param self table Panel control
-- @param type string requested visual type
-- @param flags table current Panel conditions
-- @return string|nil color_identifier
function Panel.default_color(self, type, flags)
	if type == "background" then
		return colors.panel_bg
	elseif type == "frame" then
		return colors.panel_frame
	end

	return nil
end

--- Create one non-interactive visual surface for use inside 'qui.pane.controls'
-- Place the Panel before ordinary Controls when it should appear behind them
-- @param options table size, frame width, color handling, and placement
-- @return table control unrestricted Lua Control declaration
function Panel.new(options)
	assert(type(options) == "table", "Panel expects a table")
	assert(options.on_color == nil or type(options.on_color) == "function", "Panel on_color must be a function")
	assert(options.default_color == nil, "Panel default_color is fixed; use on_color for dynamic changes")

	local control = options
	control.width = optional_dip(control.width, "Panel width")
	control.height = optional_dip(control.height, "Panel height")
	control.frame_width = optional_dip(control.frame_width, "Panel frame_width") or
		theme.resolve_metric(metrics.panel_frame_width)
	control.enabled = control.enabled ~= false
	control.focusable = false
	control.accepts_pointer = false
	control.default_color = Panel.default_color

	--- Measure only an explicitly requested size because placement normally stretches the Panel
	function control:measure(control_canvas, minimum_width, minimum_height, maximum_width, maximum_height)
		local natural_width = self.width or 0
		local natural_height = self.height or 0
		local width = math.max(minimum_width, math.min(natural_width, maximum_width))
		local height = math.max(minimum_height, math.min(natural_height, maximum_height))

		return width, height
	end

	--- Draw one complete surface and its optional inward frame
	function control:draw(control_canvas)
		local width, height = control_canvas:size()
		local flags = { grayed = not self.enabled }
		local background = self:get_color("background", flags)

		control_canvas:fill_rect(0, 0, width, height, background)
		if self.frame_width > 0 then
			local frame = self:get_color("frame", flags)
			control_canvas:draw_rect(0, 0, width, height, self.frame_width, frame)
		end
	end

	return qui.control(control)
end

-- Callable module syntax keeps declarations readable as 'Panel { ... }'
setmetatable(Panel, {
	__call = function(_, options)
		return Panel.new(options)
	end,
})

return Panel
