Quantcast
--[[
	Copyright (c) 2014 Eyal Shilony <Lynxium>

	Permission is hereby granted, free of charge, to any person obtaining
	a copy of this software and associated documentation files (the
	"Software"), to deal in the Software without restriction, including
	without limitation the rights to use, copy, modify, merge, publish,
	distribute, sublicense, and/or sell copies of the Software, and to
	permit persons to whom the Software is furnished to do so, subject to
	the following conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
	LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
	OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
	WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]

local addonName, addon = ...
local ui = addon:NewModule("Options.UI")
local L = LibStub("AceLocale-3.0"):GetLocale(addonName)

LibStub("Libra"):EmbedWidgets(ui)

local function compByName(a, b)
	return a:GetText():lower() < b:GetText():lower()
end

local function createSeparator(parent, from, to)
	local line = parent:CreateTexture()
	line:SetPoint(unpack(from))
	line:SetPoint(unpack(to))
	line:SetHeight(1)
	line:SetTexture(0.8, 0.8, 0.8, 0.5)
end

function ui:CreateSeparator(parent)
	if parent.label then
		parent:SetPoint("RIGHT", -31, 0)
		parent:SetHeight(1)
		parent.label:ClearAllPoints()
		parent.label:SetPoint("CENTER")
		createSeparator(parent, {"LEFT", parent}, {"RIGHT", parent.label, "LEFT", -5, 0})
		createSeparator(parent, {"RIGHT", parent}, {"LEFT", parent.label, "RIGHT", 5, 0})
	else
		local relativeTo = parent.desc or parent
		createSeparator(parent, {"BOTTOMLEFT", parent.desc, 0, 0}, {"BOTTOMRIGHT", parent.desc, 0, 0})
	end
end

function ui:CreateListItem()
	local frame = CreateFrame("Button")
	frame:SetSize(220, 16)
	frame:SetPushedTextOffset(0, 0)
	frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]])

	local font = frame:CreateFontString(nil, nil, "GameFontHighlight")
	font:SetJustifyH("LEFT")
	font:SetAllPoints()

	frame:SetFontString(font)

	local item = {}

	function item:Select()
		frame.selected = true
		frame:LockHighlight()
	end

	function item:Deselect()
		frame.selected = false
		frame:UnlockHighlight()
	end

    function item:Remove()
		self:Deselect()

        font:Hide()
        font:SetText(nil)
        font:ClearAllPoints()
        font = nil

        frame:Hide()
        frame:SetScript("OnClick", nil)
		frame:SetParent(nil)
        frame:ClearAllPoints()
		frame = nil

        item = nil;
	end

	function item:IsSelected()
		return frame.selected
	end

	function item:SetText(value)
		frame:SetText(value)
	end

	function item:GetText()
		return frame:GetText()
	end

	function item:Copy(destItem)
		destItem:SetText(self:GetText())
	end

	frame:SetScript("OnClick", function()
		if not item:IsSelected() then
			item:Select()
		else
			item:Deselect()
		end
	end)

	item.frame = frame

	return item
end

function ui:CreateList(parent)
	parent = parent.frame or parent

	local frame = CreateFrame("Frame", nil, parent)

	local title = frame:CreateFontString(nil, nil, "GameFontNormal")
	title:SetPoint("TOP", 0, 20)
	title:SetText(name)
	title:SetSize(220, 16)

	local bg = frame:CreateTexture(nil, "BORDER")
	bg:SetTexture(0.3, 0.3, 0.3)
	bg:SetBlendMode("MOD")
	bg:SetAllPoints()

	local border = frame:CreateTexture(nil, "BORDER", nil, -1)
	border:SetTexture(0.5, 0.5, 0.5, 0.3)
	border:SetPoint("TOPLEFT", bg, -1, 1)
	border:SetPoint("BOTTOMRIGHT", bg, 1, -1)

	local count = 0
	local list, items = {}, {}

	function list:SetTitle(value)
		title:SetText(value)
	end

	function list:SetSize(width, height)
		frame:SetSize(width, height)
	end

	function list:SetPoint(point, relativeTo, ...)
		frame:SetPoint(point, type(relativeTo) == "table" and relativeTo.frame or relativeTo, ...)
	end

	function list:AddItem(item)
		count = count + 1

		table.insert(items, item)

		local child = item.frame
		child:SetParent(frame)

		if count == 1 then
			child:SetPoint("TOPLEFT", frame, 10, -10)
		else
			local parent = items[count - 1].frame
			child:SetPoint("TOP", parent, "BOTTOM")
		end
	end

	function list:RemoveItem(index)
		local item = table.remove(items, index)

		if not item then
			return
		end

		if item:IsSelected() then
			item:Deselect()
		end

        item:Remove();

		count = count - 1
	end

	function list:Update()
		for i, item in ipairs(items) do
			item:Deselect()
			local child = item.frame
			child:ClearAllPoints()
			if i == 1 then
				child:SetPoint("TOPLEFT", frame, 10, -10)
			else
				local parent = items[i - 1].frame
				child:SetPoint("TOP", parent, "BOTTOM")
			end
		end
	end

	function list:Items()
		return ipairs(items)
	end

	local function reverse()
		local i = #items + 1
		return function ()
			i = i - 1
			if i > 0 then return i, items[i] end
		end
	end

	function list:Sort(comp)
		table.sort(items, comp)
		self:Update()
	end

	function list:CopyItem(item)
		local destItem = ui:CreateListItem()
		item:Copy(destItem)
		self:AddItem(destItem)
	end

	function list:MoveSelectedTo(destList)
		for i, item in reverse() do
			if item:IsSelected() then
				destList:CopyItem(item)
				self:RemoveItem(i)
			end
		end
		destList:Sort(compByName)
		self:Sort(compByName)
	end

	local function selectedItems()
		local i = 0
		local n = 0
		local max = #items
		return function ()
			while n <= max do
				n = n + 1
				local item = items[n]
				if item and item:IsSelected() then
					i = i + 1
					return i, n, item
				end
			end
			return nil
		end
	end

	local function swap(sourceIndex, destIndex)
		items[sourceIndex], items[destIndex] = items[destIndex], items[sourceIndex]
	end

	local function moveSelected(up)
		local selectedIndices = {}
		for i, n in selectedItems() do
			selectedIndices[i] = n
		end
		local i = up and 1 or #selectedIndices
		local selectedIndex = selectedIndices[i]
		while selectedIndex do
			local index = up and selectedIndex - 1 or selectedIndex + 1
			if count >= index and index > 0 then
				swap(selectedIndex, index)
			end
			i = up and i + 1 or i - 1
			selectedIndex = selectedIndices[i]
		end
	end

	function list:MoveSelectedDown()
		moveSelected()
		self:Update()
	end

	function list:MoveSelectedUp()
		moveSelected(true)
		self:Update()
	end

	list.frame = frame

	return list
end

function ui:CreateButton(parent)
	parent = parent.frame or parent

	local frame = CreateFrame("Button", nil, parent)
	frame:SetSize(24, 24)
	frame:SetHighlightTexture([[Interface\Buttons\UI-Common-MouseHilight]])

	local button = {}

	function button:SetSize(width, height)
		frame:SetSize(width, height)
	end

	function button:SetPoint(point, relativeTo, ...)
		frame:SetPoint(point, type(relativeTo) == "table" and relativeTo.frame or relativeTo, ...)
	end

	function button:SetNormalTexture(texture)
		frame:SetNormalTexture(texture)
	end

	function button:SetPushedTexture(texture)
		frame:SetPushedTexture(texture)
	end

	function button:OnClick(handler)
		frame:SetScript("OnClick", function()
			handler()
		end)
	end

	button.frame = frame

	return button
end