<commit_before>require "ui/widget/base"

--[[
WidgetContainer is a container for another Widget
--]]
WidgetContainer = Widget:new()

function WidgetContainer:getSize()
	if self.dimen then
		-- fixed size
		return self.dimen
	elseif self[1] then
		-- return size of first child widget
		return self[1]:getSize()
	else
		return Geom:new{ w = 0, h = 0 }
	end
end

--[[
delete all child widgets
--]]
function WidgetContainer:clear()
	while table.remove(self) do end
end

function WidgetContainer:paintTo(bb, x, y)
	-- default to pass request to first child widget
	if self[1] then
		return self[1]:paintTo(bb, x, y)
	end
end

function WidgetContainer:propagateEvent(event)
	-- propagate to children
	for _, widget in ipairs(self) do
		if widget:handleEvent(event) then
			-- stop propagating when an event handler returns true
			return true
		end
	end
	return false
end

--[[
Containers will pass events to children or react on them themselves
--]]
function WidgetContainer:handleEvent(event)
	if not self:propagateEvent(event) then
		-- call our own standard event handler
		return Widget.handleEvent(self, event)
	else
		return true
	end
end

function WidgetContainer:free()
	for _, widget in ipairs(self) do
		if widget.free then widget:free() end
	end
end

--[[
BottomContainer contains its content (1 widget) at the bottom of its own
dimensions
--]]
BottomContainer = WidgetContainer:new()

function BottomContainer:paintTo(bb, x, y)
	local contentSize = self[1]:getSize()
	if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
		-- throw error? paint to scrap buffer and blit partially?
		-- for now, we ignore this
	end
	self[1]:paintTo(bb,
		x + (self.dimen.w - contentSize.w)/2,
		y + (self.dimen.h - contentSize.h))
end

--[[
CenterContainer centers its content (1 widget) within its own dimensions
--]]
CenterContainer = WidgetContainer:new()

function CenterContainer:paintTo(bb, x, y)
	local contentSize = self[1]:getSize()
	if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
		-- throw error? paint to scrap buffer and blit partially?
		-- for now, we ignore this
	end
	local x_pos = x
	local y_pos = y
	if self.ignore ~= "height" then
		y_pos = y + (self.dimen.h - contentSize.h)/2
	end
	if self.ignore ~= "width" then
		x_pos = x + (self.dimen.w - contentSize.w)/2
	end
	self[1]:paintTo(bb, x_pos, y_pos)
end

--[[
LeftContainer aligns its content (1 widget) at the left of its own dimensions
--]]
LeftContainer = WidgetContainer:new()

function LeftContainer:paintTo(bb, x, y)
	local contentSize = self[1]:getSize()
	if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
		-- throw error? paint to scrap buffer and blit partially?
		-- for now, we ignore this
	end
	self[1]:paintTo(bb, x , y + (self.dimen.h - contentSize.h)/2)
end

--[[
RightContainer aligns its content (1 widget) at the right of its own dimensions
--]]
RightContainer = WidgetContainer:new()

function RightContainer:paintTo(bb, x, y)
	local contentSize = self[1]:getSize()
	if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
		-- throw error? paint to scrap buffer and blit partially?
		-- for now, we ignore this
	end
	self[1]:paintTo(bb,
		x + (self.dimen.w - contentSize.w),
		y + (self.dimen.h - contentSize.h)/2)
end

--[[
A FrameContainer is some graphics content (1 widget) that is surrounded by a
frame
--]]
FrameContainer = WidgetContainer:new{
	background = nil,
	color = 15,
	margin = 0,
	radius = 0,
	bordersize = 2,
	padding = 5,
}

function FrameContainer:getSize()
	local content_size = self[1]:getSize()
	return Geom:new{
		w = content_size.w + ( self.margin + self.bordersize + self.padding ) * 2,
		h = content_size.h + ( self.margin + self.bordersize + self.padding ) * 2
	}
end

function FrameContainer:paintTo(bb, x, y)
	local my_size = self:getSize()

	if self.background then
		bb:paintRoundedRect(x, y, my_size.w, my_size.h, self.background, self.radius)
	end
	if self.bordersize > 0 then
		bb:paintBorder(x + self.margin, y + self.margin,
			my_size.w - self.margin * 2, my_size.h - self.margin * 2,
			self.bordersize, self.color, self.radius)
	end
	if self[1] then
		self[1]:paintTo(bb,
			x + self.margin + self.bordersize + self.padding,
			y + self.margin + self.bordersize + self.padding)
	end
end


--[[
an UnderlineContainer is a WidgetContainer that is able to paint
a line under its child node
--]]

UnderlineContainer = WidgetContainer:new{
	linesize = 2,
	padding = 1,
	color = 0,
}

function UnderlineContainer:getSize()
	if self.dimen then
		return { w = self.dimen.w, h = self.dimen.h }
	else
		local contentSize = self[1]:getSize()
		return { 
			w = contentSize.w, 
			h = contentSize.h + self.linesize + self.padding
		}
	end
end

function UnderlineContainer:paintTo(bb, x, y)
	local content_size = self:getSize()
	self[1]:paintTo(bb, x, y)
	bb:paintRect(x, y + content_size.h - self.linesize,
		content_size.w, self.linesize, self.color)
end



--[[
an InputContainer is an WidgetContainer that handles input events

an example for a key_event is this:

	PanBy20 = {
		{ "Shift", Input.group.Cursor },
		seqtext = "Shift+Cursor",
		doc = "pan by 20px",
		event = "Pan", args = 20, is_inactive = true,<commit_msg>add vertical_align to UnderlineContainer<commit_after>require "ui/widget/base"

--[[
WidgetContainer is a container for another Widget
--]]
WidgetContainer = Widget:new()

function WidgetContainer:getSize()
	if self.dimen then
		-- fixed size
		return self.dimen
	elseif self[1] then
		-- return size of first child widget
		return self[1]:getSize()
	else
		return Geom:new{ w = 0, h = 0 }
	end
end

--[[
delete all child widgets
--]]
function WidgetContainer:clear()
	while table.remove(self) do end
end

function WidgetContainer:paintTo(bb, x, y)
	-- default to pass request to first child widget
	if self[1] then
		return self[1]:paintTo(bb, x, y)
	end
end

function WidgetContainer:propagateEvent(event)
	-- propagate to children
	for _, widget in ipairs(self) do
		if widget:handleEvent(event) then
			-- stop propagating when an event handler returns true
			return true
		end
	end
	return false
end

--[[
Containers will pass events to children or react on them themselves
--]]
function WidgetContainer:handleEvent(event)
	if not self:propagateEvent(event) then
		-- call our own standard event handler
		return Widget.handleEvent(self, event)
	else
		return true
	end
end

function WidgetContainer:free()
	for _, widget in ipairs(self) do
		if widget.free then widget:free() end
	end
end

--[[
BottomContainer contains its content (1 widget) at the bottom of its own
dimensions
--]]
BottomContainer = WidgetContainer:new()

function BottomContainer:paintTo(bb, x, y)
	local contentSize = self[1]:getSize()
	if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
		-- throw error? paint to scrap buffer and blit partially?
		-- for now, we ignore this
	end
	self[1]:paintTo(bb,
		x + (self.dimen.w - contentSize.w)/2,
		y + (self.dimen.h - contentSize.h))
end

--[[
CenterContainer centers its content (1 widget) within its own dimensions
--]]
CenterContainer = WidgetContainer:new()

function CenterContainer:paintTo(bb, x, y)
	local contentSize = self[1]:getSize()
	if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
		-- throw error? paint to scrap buffer and blit partially?
		-- for now, we ignore this
	end
	local x_pos = x
	local y_pos = y
	if self.ignore ~= "height" then
		y_pos = y + (self.dimen.h - contentSize.h)/2
	end
	if self.ignore ~= "width" then
		x_pos = x + (self.dimen.w - contentSize.w)/2
	end
	self[1]:paintTo(bb, x_pos, y_pos)
end

--[[
LeftContainer aligns its content (1 widget) at the left of its own dimensions
--]]
LeftContainer = WidgetContainer:new()

function LeftContainer:paintTo(bb, x, y)
	local contentSize = self[1]:getSize()
	if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
		-- throw error? paint to scrap buffer and blit partially?
		-- for now, we ignore this
	end
	self[1]:paintTo(bb, x , y + (self.dimen.h - contentSize.h)/2)
end

--[[
RightContainer aligns its content (1 widget) at the right of its own dimensions
--]]
RightContainer = WidgetContainer:new()

function RightContainer:paintTo(bb, x, y)
	local contentSize = self[1]:getSize()
	if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
		-- throw error? paint to scrap buffer and blit partially?
		-- for now, we ignore this
	end
	self[1]:paintTo(bb,
		x + (self.dimen.w - contentSize.w),
		y + (self.dimen.h - contentSize.h)/2)
end

--[[
A FrameContainer is some graphics content (1 widget) that is surrounded by a
frame
--]]
FrameContainer = WidgetContainer:new{
	background = nil,
	color = 15,
	margin = 0,
	radius = 0,
	bordersize = 2,
	padding = 5,
}

function FrameContainer:getSize()
	local content_size = self[1]:getSize()
	return Geom:new{
		w = content_size.w + ( self.margin + self.bordersize + self.padding ) * 2,
		h = content_size.h + ( self.margin + self.bordersize + self.padding ) * 2
	}
end

function FrameContainer:paintTo(bb, x, y)
	local my_size = self:getSize()

	if self.background then
		bb:paintRoundedRect(x, y, my_size.w, my_size.h, self.background, self.radius)
	end
	if self.bordersize > 0 then
		bb:paintBorder(x + self.margin, y + self.margin,
			my_size.w - self.margin * 2, my_size.h - self.margin * 2,
			self.bordersize, self.color, self.radius)
	end
	if self[1] then
		self[1]:paintTo(bb,
			x + self.margin + self.bordersize + self.padding,
			y + self.margin + self.bordersize + self.padding)
	end
end


--[[
an UnderlineContainer is a WidgetContainer that is able to paint
a line under its child node
--]]

UnderlineContainer = WidgetContainer:new{
	linesize = 2,
	padding = 1,
	color = 0,
	vertical_align = "top",
}

function UnderlineContainer:getSize()
	if self.dimen then
		return { w = self.dimen.w, h = self.dimen.h }
	else
		return self:getContentSize()
	end
end

function UnderlineContainer:getContentSize()
	local contentSize = self[1]:getSize()
	return {
		w = contentSize.w,
		h = contentSize.h + self.linesize + self.padding
	}
end

function UnderlineContainer:paintTo(bb, x, y)
	local container_size = self:getSize()
	local content_size = self:getContentSize()
	local p_y = y
	if self.vertical_align == "center" then
		p_y = (container_size.h - content_size.h) / 2 + y
	elseif self.vertical_align == "bottom" then
		p_y = (container_size.h - content_size.h) + y
	end
	self[1]:paintTo(bb, x, p_y)
	bb:paintRect(x, y + container_size.h - self.linesize,
		container_size.w, self.linesize, self.color)
end



--[[
an InputContainer is an WidgetContainer that handles input events

an example for a key_event is this:

	PanBy20 = {
		{ "Shift", Input.group.Cursor },
		seqtext = "Shift+Cursor",
		doc = "pan by 20px",
		event = "Pan", args = 20, is_inactive = true,
{'fraction_non_alphanumeric': 0.11668827560659381, 'fraction_numerical': 0.009168364511946657, 'mean_word_length': 3.8513027852650494, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3606430', 'n_tokens_mistral': 3910, 'n_tokens_neox': 3737, 'n_words': 1155}