diff --git a/changelog.txt b/changelog.txt index 5ec5dac..45440aa 100644 --- a/changelog.txt +++ b/changelog.txt @@ -32,6 +32,7 @@ Version 0.9.7 - Alpha (Release Date TBD) [ADDED] a new util library function: GetHoverObject() [ADDED] a new callback: textinput(text) [ADDED] a new object: form +[ADDED] a new object: menu [ADDED] a new skin drawing function: DrawOverTabPanel(object) [ADDED] basic clipboard support for the textinput object (0.9.0 only) [ADDED] custom cursor support for the textinput object diff --git a/init.lua b/init.lua index a4b0e35..d9a2ccf 100644 --- a/init.lua +++ b/init.lua @@ -187,6 +187,24 @@ function loveframes.mousepressed(x, y, button) local base = loveframes.base base:mousepressed(x, y, button) + -- close open menus + local bchildren = base.children + local hoverobject = loveframes.hoverobject + for k, v in ipairs(bchildren) do + local otype = v.type + local visible = v.visible + if hoverobject then + local htype = hoverobject.type + if otype == "menu" and visible and htype ~= "menu" and htype ~= "menuoption" then + v:SetVisible(false) + end + else + if otype == "menu" and visible then + v:SetVisible(false) + end + end + end + end --[[--------------------------------------------------------- diff --git a/objects/internal/menuoption.lua b/objects/internal/menuoption.lua new file mode 100644 index 0000000..6e04947 --- /dev/null +++ b/objects/internal/menuoption.lua @@ -0,0 +1,233 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2013 Kenny Shields -- +--]]------------------------------------------------ + +-- menuoption object +local newobject = loveframes.NewObject("menuoption", "loveframes_object_menuoption", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize(parent, option_type, menu) + + self.type = "menuoption" + self.text = "Option" + self.width = 100 + self.height = 25 + self.contentwidth = 0 + self.contentheight = 0 + self.parent = parent + self.option_type = option_type or "option" + self.menu = menu + self.activated = false + self.internal = true + self.icon = false + self.func = nil + +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the object +--]]--------------------------------------------------------- +function newobject:update(dt) + + local state = loveframes.state + local selfstate = self.state + + if state ~= selfstate then + return + end + + local visible = self.visible + local alwaysupdate = self.alwaysupdate + + if not visible then + if not alwaysupdate then + return + end + end + + self:CheckHover() + + local hover = self.hover + local parent = self.parent + local option_type = self.option_type + local base = loveframes.base + local update = self.Update + + if option_type == "submenu_activator" then + local activated = self.activated + if hover and not activated then + self.menu:SetVisible(true) + self.menu:SetPos(self:GetX() + self:GetWidth(), self:GetY()) + self.activated = true + elseif not hover and activated then + local hoverobject = loveframes.hoverobject + if hoverobject and hoverobject:GetBaseParent() == self.parent then + self.menu:SetVisible(false) + self.activated = false + end + end + end + + -- move to parent if there is a parent + if parent ~= base then + self.x = self.parent.x + self.staticx + self.y = self.parent.y + self.staticy + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: draw() + - desc: draws the object +--]]--------------------------------------------------------- +function newobject:draw() + + local state = loveframes.state + local selfstate = self.state + + if state ~= selfstate then + return + end + + local visible = self.visible + + if not visible then + return + end + + local skins = loveframes.skins.available + local skinindex = loveframes.config["ACTIVESKIN"] + local defaultskin = loveframes.config["DEFAULTSKIN"] + local selfskin = self.skin + local skin = skins[selfskin] or skins[skinindex] + local drawfunc = skin.DrawMenuOption or skins[defaultskin].DrawMenuOption + local draw = self.Draw + local drawcount = loveframes.drawcount + + -- set the object's draw order + self:SetDrawOrder() + + if draw then + draw(self) + else + drawfunc(self) + end + +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +function newobject:mousepressed(x, y, button) + + local state = loveframes.state + local selfstate = self.state + + if state ~= selfstate then + return + end + + local visible = self.visible + + if not visible then + return + end + +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + + local state = loveframes.state + local selfstate = self.state + + if state ~= selfstate then + return + end + + local visible = self.visible + + if not visible then + return + end + + local hover = self.hover + local option_type = self.option_type + if hover and option_type ~= "divider" and button == "l" then + local func = self.func + if func then + local text = self.text + func(self, text) + end + local basemenu = self.parent:GetBaseMenu() + basemenu:SetVisible(false) + end + +end + +--[[--------------------------------------------------------- + - func: SetText(text) + - desc: sets the object's text +--]]--------------------------------------------------------- +function newobject:SetText(text) + + self.text = text + +end + +--[[--------------------------------------------------------- + - func: GetText() + - desc: gets the object's text +--]]--------------------------------------------------------- +function newobject:GetText() + + return self.text + +end + +--[[--------------------------------------------------------- + - func: SetIcon(icon) + - desc: sets the object's icon +--]]--------------------------------------------------------- +function newobject:SetIcon(icon) + + if type(icon) == "string" then + self.icon = love.graphics.newImage(icon) + elseif type(icon) == "userdata" then + self.icon = icon + end + +end + +--[[--------------------------------------------------------- + - func: GetIcon() + - desc: gets the object's icon +--]]--------------------------------------------------------- +function newobject:GetIcon() + + return self.icon + +end + +--[[--------------------------------------------------------- + - func: SetFunction(func) + - desc: sets the object's function +--]]--------------------------------------------------------- +function newobject:SetFunction(func) + + self.func = func + +end \ No newline at end of file diff --git a/objects/menu.lua b/objects/menu.lua new file mode 100644 index 0000000..1b76b5f --- /dev/null +++ b/objects/menu.lua @@ -0,0 +1,292 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2013 Kenny Shields -- +--]]------------------------------------------------ + +-- menu object +local newobject = loveframes.NewObject("menu", "loveframes_object_menu", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize(menu) + + self.type = "menu" + self.width = 80 + self.height = 25 + self.largest_item_width = 0 + self.largest_item_height = 0 + self.is_sub_menu = false + self.internal = false + self.parentmenu = nil + self.options = {} + self.internals = {} + +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the object +--]]--------------------------------------------------------- +function newobject:update(dt) + + local state = loveframes.state + local selfstate = self.state + + if state ~= selfstate then + return + end + + local visible = self.visible + local alwaysupdate = self.alwaysupdate + + if not visible then + if not alwaysupdate then + return + end + end + + self:CheckHover() + + local hover = self.hover + local parent = self.parent + local base = loveframes.base + local update = self.Update + + -- move to parent if there is a parent + if parent ~= base then + self.x = self.parent.x + self.staticx + self.y = self.parent.y + self.staticy + end + + for k, v in ipairs(self.internals) do + local width = v.contentwidth + local height = v.contentheight + if width > self.largest_item_width then + self.largest_item_width = width + end + if height > self.largest_item_height then + self.largest_item_height = height + end + end + + local y = 0 + self.height = 0 + + for k, v in ipairs(self.internals) do + v:SetWidth(self.largest_item_width) + if v.option_type ~= "divider" then + v:SetHeight(self.largest_item_height) + else + v:SetHeight(5) + end + v:SetY(y) + self.height = self.height + v.height + y = y + v.height + v:update(dt) + end + + self.width = self.largest_item_width + self.largest_item_width = 0 + self.largest_item_height = 0 + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: draw() + - desc: draws the object +--]]--------------------------------------------------------- +function newobject:draw() + + local state = loveframes.state + local selfstate = self.state + + if state ~= selfstate then + return + end + + local visible = self.visible + + if not visible then + return + end + + local skins = loveframes.skins.available + local skinindex = loveframes.config["ACTIVESKIN"] + local defaultskin = loveframes.config["DEFAULTSKIN"] + local selfskin = self.skin + local skin = skins[selfskin] or skins[skinindex] + local drawfunc = skin.DrawMenu or skins[defaultskin].DrawMenu + local draw = self.Draw + local drawoverfunc = skin.DrawOverMenu or skins[defaultskin].DrawOverMenu + local drawcount = loveframes.drawcount + + -- set the object's draw order + self:SetDrawOrder() + + if draw then + draw(self) + else + drawfunc(self) + end + + for k, v in ipairs(self.internals) do + v:draw() + end + + if drawoverfunc then + drawoverfunc(self) + end + +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +function newobject:mousepressed(x, y, button) + + local state = loveframes.state + local selfstate = self.state + + if state ~= selfstate then + return + end + + local visible = self.visible + + if not visible then + return + end + +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + + local state = loveframes.state + local selfstate = self.state + + if state ~= selfstate then + return + end + + local visible = self.visible + + if not visible then + return + end + + local internals = self.internals + for k, v in ipairs(internals) do + v:mousereleased(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: AddOption(text, icon, func) + - desc: adds an option to the object +--]]--------------------------------------------------------- +function newobject:AddOption(text, icon, func) + + local menuoption = loveframes.objects["menuoption"]:new(self) + menuoption:SetText(text) + menuoption:SetIcon(icon) + menuoption:SetFunction(func) + + table.insert(self.internals, menuoption) + +end + +--[[--------------------------------------------------------- + - func: AddSubMenu(text, icon, menu) + - desc: adds a submenu to the object +--]]--------------------------------------------------------- +function newobject:AddSubMenu(text, icon, menu) + + local function activatorFunc(object) + if menu:GetVisible() then + local hoverobject = loveframes.hoverobject + if hoverobject ~= object and hoverobject:GetBaseParent() ~= menu then + menu:SetVisible(false) + end + else + menu:SetVisible(true) + menu:SetPos(object:GetX() + object:GetWidth(), object:GetY()) + end + end + + menu:SetVisible(false) + + local menuoption = loveframes.objects["menuoption"]:new(self, "submenu_activator", menu) + menuoption:SetText(text) + menuoption:SetIcon(icon) + + if menu then + menu.is_sub_menu = true + menu.parentmenu = self + end + + table.insert(self.internals, menuoption) + +end + +--[[--------------------------------------------------------- + - func: AddDivider() + - desc: adds a divider to the object +--]]--------------------------------------------------------- +function newobject:AddDivider() + + local menuoption = loveframes.objects["menuoption"]:new(self, "divider") + + table.insert(self.internals, menuoption) + +end + +--[[--------------------------------------------------------- + - func: GetBaseMenu(t) + - desc: gets the object's base menu +--]]--------------------------------------------------------- +function newobject:GetBaseMenu(t) + + local t = t or {} + + if self.parentmenu then + table.insert(t, self.parentmenu) + self.parentmenu:GetBaseMenu(t) + else + return self + end + + return t[#t] + +end + +--[[--------------------------------------------------------- + - func: SetVisible(bool) + - desc: sets the object's visibility +--]]--------------------------------------------------------- +function newobject:SetVisible(bool) + + self.visible = bool + + if not bool then + local internals = self.internals + for k, v in ipairs(internals) do + if v.menu then + v.activated = false + v.menu:SetVisible(bool) + end + end + end + +end \ No newline at end of file diff --git a/skins/Blue/skin.lua b/skins/Blue/skin.lua index f43ba8d..5897177 100644 --- a/skins/Blue/skin.lua +++ b/skins/Blue/skin.lua @@ -104,7 +104,7 @@ skin.controls.checkbox_check_color = {128, 204, 255, 255} skin.controls.checkbox_text_font = smallfont -- collapsiblecategory -skin.controls.collapsiblecategory_text_color = {0, 0, 0, 255} +skin.controls.collapsiblecategory_text_color = {255, 255, 255, 255} -- columnlist skin.controls.columnlist_body_color = {232, 232, 232, 255} @@ -134,10 +134,21 @@ skin.controls.modalbackground_body_color = {255, 255, 255, 100} skin.controls.linenumberspanel_text_color = {170, 170, 170, 255} skin.controls.linenumberspanel_body_color = {235, 235, 235, 255} +-- grid +skin.controls.grid_body_color = {230, 230, 230, 255} + -- form skin.controls.form_text_color = {0, 0, 0, 255} skin.controls.form_text_font = smallfont +-- menu +skin.controls.menu_body_color = {255, 255, 255, 255} + +-- menuoption +skin.controls.menuoption_body_hover_color = {51, 204, 255, 255} +skin.controls.menuoption_text_hover_color = {255, 255, 255, 255} +skin.controls.menuoption_text_color = {180, 180, 180, 255} + --[[--------------------------------------------------------- - func: OutlinedRectangle(x, y, width, height, ovt, ovb, ovl, ovr) - desc: creates and outlined rectangle @@ -207,8 +218,6 @@ function skin.DrawFrame(object) -- frame top bar love.graphics.setColor(255, 255, 255, 255) love.graphics.draw(topbarimage, x, y, 0, topbarimage_scalex, topbarimage_scaley) - love.graphics.setColor(bordercolor) - skin.OutlinedRectangle(x, y + 25, width, 1) -- frame name section love.graphics.setFont(font) @@ -230,6 +239,12 @@ function skin.DrawFrame(object) love.graphics.setColor(bordercolor) skin.OutlinedRectangle(x, y, width, height) + love.graphics.setColor(255, 255, 255, 70) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, 24) + + love.graphics.setColor(220, 220, 220, 255) + skin.OutlinedRectangle(x + 1, y + 25, width - 2, height - 26) + end --[[--------------------------------------------------------- @@ -316,6 +331,9 @@ function skin.DrawButton(object) love.graphics.setColor(bordercolor) skin.OutlinedRectangle(x, y, width, height) end + + love.graphics.setColor(255, 255, 255, 150) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, height - 2) end @@ -504,9 +522,9 @@ function skin.DrawScrollArea(object) love.graphics.setColor(bordercolor) if bartype == "vertical" then - skin.OutlinedRectangle(x, y, width, height, true, true) + --skin.OutlinedRectangle(x, y, width, height, true, true) elseif bartype == "horizontal" then - skin.OutlinedRectangle(x, y, width, height, false, false, true, true) + --skin.OutlinedRectangle(x, y, width, height, false, false, true, true) end end @@ -555,18 +573,6 @@ function skin.DrawScrollBar(object) skin.OutlinedRectangle(x, y, width, height) end - if bartype == "vertical" then - love.graphics.setColor(bordercolor) - love.graphics.rectangle("fill", x + 3, y + height/2 - 3, width - 6, 1) - love.graphics.rectangle("fill", x + 3, y + height/2, width - 6, 1) - love.graphics.rectangle("fill", x + 3, y + height/2 + 3, width - 6, 1) - else - love.graphics.setColor(bordercolor) - love.graphics.rectangle("fill", x + width/2 - 3, y + 3, 1, height - 6) - love.graphics.rectangle("fill", x + width/2, y + 3, 1, height - 6) - love.graphics.rectangle("fill", x + width/2 + 3, y + 3, 1, height - 6) - end - end --[[--------------------------------------------------------- @@ -602,6 +608,10 @@ function skin.DrawPanel(object) love.graphics.setColor(bodycolor) love.graphics.rectangle("fill", x, y, width, height) + + love.graphics.setColor(255, 255, 255, 200) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, height - 2) + love.graphics.setColor(bordercolor) skin.OutlinedRectangle(x, y, width, height) @@ -1059,6 +1069,9 @@ function skin.DrawTextInput(object) love.graphics.print(#str > 0 and str or placeholder, textx, texty) end + love.graphics.setColor(230, 230, 230, 255) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, height - 2) + end --[[--------------------------------------------------------- @@ -1321,15 +1334,19 @@ function skin.DrawCollapsibleCategory(object) local textcolor = skin.controls.collapsiblecategory_text_color local font = smallfont local image = skin.images["button-nohover.png"] + local topbarimage = skin.images["frame-topbar.png"] + local topbarimage_width = topbarimage:getWidth() + local topbarimage_height = topbarimage:getHeight() + local topbarimage_scalex = width/topbarimage_width + local topbarimage_scaley = 25/topbarimage_height local imageheight = image:getHeight() local scaley = height/imageheight love.graphics.setColor(255, 255, 255, 255) love.graphics.draw(image, x, y, 0, width, scaley) - love.graphics.setFont(font) - love.graphics.setColor(textcolor) - love.graphics.print(text, x + 5, y + 5) + love.graphics.setColor(255, 255, 255, 255) + love.graphics.draw(topbarimage, x, y, 0, topbarimage_scalex, topbarimage_scaley) love.graphics.setColor(bordercolor) skin.OutlinedRectangle(x, y, width, height) @@ -1339,12 +1356,20 @@ function skin.DrawCollapsibleCategory(object) local icon = skin.images["collapse.png"] icon:setFilter("nearest", "nearest") love.graphics.draw(icon, x + width - 21, y + 5) + love.graphics.setColor(255, 255, 255, 70) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, 24) else local icon = skin.images["expand.png"] icon:setFilter("nearest", "nearest") love.graphics.draw(icon, x + width - 21, y + 5) + love.graphics.setColor(255, 255, 255, 70) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, 23) end + love.graphics.setFont(font) + love.graphics.setColor(textcolor) + love.graphics.print(text, x + 5, y + 5) + end --[[--------------------------------------------------------- @@ -1504,23 +1529,15 @@ function skin.DrawColumnListRow(object) if selected then love.graphics.setColor(bodyselectedcolor) love.graphics.rectangle("fill", x, y, width, height) - love.graphics.setColor(bordercolor) - skin.OutlinedRectangle(x, y, width, height, true, false, true, true) elseif hover then love.graphics.setColor(bodyhovercolor) love.graphics.rectangle("fill", x, y, width, height) - love.graphics.setColor(bordercolor) - skin.OutlinedRectangle(x, y, width, height, true, false, true, true) elseif colorindex == 1 then love.graphics.setColor(body1color) - love.graphics.rectangle("fill", x + 1, y + 1, width - 2, height - 2) - love.graphics.setColor(bordercolor) - skin.OutlinedRectangle(x, y, width, height, true, false, true, true) + love.graphics.rectangle("fill", x, y, width, height) else love.graphics.setColor(body2color) love.graphics.rectangle("fill", x, y, width, height) - love.graphics.setColor(bordercolor) - skin.OutlinedRectangle(x, y, width, height, true, false, true, true) end for k, v in ipairs(columndata) do @@ -1613,6 +1630,7 @@ function skin.DrawGrid(object) local y = object:GetY() local width = object:GetWidth() local height = object:GetHeight() + local bodycolor = skin.controls.grid_body_color love.graphics.setColor(bordercolor) skin.OutlinedRectangle(x, y, width, height) @@ -1632,6 +1650,9 @@ function skin.DrawGrid(object) if n > 1 then ovl = true end + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", cx, cy, cw, ch) + love.graphics.setColor(bordercolor) skin.OutlinedRectangle(cx, cy, cw, ch, ovt, false, ovl, false) cx = cx + cw end @@ -1647,6 +1668,7 @@ end --]]--------------------------------------------------------- function skin.DrawForm(object) + local skin = object:GetSkin() local x = object:GetX() local y = object:GetY() local width = object:GetWidth() @@ -1670,5 +1692,72 @@ function skin.DrawForm(object) end +--[[--------------------------------------------------------- + - func: skin.DrawMenu(object) + - desc: draws the menu object +--]]--------------------------------------------------------- +function skin.DrawMenu(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local bodycolor = skin.controls.menu_body_color + + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x, y, width, height) + + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawMenuOption(object) + - desc: draws the menuoption object +--]]--------------------------------------------------------- +function skin.DrawMenuOption(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local hover = object:GetHover() + local text = object:GetText() + local icon = object:GetIcon() + local option_type = object.option_type + local body_hover_color = skin.controls.menuoption_body_hover_color + local text_hover_color = skin.controls.menuoption_text_hover_color + local text_color = skin.controls.menuoption_text_color + local twidth = smallfont:getWidth(text) + + + if option_type == "divider" then + love.graphics.setColor(200, 200, 200, 255) + love.graphics.rectangle("fill", x + 4, y + 2, width - 8, 1) + object.contentheight = 10 + else + love.graphics.setFont(smallfont) + if hover then + love.graphics.setColor(body_hover_color) + love.graphics.rectangle("fill", x + 2, y + 2, width - 4, height - 4) + love.graphics.setColor(text_hover_color) + love.graphics.print(text, x + 26, y + 5) + else + love.graphics.setColor(text_color) + love.graphics.print(text, x + 26, y + 5) + end + if icon then + love.graphics.setColor(255, 255, 255, 255) + love.graphics.draw(icon, x + 5, y + 5) + end + object.contentwidth = twidth + 31 + object.contentheight = 25 + end + +end + -- register the skin -loveframes.skins.Register(skin) +loveframes.skins.Register(skin) \ No newline at end of file diff --git a/skins/Orange/skin.lua b/skins/Orange/skin.lua index 3cdde19..6b0043f 100644 --- a/skins/Orange/skin.lua +++ b/skins/Orange/skin.lua @@ -28,5 +28,8 @@ skin.controls.checkbox_check_color = {255, 153, 0, 255} skin.controls.columnlistrow_body_selected_color = {255, 153, 0, 255} skin.controls.columnlistrow_body_hover_color = {255, 173, 51, 255} +-- menuoption +skin.controls.menuoption_body_hover_color = {255, 153, 0, 255} + -- register the skin loveframes.skins.Register(skin) \ No newline at end of file