-- This file is part of SUIT, copyright (c) 2016 Matthias Richter local BASE = (...):match('(.-)[^%.]+$') local theme = {} theme.cornerRadius = 4 theme.color = { normal = {bg = { 0.25, 0.25, 0.25}, fg = {0.73,0.73,0.73}}, hovered = {bg = { 0.19,0.6,0.73}, fg = {1,1,1}}, active = {bg = {1,0.6, 0}, fg = {1,1,1}} } -- HELPER function theme.getColorForState(opt) local s = opt.state or "normal" return (opt.color and opt.color[opt.state]) or theme.color[s] end function theme.drawBox(x,y,w,h, colors, cornerRadius, outline, scale) colors = colors or theme.getColorForState(opt) cornerRadius = (cornerRadius or theme.cornerRadius) w = math.max(cornerRadius/2, w) if h < cornerRadius/2 then y,h = y - (cornerRadius - h), cornerRadius/2 end -- by default, scale will operate about the center of the box. meaning it grows -- out/in in all directions if scale and scale ~= 1.0 then local baseW, baseH = w, h w = w * scale h = h * scale x = x - (w - baseW) / 2 y = y - (h - baseH) / 2 cornerRadius = cornerRadius * scale end love.graphics.setColor(colors.bg) love.graphics.rectangle('fill', x,y, w,h, cornerRadius) if outline ~= nil then love.graphics.setColor(colors.fg) love.graphics.setLineWidth(outline) love.graphics.rectangle('line', x,y, w,h, cornerRadius) end end function theme.getVerticalOffsetForAlign(valign, font, h) if valign == "top" then return 0 elseif valign == "bottom" then return h - font:getHeight() end -- else: "middle" return (h - font:getHeight()) / 2 end -- WIDGET VIEWS function theme.Label(text, opt, x,y,w,h) y = y + theme.getVerticalOffsetForAlign(opt.valign, opt.font, h) love.graphics.setColor((opt.color and opt.color.normal or {}).fg or theme.color.normal.fg) love.graphics.setFont(opt.font) love.graphics.printf(text, x+2, y, w-4, opt.align or "center") end function theme.Button(text, opt, x,y,w,h) local c = theme.getColorForState(opt) local scale = opt.scale or 1.0 theme.drawBox(x,y,w,h, c, opt.cornerRadius, opt.outline, scale) love.graphics.setColor(c.fg) love.graphics.setFont(opt.font) -- ensure text remains aligned regardless of scale local align = opt.align or "center" local textX = x local textY = y local textW = w if scale ~= 1.0 then -- For center alignment, shift x so the scaled text stays centered if align == "center" then textX = x + (w - w * scale) / 2 elseif align == "right" then textX = x + (w - w * scale) end end y = y + theme.getVerticalOffsetForAlign(opt.valign, opt.font, h) love.graphics.printf(text, textX+2, textY, textW-4, align, 0, scale, scale ) end function theme.Checkbox(chk, opt, x,y,w,h) local c = theme.getColorForState(opt) local th = opt.font:getHeight() theme.drawBox(x+h/10,y+h/10,h*.8,h*.8, c, opt.cornerRadius) love.graphics.setColor(c.fg) if chk.checked then love.graphics.setLineStyle('smooth') love.graphics.setLineWidth(5) love.graphics.setLineJoin("bevel") love.graphics.line(x+h*.2,y+h*.55, x+h*.45,y+h*.75, x+h*.8,y+h*.2) end if chk.text then love.graphics.setFont(opt.font) y = y + theme.getVerticalOffsetForAlign(opt.valign, opt.font, h) love.graphics.printf(chk.text, x + h, y, w - h, opt.align or "left") end end function theme.Slider(fraction, opt, x,y,w,h) local xb, yb, wb, hb -- size of the progress bar local r = math.min(w,h) / 2.1 if opt.vertical then x, w = x + w*.25, w*.5 xb, yb, wb, hb = x, y+h*(1-fraction), w, h*fraction else y, h = y + h*.25, h*.5 xb, yb, wb, hb = x,y, w*fraction, h end local c = theme.getColorForState(opt) theme.drawBox(x,y,w,h, c, opt.cornerRadius) theme.drawBox(xb,yb,wb,hb, {bg=c.fg}, opt.cornerRadius) if opt.state ~= nil and opt.state ~= "normal" then love.graphics.setColor((opt.color and opt.color.active or {}).fg or theme.color.active.fg) if opt.vertical then love.graphics.circle('fill', x+wb/2, yb, r) else love.graphics.circle('fill', x+wb, yb+hb/2, r) end end end function theme.Input(input, opt, x,y,w,h) local utf8 = require 'utf8' theme.drawBox(x,y,w,h, (opt.color and opt.color.normal) or theme.color.normal, opt.cornerRadius) x = x + 3 w = w - 6 local th = opt.font:getHeight() -- set scissors local sx, sy, sw, sh = love.graphics.getScissor() love.graphics.setScissor(x-1,y,w+2,h) x = x - input.text_draw_offset -- text love.graphics.setColor((opt.color and opt.color.normal and opt.color.normal.fg) or theme.color.normal.fg) love.graphics.setFont(opt.font) love.graphics.print(input.text, x, y+(h-th)/2) -- candidate text local tw = opt.font:getWidth(input.text) local ctw = opt.font:getWidth(input.candidate_text.text) love.graphics.setColor((opt.color and opt.color.normal and opt.color.normal.fg) or theme.color.normal.fg) love.graphics.print(input.candidate_text.text, x + tw, y+(h-th)/2) -- candidate text rectangle box love.graphics.rectangle("line", x + tw, y+(h-th)/2, ctw, th) -- cursor if opt.hasKeyboardFocus and (love.timer.getTime() % 1) > .5 then local ct = input.candidate_text; local ss = ct.text:sub(1, utf8.offset(ct.text, ct.start)) local ws = opt.font:getWidth(ss) if ct.start == 0 then ws = 0 end love.graphics.setLineWidth(1) love.graphics.setLineStyle('rough') love.graphics.line(x + opt.cursor_pos + ws, y + (h-th)/2, x + opt.cursor_pos + ws, y + (h+th)/2) end -- reset scissor love.graphics.setScissor(sx,sy,sw,sh) end return theme