From f3da84db34c9a8c9c016f40f39c5657f82c9ee53 Mon Sep 17 00:00:00 2001 From: Brandon Dyck Date: Thu, 11 Apr 2024 21:42:11 -0600 Subject: [PATCH] Added time controls and nice clock face --- clock.lua | 93 +- conf.lua | 1 + font/JosefinSans-Regular.ttf | Bin 0 -> 59880 bytes font/OFL.txt | 93 + loveframes/changelog.txt | 954 ++++++++ loveframes/init.lua | 308 +++ loveframes/libraries/objects.lua | 150 ++ loveframes/libraries/skins.lua | 117 + loveframes/libraries/templates.lua | 85 + loveframes/libraries/utils.lua | 452 ++++ loveframes/license.txt | 20 + loveframes/objects/base.lua | 1295 ++++++++++ loveframes/objects/button.lua | 298 +++ loveframes/objects/checkbox.lua | 429 ++++ loveframes/objects/collapsiblecategory.lua | 328 +++ loveframes/objects/columnlist.lua | 984 ++++++++ loveframes/objects/form.lua | 303 +++ loveframes/objects/frame.lua | 1111 +++++++++ loveframes/objects/grid.lua | 358 +++ loveframes/objects/image.lua | 385 +++ loveframes/objects/imagebutton.lua | 343 +++ loveframes/objects/internal/closebutton.lua | 159 ++ .../internal/columnlist/columnlistarea.lua | 469 ++++ .../internal/columnlist/columnlistheader.lua | 203 ++ .../internal/columnlist/columnlistrow.lua | 218 ++ .../objects/internal/linenumberspanel.lua | 161 ++ loveframes/objects/internal/menuoption.lua | 218 ++ .../objects/internal/modalbackground.lua | 79 + .../internal/multichoice/multichoicelist.lua | 420 ++++ .../internal/multichoice/multichoicerow.lua | 157 ++ .../internal/scrollable/scrollarea.lua | 204 ++ .../objects/internal/scrollable/scrollbar.lua | 358 +++ .../internal/scrollable/scrollbody.lua | 192 ++ .../internal/scrollable/scrollbutton.lua | 139 ++ loveframes/objects/internal/sliderbutton.lua | 228 ++ loveframes/objects/internal/tabbutton.lua | 205 ++ loveframes/objects/internal/tooltip.lua | 353 +++ loveframes/objects/internal/treenode.lua | 296 +++ .../objects/internal/treenodebutton.lua | 108 + loveframes/objects/list.lua | 807 +++++++ loveframes/objects/menu.lua | 287 +++ loveframes/objects/multichoice.lua | 418 ++++ loveframes/objects/numberbox.lua | 485 ++++ loveframes/objects/panel.lua | 134 ++ loveframes/objects/progressbar.lua | 318 +++ loveframes/objects/radiobutton.lua | 429 ++++ loveframes/objects/slider.lua | 514 ++++ loveframes/objects/tabs.lua | 765 ++++++ loveframes/objects/text.lua | 802 +++++++ loveframes/objects/textinput.lua | 2136 +++++++++++++++++ loveframes/objects/tree.lua | 342 +++ loveframes/skins/Blue/images/arrow-down.png | Bin 0 -> 344 bytes loveframes/skins/Blue/images/arrow-left.png | Bin 0 -> 337 bytes loveframes/skins/Blue/images/arrow-right.png | Bin 0 -> 336 bytes loveframes/skins/Blue/images/arrow-up.png | Bin 0 -> 366 bytes loveframes/skins/Blue/images/close.png | Bin 0 -> 252 bytes loveframes/skins/Blue/images/collapse.png | Bin 0 -> 199 bytes loveframes/skins/Blue/images/expand.png | Bin 0 -> 221 bytes .../Blue/images/gradients/button-down.png | Bin 0 -> 240 bytes .../Blue/images/gradients/button-hover.png | Bin 0 -> 240 bytes .../Blue/images/gradients/button-nohover.png | Bin 0 -> 218 bytes .../images/gradients/button-unclickable.png | Bin 0 -> 219 bytes .../Blue/images/gradients/frame-body.png | Bin 0 -> 235 bytes .../Blue/images/gradients/frame-topbar.png | Bin 0 -> 241 bytes .../Blue/images/gradients/progressbar.png | Bin 0 -> 199 bytes .../skins/Blue/images/multichoice-arrow.png | Bin 0 -> 284 bytes .../Blue/images/tree-node-button-close.png | Bin 0 -> 166 bytes .../Blue/images/tree-node-button-open.png | Bin 0 -> 179 bytes loveframes/skins/Blue/skin.lua | 2110 ++++++++++++++++ .../skins/Default/images/arrow-down.png | Bin 0 -> 181 bytes .../skins/Default/images/arrow-left.png | Bin 0 -> 196 bytes .../skins/Default/images/arrow-right.png | Bin 0 -> 197 bytes loveframes/skins/Default/images/arrow-up.png | Bin 0 -> 177 bytes loveframes/skins/Default/images/check-off.png | Bin 0 -> 202 bytes loveframes/skins/Default/images/check-on.png | Bin 0 -> 223 bytes loveframes/skins/Default/images/close.png | Bin 0 -> 241 bytes loveframes/skins/Default/images/collapse.png | Bin 0 -> 166 bytes loveframes/skins/Default/images/drawing.svg | 519 ++++ loveframes/skins/Default/images/expand.png | Bin 0 -> 177 bytes .../Default/images/multichoice-arrow.png | Bin 0 -> 241 bytes loveframes/skins/Default/images/radio-off.png | Bin 0 -> 429 bytes loveframes/skins/Default/images/radio-on.png | Bin 0 -> 365 bytes loveframes/skins/Default/images/slider.png | Bin 0 -> 477 bytes .../Default/images/tree-node-button-close.png | Bin 0 -> 212 bytes .../Default/images/tree-node-button-open.png | Bin 0 -> 223 bytes loveframes/skins/Default/skin.lua | 1788 ++++++++++++++ loveframes/skins/Orange/images/arrow-down.png | Bin 0 -> 344 bytes loveframes/skins/Orange/images/arrow-left.png | Bin 0 -> 337 bytes .../skins/Orange/images/arrow-right.png | Bin 0 -> 336 bytes loveframes/skins/Orange/images/arrow-up.png | Bin 0 -> 366 bytes loveframes/skins/Orange/images/close.png | Bin 0 -> 252 bytes loveframes/skins/Orange/images/collapse.png | Bin 0 -> 199 bytes loveframes/skins/Orange/images/expand.png | Bin 0 -> 221 bytes .../Orange/images/gradients/button-down.png | Bin 0 -> 240 bytes .../Orange/images/gradients/button-hover.png | Bin 0 -> 240 bytes .../images/gradients/button-nohover.png | Bin 0 -> 218 bytes .../images/gradients/button-unclickable.png | Bin 0 -> 219 bytes .../Orange/images/gradients/frame-body.png | Bin 0 -> 235 bytes .../Orange/images/gradients/frame-topbar.png | Bin 0 -> 214 bytes .../Orange/images/gradients/progressbar.png | Bin 0 -> 199 bytes .../skins/Orange/images/multichoice-arrow.png | Bin 0 -> 284 bytes loveframes/skins/Orange/skin.lua | 48 + loveframes/templates/base.lua | 1 + loveframes/third-party/middleclass.lua | 183 ++ loveframes/third-party/utf8.lua | 1045 ++++++++ main.lua | 59 +- time.lua | 39 + 107 files changed, 25454 insertions(+), 49 deletions(-) create mode 100644 font/JosefinSans-Regular.ttf create mode 100644 font/OFL.txt create mode 100644 loveframes/changelog.txt create mode 100644 loveframes/init.lua create mode 100644 loveframes/libraries/objects.lua create mode 100644 loveframes/libraries/skins.lua create mode 100644 loveframes/libraries/templates.lua create mode 100644 loveframes/libraries/utils.lua create mode 100644 loveframes/license.txt create mode 100644 loveframes/objects/base.lua create mode 100644 loveframes/objects/button.lua create mode 100644 loveframes/objects/checkbox.lua create mode 100644 loveframes/objects/collapsiblecategory.lua create mode 100644 loveframes/objects/columnlist.lua create mode 100644 loveframes/objects/form.lua create mode 100644 loveframes/objects/frame.lua create mode 100644 loveframes/objects/grid.lua create mode 100644 loveframes/objects/image.lua create mode 100644 loveframes/objects/imagebutton.lua create mode 100644 loveframes/objects/internal/closebutton.lua create mode 100644 loveframes/objects/internal/columnlist/columnlistarea.lua create mode 100644 loveframes/objects/internal/columnlist/columnlistheader.lua create mode 100644 loveframes/objects/internal/columnlist/columnlistrow.lua create mode 100644 loveframes/objects/internal/linenumberspanel.lua create mode 100644 loveframes/objects/internal/menuoption.lua create mode 100644 loveframes/objects/internal/modalbackground.lua create mode 100644 loveframes/objects/internal/multichoice/multichoicelist.lua create mode 100644 loveframes/objects/internal/multichoice/multichoicerow.lua create mode 100644 loveframes/objects/internal/scrollable/scrollarea.lua create mode 100644 loveframes/objects/internal/scrollable/scrollbar.lua create mode 100644 loveframes/objects/internal/scrollable/scrollbody.lua create mode 100644 loveframes/objects/internal/scrollable/scrollbutton.lua create mode 100644 loveframes/objects/internal/sliderbutton.lua create mode 100644 loveframes/objects/internal/tabbutton.lua create mode 100644 loveframes/objects/internal/tooltip.lua create mode 100644 loveframes/objects/internal/treenode.lua create mode 100644 loveframes/objects/internal/treenodebutton.lua create mode 100644 loveframes/objects/list.lua create mode 100644 loveframes/objects/menu.lua create mode 100644 loveframes/objects/multichoice.lua create mode 100644 loveframes/objects/numberbox.lua create mode 100644 loveframes/objects/panel.lua create mode 100644 loveframes/objects/progressbar.lua create mode 100644 loveframes/objects/radiobutton.lua create mode 100644 loveframes/objects/slider.lua create mode 100644 loveframes/objects/tabs.lua create mode 100644 loveframes/objects/text.lua create mode 100644 loveframes/objects/textinput.lua create mode 100644 loveframes/objects/tree.lua create mode 100644 loveframes/skins/Blue/images/arrow-down.png create mode 100644 loveframes/skins/Blue/images/arrow-left.png create mode 100644 loveframes/skins/Blue/images/arrow-right.png create mode 100644 loveframes/skins/Blue/images/arrow-up.png create mode 100644 loveframes/skins/Blue/images/close.png create mode 100644 loveframes/skins/Blue/images/collapse.png create mode 100644 loveframes/skins/Blue/images/expand.png create mode 100644 loveframes/skins/Blue/images/gradients/button-down.png create mode 100644 loveframes/skins/Blue/images/gradients/button-hover.png create mode 100644 loveframes/skins/Blue/images/gradients/button-nohover.png create mode 100644 loveframes/skins/Blue/images/gradients/button-unclickable.png create mode 100644 loveframes/skins/Blue/images/gradients/frame-body.png create mode 100644 loveframes/skins/Blue/images/gradients/frame-topbar.png create mode 100644 loveframes/skins/Blue/images/gradients/progressbar.png create mode 100644 loveframes/skins/Blue/images/multichoice-arrow.png create mode 100644 loveframes/skins/Blue/images/tree-node-button-close.png create mode 100644 loveframes/skins/Blue/images/tree-node-button-open.png create mode 100644 loveframes/skins/Blue/skin.lua create mode 100644 loveframes/skins/Default/images/arrow-down.png create mode 100644 loveframes/skins/Default/images/arrow-left.png create mode 100644 loveframes/skins/Default/images/arrow-right.png create mode 100644 loveframes/skins/Default/images/arrow-up.png create mode 100644 loveframes/skins/Default/images/check-off.png create mode 100644 loveframes/skins/Default/images/check-on.png create mode 100644 loveframes/skins/Default/images/close.png create mode 100644 loveframes/skins/Default/images/collapse.png create mode 100644 loveframes/skins/Default/images/drawing.svg create mode 100644 loveframes/skins/Default/images/expand.png create mode 100644 loveframes/skins/Default/images/multichoice-arrow.png create mode 100644 loveframes/skins/Default/images/radio-off.png create mode 100644 loveframes/skins/Default/images/radio-on.png create mode 100644 loveframes/skins/Default/images/slider.png create mode 100644 loveframes/skins/Default/images/tree-node-button-close.png create mode 100644 loveframes/skins/Default/images/tree-node-button-open.png create mode 100644 loveframes/skins/Default/skin.lua create mode 100644 loveframes/skins/Orange/images/arrow-down.png create mode 100644 loveframes/skins/Orange/images/arrow-left.png create mode 100644 loveframes/skins/Orange/images/arrow-right.png create mode 100644 loveframes/skins/Orange/images/arrow-up.png create mode 100644 loveframes/skins/Orange/images/close.png create mode 100644 loveframes/skins/Orange/images/collapse.png create mode 100644 loveframes/skins/Orange/images/expand.png create mode 100644 loveframes/skins/Orange/images/gradients/button-down.png create mode 100644 loveframes/skins/Orange/images/gradients/button-hover.png create mode 100644 loveframes/skins/Orange/images/gradients/button-nohover.png create mode 100644 loveframes/skins/Orange/images/gradients/button-unclickable.png create mode 100644 loveframes/skins/Orange/images/gradients/frame-body.png create mode 100644 loveframes/skins/Orange/images/gradients/frame-topbar.png create mode 100644 loveframes/skins/Orange/images/gradients/progressbar.png create mode 100644 loveframes/skins/Orange/images/multichoice-arrow.png create mode 100644 loveframes/skins/Orange/skin.lua create mode 100644 loveframes/templates/base.lua create mode 100644 loveframes/third-party/middleclass.lua create mode 100644 loveframes/third-party/utf8.lua create mode 100644 time.lua diff --git a/clock.lua b/clock.lua index f6a2ef2..631601f 100644 --- a/clock.lua +++ b/clock.lua @@ -1,41 +1,6 @@ -local MAX_MINUTES = 60 * 12 - -local Time = {} -Time.__index = Time - -local function newTimeRaw(rawMinutes) - local t = { - rawminutes = rawMinutes % MAX_MINUTES - } - return setmetatable(t, Time) -end - -function Time:new(hour, minute) - return newTimeRaw((hour or 12) % 12 * 60 + (minute or 0)) -end - -function Time:get() - local h = math.floor(self.rawminutes / 60 % 12) - if h == 0 then h = 12 end - local m = self.rawminutes % 60 - return h, m -end - -function Time:getHoursSinceTwelve() - local h = self.rawminutes / 60 - if h < 1 then h = h + 12 end - return h -end - -function Time:addMinutes(minutes) - return newTimeRaw(self.rawminutes + minutes) -end - -function Time:fmt() - local h, m = self:get() - return string.format("%2d:%02d", h, m) -end +local Time = require"time" +local numberFont = love.graphics.newFont(100) local function pointToTurns(x, y) local rawTurns = math.atan2(y, x) / 2 / math.pi @@ -68,17 +33,58 @@ function Hand:draw(turns) end +local function drawFaceCanvas(r) + local oldCanvas = love.graphics.getCanvas() + local canvas = love.graphics.newCanvas(2*r,2*r) + love.graphics.setCanvas(canvas) + love.graphics.push("all") + love.graphics.translate(r, r) + love.graphics.setColor(0.93, 0.8, 0) + love.graphics.circle("fill", 0, 0, r) + love.graphics.setColor(1, 1, 1) + love.graphics.circle("fill", 0, 0, 0.84*r) + love.graphics.setColor(0,0,0) + for i=1,60 do + love.graphics.rotate(math.pi/30) + love.graphics.circle("fill", 0.6*r, 0, 0.01*r) + end + love.graphics.setColor(0.87,0,0) + for i=1,12 do + love.graphics.rotate(math.pi/6) + love.graphics.circle("fill", 0.6*r, 0, 0.015*r) + end + + local font = love.graphics.newFont("font/JosefinSans-Regular.ttf", r/6) + love.graphics.setColor(0,0,0) + for i=1,12 do + local s = tostring(i) + local h = font:getHeight() + local w = font:getWidth(s) + local tr = love.math.newTransform(0,0,-math.pi/6*i+math.pi) + tr = tr:apply(love.math.newTransform(w*0.5, h*0.4)) + local x, y = tr:inverseTransformPoint(0, 0.72*r) + love.graphics.printf(s, font, x, y, r) + end + love.graphics.pop() + love.graphics.setCanvas(oldCanvas) + return canvas +end + local Clock = {} Clock.__index = Clock -function Clock:new(time, diameter, transform) +function Clock:new(time, diameter) + local radius = diameter and diameter/2 or 300 + local transform = love.math.newTransform(radius, radius) local c = { time = (time or Time:new()), minuteHand = Hand:new(240, {1,0,0}), hourHand = Hand:new(180, {0,0.5,0.5}), dragging = false, - transform = transform or love.math.newTransform(), - radius = diameter and diameter/2 or 300 + radius = radius, + onSetHands = nil, + transform = transform, + faceCanvas = drawFaceCanvas(radius) } return setmetatable(c, self) end @@ -94,11 +100,9 @@ end function Clock:draw() local _, m = self.time:get() local h = self.time:getHoursSinceTwelve() - love.graphics.push("all") + love.graphics.draw(self.faceCanvas) love.graphics.applyTransform(self.transform) - love.graphics.setColor(0.5, 0.5, 0.5) - love.graphics.circle("fill", 0, 0, self.radius) self.minuteHand:draw(m / 60) self.hourHand:draw(h / 12) love.graphics.pop() @@ -122,13 +126,13 @@ local function clockPointAt(clock, x, y) dMinutes = dMinutes - 60 end clock.time = clock.time:addMinutes(dMinutes) + if clock.onSetHands then clock.onSetHands(clock.time) end end function Clock:movemouse(x, y) if self.dragging then local localX, localY = self.transform:inverseTransformPoint(x, y) clockPointAt(self, x, y) - -- TODO update clock hands end end @@ -136,7 +140,6 @@ function Clock:pressmouse(x, y, button) if not self.dragging and button == 1 and clockContainsPoint(self, x,y) then self.dragging = true clockPointAt(self, x, y) - -- TODO update clock hands end end diff --git a/conf.lua b/conf.lua index 9fda08f..b7a8741 100644 --- a/conf.lua +++ b/conf.lua @@ -1,3 +1,4 @@ function love.conf(t) t.window.msaa = 3 + t.window.fullscreen = true end \ No newline at end of file diff --git a/font/JosefinSans-Regular.ttf b/font/JosefinSans-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c116243c3f19560336b1a723c000554735b368b9 GIT binary patch literal 59880 zcmeFa2Y6h?)&D;;ceRpLtuD*zU9u&s7t2M}RjzWwxXH3yuv~DZ7n@=*J+vhB7D5Rn z0Rkq55CVh_rh~vn4lR@gW5pP({eNce-IWX`A@Bcr-@L!~iB{javuEbc%$aiL%$d1& zg%m;z#Bm8RwyAl{gu?L~giv)t$ZN(qPj_l`j^MH&TN=;d{wXz5ye6T zx~H@bD?L46);q-AEreLqI-`EZhufb`=KGa=AJ@LBZS6b3=ME4e=nf&=Tb8x0UkiO8 z;W1o;mUSM#^lt0P^+KGGAjFy%mv^)+i7kC2mGDJ`S1yMTxZm|1-$(F0Yx$}T$Msx# zYL^hnCkZj&jLtRfZFA4ubVvwmHw-+xs_nS7>Ui;c;wKS5ZFSqKj`tpocv6VCYRcQN zcFp({R9Si9VP-kHP?g%J3A={@sq*ZF)E((4rwT!rco3q+upBi#C1 zzd!w5hkx#M3lXs0dv|YGz>M$35o*4nDA90SUEA)35hL~s%lb&Cvg?C{sruSge8K_m z-QMVc8Ln&j>J~~<`O~QfnQt-1%@S(!vgI3eAy#Z?>y&YX$IxmPS0&?}d#DP0N(Rb{ zxIB#Cr84mc@aTPM;c`e>7~* znGTmHsGVHW?A*mXP2(@hxYCrN2tTb#Yg0Z|q?+NvQmLwtl2oZC5up~Tc9BeIs2Zk< zRf#H9<*GuBQDfCOHC|0rE!UY*kQ9FqJ8_@nBgHd(q}a_z zioJZK_&|J!`xzf8_VJN2NDjb_kn|cEC8KdOCFPXaG8;Ef=HU*L#kdu+61PUy;I_(E z+}Vs%MRu6Et#y5IGf>v`8(u1{P&0V*IoATb~( zpfq4q!190%0owzv2)IAsv4EEY-VOL9pvSG;;qDZ7rF*t}o%X@WsJb2j3a|V2BI}3mFuW6;d2BBIK7L zZ-jgjvOiRYhK44DjtCtWIwN#ZXlLk2q1!?)4ZSY(j?mwSJ{9^#=trRk!h*sQ!m`4O z!`6qL8n!*`y0AyXo(+2=Y;Tw+JUl!nyfl1N_=NCT;fuppho2CBR`^}vJHnp~-xU!N zF*qV8q9URxqBUZ1#IX@4MQo4wMZ~QU4@5i>@mj>5h|eOv85l5d;K0EH*A6^!;JE`Y ziwuh#6xkZNCGvvEpGV#lc~|6)$o)}uQ7ut(qLxH$i28NZeNm4_Jrng>)L)~%j#kl; z(P`1cqK8M1iJl(4AbLgghUinHUy6PwCNicX=8TvNV}22HbF7RFi!F&A89P39Mr>Pb zXYA(KEwLBH{xbHK*x$uI68m)QtFa%&?u#potBz}on-kX_cS_tjaW}@@9rtkDQ*pcE z-i!MpUd7kNcf=nXe{%e`_)Fs-iT^S|CWI!8OcV%UMwkP}|;nxYjPxw>9 z%L(r%e4cP{P{5$bLFt1^2GtLmI_QBxPY!x{P*-A6;xUPv5>HRODDkSq*9XT8o;>)N z!5askHhBBspAWui@JEC94em`EkQ9@YnsiLksY%CU8GN$(|nlC(eBl^l^g zI5{`DG#I5_3YGZQ{POp(nh4MPTQ9DyR>K0W%|JM z@#$OAuT6h7BQ7I9qJD>ERoHgiVilFap)*Jj?8`At?>R$NwD*3nt3vu@7% zV^&voUH0tktFqtEKA01nQPyKUMyA`IqGfE5a+{DpD$PD~c;dR*b2b zQZc(?Va3Xd^%W;pY^~T{@leHM6;D^ZRmQsvCb#g(U5 zURwF*$~P*#Rk2kWRYg_9tL9a0sXDjn@~RuE?yP#S>d#d#R=rd8QI(!I_3WsnT8x=_ z^ws5F&G#$CY0RB^z6le>2c{9={XthjEIb=jM$9CjFgNa8RIe*Wprde{jEZm z(0^gfm&IbZxXvlrb@DFxI3@c)ej@kDgQ|d8&{wi2DA^m9u-ud^l9FXwIfs?(G)i_| zT69`MT2fk?DOrtEvK!NGp=7tG-9yP9OnbOr$s#G)Ab-i0P%`25swMJe=JR#BfZk9s zv-er;6QcJexyl$_{D|I!y+ z_YZTSy+L)kf^dU$4BwxNTr})I3%)dDmwZ@0CU?rcDqKa$Kgs9h^YT7`jsp27d zrg&6tM<06%?fPkXnfQymRGcKoi`(TUktOoPSK?@~NEV7E;uu*a>STyGQ%*#ntVm0$J>yQ^jC4;+K zDltO3MUgmwOgtz`#J8+RzC(6@Bc`!>n<5j%@p6nfQH~R9o!B7j#j$df zI9W~*r^*&_nw%s~my?nA6UD7^y|_(o6nDtY;y3bmahE&+>2adCQywS&Brgz;$@9hI z@1yjZ>{UyyIeH|6Wh2ubqy@*`%4zZyyGksr&iU#bxKjqFjOio(jvjn-{T zreHZru_|jC(=tOQcD8L;4ZmNDp!&JZY2uy6`Wb2B@y6-6cTB9GnCK#56F1e zR968jpE^E4>UlnESd5p&wTuhSW*@&s1B+%eQpl1O!+2v!TRw&bY=xCLrH zZn~O>o54N480{v;ViTjy#8_lvz&)})$K;_)rbMrZ`>PDZjQ*GMMDj2e=n04QL|qb>*d(SiyM&wmqH{&!n!H`)P441G zzTYgK=Bj&?j^XQ3dYmhhqA-11r=jnygB~NW-z?ra`)D%u`1 z)ZB|*$cdp_JeV*&rgfi-(k(BaWIQPuEeDy@?fRH3vdjq4y-SZ4dYHTeJq^8$b1hiV&u7wKR^Vdr`dGoLLVzt3|5`U*9iop=cmRC;H?+kJ(B(t4Qak-!X|hmT<>L?)&HIPbc;=;&xKX zbw43~3n?#ShTrfL;x>!ph_{ZE|CPIDkh-onAIIOXf&TpUrF*2jd@0R_$Ddki&DjRA z7TsVNpY^onI__NyZ9P3?J^oIvYoIP8e2N$YZ+1TGMH=7MQ1T7dz(BiH57 zbWclTRqSik_0CvX=JcD5^rRxwTB{f#IwxC3t~a^0Q~!E&5Bpx;zPk2}phDAH>&a91 z?R?YE`+BCX1Ks=A(SPkx3u;NjsPoEEVu3gT(P<=SJ&8A z{FW^7ehyx;{bDiKML>ZT=w7aaWuyql{|&olmWKKjX=tn_&A08VTIyUkLOT}!Qgn-J z@i&X*u6ymP_8a7gqpS*%>>BTUKT6bE{}Y%?J{rEf4v0q8N?C!mnY#NK{=?C3zK;IksLa^GN4teQpH5Ae2FsD27QBi@nlWB0xw@-5E~p{^4d>bD~4pW-RX+8+}{q5A2N zKPm1MF|2<)t4I`TsA<@so)U#e0%3(J9sJhBD|Dp^0~N&gABFer9}oN9eZiE;PA3c7 z)lfBy@cyWBzUPZ+D&Kn$yu>MX&c`@D{imeC~u1?)?IPj;6^2CcaxLZ!h2X zU@uIy;q8`R!Mnz{COw_zG|Hi`!{l7@RD2H+F;doV=`5{IsJQC#L8&!v;9bK`hr=d7O7I*G%jtL%xR`{aqa;hGN4m z1nJII`wLk~Px~GkzW05aDk9F2(Er|?zI52Zk5)JQ5b`Avt;7B)UJyyLAJna^g-#Yj zU1xK>1&pU3HQC@SNIJIBboD;-4&}if9jMl@${a5$sJna>!Zn_`B1F{lJx6{lQt>CL zK_bV*3#U$gCYo6LRmm+Pi*;|P)hSA>A)s26$|)iRd$tg_i43`yIr1K6!Do=gVO;;h zTIOj{pc=5H-Aec~A_|L4vTPNj#Z6*}c*grR>#ay^7#;e4lSUimT`%e+a~CKh@1lBvGR-74hnGGZ#dtRU%O>;S|eckcm7#PE>1or{x;9 z_+$^vsdww$i;RY zX4Q*dG7g*6OX3;Qnxu+JlQv_19POIM9>?>d$z@UgS1DTo?NcjCttsqrd_bGk(|?mi zHfzjzlxGaOM!GB!aRKN}@@;V}Ei?gWi-@*;&IZ~_p%Dj4!2&QEps6tag*oM;>1Ci9 zP>UuFZ4D>^@v(`Rusp6h{ZQabU+@3vc$2_5p!4vh--=&{>2m4v{V?rkSd*jQ z$r$?K#q>A&4QFDevz8w!uVs(zE!O){=mED8zMeXoL0h(pN%B$po=#hT8YoK|Xo8{u zf8ML0AK_1RK+IxCMoCM$WPo(bK=$bLZd|Yok)iA_EtcWzF+|9LGEzo~c6OD1!(LE~ z$VS>8VqaGad5Wv0x+GLxO$17u3vYfHDP%dHzaxr^dmDoY{if?5HR;p!kIr3qJ zJO&$6C$rKk>`<;2uS#t5a;aa zG2Sj`uj~qWB`2AF!EW6z(a5jEdfv=>vR880&{);RvMYJ5l=3=xJw0))wuZ6OWZT1j zC2y6#X3yz1tjWjrv$@?vKc67JVUP5;?2_ImCbC=m0Bhyf*_--3`=Af9r}mKC!Oq*m z?7!}0Pxw*xQYW!z{3muCAD4e-Z|ezd>yv+xPqRBZ6&d^tClvHP@(b)sy~G-HI(uI) zv-h=&-Pl*a_OHE|H>Fa_QZ8|nn5zPmTLq$<9E~LSl)3gH6|6$o9Sc+8$g>FXp&F-iVbvl6l|;_CSJ>;ZdSNC94!9(;`NC9hUJ>@mp~(QZbdi=iAsle?U$C?MdnCk# z>^Y~3%h;j+8N1qT%u$z!t2jSWE`EW%|7KNzmHY`avkYJl{4DnK&t+d{t5_&L5?jP$ z%#HQ`iY;4BQj^(@pUNKWbarBAun#+nJ=i(y#m;3ncAlEA7N~`4k!n+mRl8cEI#|7& z&+h9Uc7EUBB*8nPkv;Rb*e~xAZ>nW#xmux)Q7cuaTBTO2HSYSw>pC`d1a4ftqNKUL z*}gVZI@e<7TIyWO?Q6a7+UR_D;@4L@-|O|YxU|^0zutE>=|C?HtY6jEzHZIx!1^`I z)~xPW8C<_^#p-2k?Hf0A1lBj3Ye-}JigoQ9S1s-AI4-zx$(jvq?d=__H<*-58q3{H z?QJB$W!;)KAGN~WY}j!(n?SoX4Gve0PAMCm(lk0;H5zUxRe5mpVcC>4H#iJ6_!z1T zY<3FXY!}?gqR~Cp?5Ixa zC5`p&$#&Gq{i2pvSk0@K*)eOHoI4uaQ~bp(X>M|=vdJlSlT)Qlrb-F7%TiiwI!bYA zsZ)<-z9w)wP-Anzl;vyIt=5@vm&1IsFEuAtlhcsR#bHyHZ=}1d+qkN;ZKKUhX>oJl z6sL-G=c6}=Oj+OAwtl(Yt4xP1ZFEn!8J*sb(F&)OC8kuxr6r~ARue0v^?Q|DTH-KT zV~SE-Qa#2sgC=#)=$Blj)5}Zh-821lRb0|kW~#8X#HpKR-?cJeW*_g(P6lI~8fx~{ zg;NL3&0#Zt$a_g;;7o`2nRfRGn5hSpd#33m?%6gwv-{W?Fnh_0j&&XDSFCr>Ube1n zQ%A^AeSvl}j45{?WrCcqPA!!=tum(CJ=Y`~JlEg9-EDq`ssAzdjSW@KwZyraiePY6 z*x&1YSJTJ1&xv1Ol>riqYt>(`eYBm=(bt{`4J=9Znj2oKyvNI3?~l zOpMs0thA!Wz0BksvaGMvrV>g@%Yv8rQ+F-b;$(SW9QO);{Zo*d0V|61X$Vf1*yU(6 z`6E?Kd5F=VRvZ(!!YRrMN3g6gea5cyvZ|0{`jWScP*xSXa@o3$j@6xQtCy^3cXyf! zc6a*g3Mtd*>ZFu*{KgvhYP$_qx9P_%)~#8)yu-b^U-a@ytHY5rrB(LmDQRqUukka3 zOmJ$u$*D?vG(mSdPm^gCSaPbc)T!z+Un@DCt8q-gn!eH2tR|NoH}UsU8@2%_VL*4)YurOCYpUbJG?fJ3ETKX9!n^xk4HzM zY%~&Oqb*T3+r{48SL^|s{SsxfEm4l|3$**+m2yIj#&oZ;8Y4%G%NiO7=z~5*+A$%;4R$v#Zm_#laf8XHw79B# z@Y;@bE7mO0`UFC7i5VrF(JE@^3{u>Y!|WvM?e0}vU#uFZYZ7CqBCLH)=bF{4&|@~V ztvlYeWXYGlMs|I#;Y~b8a$Xoj@bj39NLl?O4zKPOxb!f=zZ@4JSmi zuXGL*&uMukEF+ssON(t8O_@x13G;&Pp=GvO!L@3DssHvhs}>J1Rjqwa9DBr+p`6+G zn4)oyFOB*Ers@0LQ69E@&6<^Mi`Q)G=tnhUr?|}N<7FjIdL<2^wCduH&NZ9+B9}Ui zXERV-R%&;NvQk^`DJ!+-*)n?=7nhY)ggOkFwsO8ynJ?jf*6go-{`yC4=>Mg(|Ch%8 zUn={5sW)H3{oMBtD>q-F4y%X$;bZ!JDJkjy#V$!?|2pXxTxut5Gg#WcIHfkXPDpkC zdz$-wDYG*(ZCPq}v*Oamnh?ACDrwh}e*WTq{{C^w9C~TL_}cG_ul>IG+F$0HJhP=m z+e}zcvp&mX-D=K6ig4#lq&}yl&jH%!VmPU@vSZz9k+rIA-Aa+NYUQex=472dC8JLd z>U4BU8UZ1vsK?}YtnoO##b(1O3dG{j8bq9#WK7 znWv@n*@<-N!j64_^R%CGu6j2srB|?_JjE%chgmV+%?k1+aShKBT*4~uEO8opz8lyn zTrL)~;+@4xeF9boDfU}+q#CNaaoy^6++_6t^v|_l>{t5S*RRyyaQ~pT<9=kV#=TWt zi2J0v9QO_Nm~n5$-J_1jU8&x~Jr+xzWS`}CxVzPhxa+VdO7Xb5iCltA%Ga?ABgL<= z$4XY*`uVoU4gD|bV*K|j{T$mad@CJApJPV!xkAjE5@4#_j9q0s0!6Lxf`vEh+WPn|7Km))=IG_?>4;+B~Z9pjC zY?eM^8FWy$JEx8cF~aqKBGA`%x+h%6N74qNeEQm86c(jY>~}dL&71>#$a}1A3-3tc zUhmcCua5Fo;J)b9=kZo~m*GC--Du)eUzlaJJ)Yqx8lD6TxCKp$9IwOor~`b<2wZ(y$hHA zUmmu0%+3r>Q-PMR;S|6 zmvN*y;VD@41pdw5FSV=X6(<>Q#og{bNa!JRvUjhExmWwKE9<-dZo8U-Ess;rST=QN z6qZ(r?fh|E`iS3dzqjpXS9Dc>_`Mw-xH+H{>V zPn~Ef$`eM~)pT*Hj*qL;{KQbUSo%cfH-_?!q0q`u&Nco+I%UodY07DaLT|;tjolp5 zH~y0>J?H2>4qU?#J&8Cwb$t1_DO-RE4K<~Dft@9(Mw-w(lV-Pxf5?SChjuhUuNiD zliF%cQJXDJUdz>bhGK_eg?3HMOcOIhw~ox9??|b83|yO-_Zk0vCQhvJ#~S}I;~!@H z-x>dR#?J`j-aCx{PMwPyZpv_{rnC9dK@2L!+tE~x@C+F{uDiwFA3Qr2P5b$t9@9HUHSF=|-JK&nMaDDc@;d!=IZuy;G206E zAOyP-LOu(g0FQ!)!0*6s0CmgL3qoE6=&S5B3wbU$gSt3{t%T#iI?xH03QI2HIv32~ zNdW4Qy(l3YzzBd$XP-;R0+0oejWPjHYcdqL0oBEmL;9&Qf7obZ3ujHzkbWe-fdZ<+pZEwS_)0zz>|t5a}4XV*o_EcSY&xSG9O^g4M6 z_amcm-758&_NU~-xUWz*Xm|1v+&kohxI>lJX>V5gd58rn7k9TBg}alnf=;6I(!Ai7 znB1@7M26%EeO(4!UNjTqp04{0dsDickIN^CUugWdvpY)q2eb&7NNw43@P{emm|GRFZL`q#GT*&@|Rsp*DK+3|O zm!5$875LoyjPdXC?&BNq{q_0#`H=kH9(}jh<9*+IJ=aIPH=Fw(_1$N_dHR1l-0$r< z{QLL6c`v6-zqF~|`fSxx56S->?~^)A`;YYJ<>}PJ|Gbxx{v+H$FZVuf zhk11m6W(7N_Xh8?nkVm5;CUyUxZnTNwfAFxc6vV+>Z99b=7bM_-VeQB+jQ^K-Y@n2 zUS<*R-yGU2_SNTdI_Mw#+4b||5xjr3!@RHRtK)9;#rIz5ecAg*==T65gZ}egYFzWp z`-vg_sAKc$zfmNRa&HjO0ERcd+3k*l-f;=cLte!m8fXy3I+nsdbkrv5SxC*QYJW~GeteUicx-${Jp@Xw&?`02ch<2TVy<=qkaLFBUo6T_=R zp9rZ7sSG|4{FVRnQSiILZv@{T^rHKq`wjQ~?wjn7>vPu|KELm3)(=tY4c_7Mta^gy z6iaDgJum5}8@0Y+kEy|COeJvwC7;oxpIuMG_R&Po)^FCyG(8~8^nh$mTDOZFdipt} zvz;E$%zpp%jHw5Bch1rD;%5lk!)Fy5$zIm-`ib^6LccZVSbdI$Sxvt+X9N0q45N?J zFPx&#z56)RCr+eK)NryvzbWTbw3XT7G}EI`H$8fbc~j0-`otwXm(9ryp1}S!^W7El zc6kTm^e%Z9<5c(PUz&I1Tt#2M$@`hSnUiL>cwdpf!hfsxLwP&bJG^hn-T3!Ff1hhN zCnG=R`Zuu8yGO+$abv|*NVTiMHQ-us9e4l<_j_i92f;&N2Y49l^j;|*0gr+|g2%w0 zz~kW0;0f=QlmdGW?(?|&k<8lvG9&dC?;Vuv03|y>slGO)>ZXK$^?u@%>J|AZ^v}Ep zDcxHt#`_s1dObkf!$yacpvEXik?3|0v`h{;q}b(DfkS00rZ@!XFRPTd=2&k zJ(KIT-~sRrI0*E7`yDt0dVyD~Kw3Ql3Rr;gE(3tp0Wl=WU=RYdUKj?#0jmt7KbCMU z1LdF^pn=Qbpcae(Bf%&z8q|S$pmoqj&;**n7%&!S{d7E-044(TC8M`a;W`ye1Jl7w zFbm8EbHUM|4WP*(cLiscY`u6p*Ym*n-~w`o*Osif zo&(Q=7r=|)CGaxX1zrKKg4e+7;0^F5cniD@-T__UUGN^*4fcTdK{p^*@gdibz{lVd z@Hg-&ptp%HfCqd9_JOa#e$WH{4i12Cz(MdW_zoNby}(Ov6+i+7EZ_nGzzqg~U=RXA zK^O=JKiZyz4F|Pg1Q-cMfzhB2)Pn}l2%11M7z4(FabP@{049PKFd0k%Q^7Pa9n1u? zz-%xV==S_q+R}AcTk3WUI*ii4ZxD*CvSWDs?SG^g8~;bfwdo6#=if25b8Q@HC7C0N61I`88!Fk|(Z~?dwTm&x0 z!eFNx=;h2ilIWm#mNnmV;Cb)@coDn=UIx3sE8tb|8h9PN0p0{}fw#dspbNYU-UGYA z9`HWs2KJ2NVMg&Vqj;E6Jj^H_W)u%Iiia7+!;Io#M)5GCc$iT<%qSja6c00shZ)7g zjN)NN@i3!!m{B~;C>~}M4>O8~8O6hl;$cSdFr#>wQ9R5j9%dAegiB@>53`DgS;fPw z;$c?tFspc&S3S%g9%c^@vxkS-!^7<1VfOGadw7^VJj@;*W)Bauhlkn2!|dT<_V6%! zc$hsr%pM+Q4-d14huOo!?BQYd@GyILm_0nq9v)^753`4d*~9b0)}}S*{huH8KPJcj z9r~CaPsjbAukrt_v*&-OoP7xK=##O$O@?-U7CZ<3yVgDbPW|Y|#?+7M%GA!kbM14a z*|UF(Ve#^Q;LM6&n{|()W&dZi{_kANdcQ&g+5ZDwcN?^yqVM)^`~T>@#f;8>hu-@S zbzbz9t>F8snQhR1N(<}NZ2wl)@68sx4dVa0Wd28U@4rdo`N@{2|BS@{l_Qanbfo!n z8}$FmNNoQn@u=Xah8-6K1@3le!3%Ec4aDzY)1O|X$ z5CTF$7zhUuU?7MDQ6L(`fLIU*;z0r!1a!{H-X}x~NCjyi9b|w}U^J)$^`HSXf=;js ztOjeqT5v2_2iAiPU?bQBHiP59@!$k-A~*@03{C;3g44k1U<=p^&H!hEZQvYmE;t`t zihlTv_XdA0wRvyTH6>Sh@5LVSIJ=O^-Yz)lf|D*d>4K9kIO&3uE;#9elP);vf|D*d z>4K9kIO&3uE;#9elP);vf|D*d>4K9kIO&3uE;#9elP);vf|D*d>4K9kIO&3uE;#9e zlP);vf|D*d>4K9kIO&3uE;#9elP);vvPT~l{^!8+;05p^cnQ1=^m&R`z^mXj@H%({ zyb0a{Z-aM07kC%E2X=!!;C;{yJ_H|ukHIJ4Z{Sn#8TbNtz*k@&_!{g7J>c))0Qd$R z1mA-1z#-5JyzEAB)&q;nJ}fT#u(<5Q;<68m%RVeF`>?j`!`iYBYs)^YE&H&x?8Dl! z&+K9h=UNL!fRSJn7!B$`J!k-ppb0dCF<>kh2gZX5U?OM%lfe`)6-)!u!Avj<%m#CT z*>CaoU=i!VBG!XNtOtu&4;HZ=EMh%a#CouZ>GuyNauQ?~yMR%g%oxDPyBW%FpnOe_ zyU_GFLg;OOr?=gy)8(vz)HXU`0T&1WZV(89zyJ^oLO>`81K}V73T>>|q4#VFc`91ngl1 z>|q4#VFc`91ngl1>|q4#VFc`91h6v;R)aNQEjSje1M9&Cun}wmo56A5cyIzZ5u5~0 z2B&~i!D--humx-dXMi)oHgFC&7n~2C@m}WVfN_tWd57jiJ_L4vN8rk~Q=(0Aw!l{p zTDLOmLRxn#z0oqMXeyQkPQxW*6HEcAAPuC041iq^{yp&TfqxJDd*I&#{~q}Fz`qCn zJ@D^=e-He7;NJuP9{BgbzX$$3@b7_t5Bz)J-vj?1`1ioS2mU?q?}2|0{CnWv1OFcQ z_rO2T-h*?&`QR#g-A?bD|09w>Yu*1YX`ox?-zgD{y@|fkUn=-4?z(;4?A|}m?)@w5 z-oL``{VVL=zrybQD`u4aQ9Q}6zaD9NpFWFGwu2GBgAu=j5x;{Gzk?CKgAu=j5x;{G zzk?CKgAu=j5x;{Gzk?CKgAu=j5x;{Gzk?CKgAu=j5x;{Gzk?CKgAu=j5x;{Gzk^Zy zM|#G`CTCx-_m!AZFhXu(gxtgkxrx&nlCh+K1zaEixIrKY0s}xW2mzrW41|LSFc3t7 zC=d-|KrDy@@gM;V0-S}UrzTQQSMlu+%wId1ji01OzF$6{gj#I(Yx>=Pr}gbWrw;z{ zsRONBmLn1OArbc>5%(bx_aPDYArbc>5%(bx_aPDYArbc>5%(bx_aPDYArbc>5%(bx z_aPBEsRP!5^V~6kIO>L@ZaC_O zqi#6rhNEsc>V~6kIO>L@ZaC_Oqi#6rhNEsc>V~6kIO>L@ZaC_Oqi#6rhNEsc>V~6k zIO>L@ZaC_Oqi#6rhNEsc>V~6kIO>L@ZaC^@j@!rHS`S)Y4_aOiT3!!YUJqJc4_aOi zT3!!YUJqJc4_aOiT3!!YUJqJc4_aOiT3!!YUJqJc4_aOiT3!!YUJqJc4_aOiTAtZO zM7H;!>Gh!L^`PnXpy~CX>Gh!L^`PnXpy~CX>Gh!L^`PnXpy~CX>Gh!L^`PnXpy~CX z>Gh!L^`PnXpy~CX>Gh!L^+-n- zfqKvY8bK3i24lcjFb<3d6Tn2!0w#kgU@Djfrh}Pa7MKm@f-T-R(FZlq~T6mGfa|fHT2a;A~E71&U_uJlAu_POMaVZE9k2)hELu(T?9l6aK)&>coFO{qQQR zL;8*fu=wh`e0?zpdzO#$E#7y??_-mSK5>?YbG7=C{6YjTLM)S+R+WrSk55mNBiyof z&8N-12jQmET+|^wC{${&ZW#`J5)#xX zrU&xA=Tv!*KmDQo!p|}37sy5E!%jWBHueiYizg=oRh~FWrTN0G8~ow3#5NN?i{Ibt zbW`8{^se;NXYt#0{(7(;_tOh__u~it__z7#O+4`t>8H=} z)8~jASRd$o^VOgF<$DzGA2Q9>EtRyH}xN-0({}t@BR7I@$B}| zSPa8>qHz;XREF?I$v7eE(_{UgXtz6%r(`V%yk>KI?`u-_dS!L*vTzkBdw;n`zQ_`& z_dT_1LD&3u=c{GG@#@gSYFBUJB=R%qT4$19A|sK0pz3(rt0k5*lJpbL(L7<3OMazs zu`%S6o1$W4!c}HwWOQj|MR`tUW-K1<(_Wde>g4kIqr=BLXjJ#(BW=XxhLDcOWkkjQK6~C=C>nt z>;z)}!HykhVt?esc3q@)`SOsLAYtu126{iG#dKe3F@00C`g>(;`f~YN?{+z<_qTFu zZ<5+I|DE}}=R0|~m>!pJQkf!^O!U+5qf9n^syNHkqeIAHKX__$FDv{duC3C!U=9t;_u3`j;$q_$=PjT;LDa{l>0` z89dFYC6-+etNiqtJelUzbj^=xGdsTF#~=SZfBaee(xk6`T8xCT;}?i~u-y34zuF(a ziQf{{63NbYqMts8U*;?|`R1!*`{jF-ewxT1|8{@;I!@0_ae9eg6DM?KG0(Hc{EN3}ibHC>Msn?8--<HJEl_iKOrHa~r)9Lm#W_Sm_}9y|4snUU$B3|HN>sQ1jaHhH4jb*NB|?EMq6@(Fzu z(#Q{MEO%JEaoE&kcE9_UtM?A2t8Hz)XL0ihs%Ct5|Jx~tZq1u4U2dKggU?ppjjf;b zhc5nNQWdRbv`ZTea;VU>r+1~QG^2m4zJoV2bLPuVNtT&$Z0KqVziOh#u|*RWTY4PZ z^r`#;3i41tB`s^sxU=c4-aqR8$ZtXL{F@mMnx3m>dH-aO2i}vV$AeBU$I|1$zHf&2 z&t^OOCNpcp@q#xiqgOvZOjCDkdX5D{6FYTiffEC7E?m(j8ZnnixMQZdh`Tb(^Vs z?>FQ%%F<)W&Z~}R)b&`hyenmZ-D^7Zv|Lib92{9D0~$9>9CLKr);TBDTMJxAFHnm$g9iTO^3T+uJB2ah0r>!uVcXIEma>R+f2SzSlEbq>W zk`=vA_qNN0wY~3f3#l%rr*k)Dn`2Tf!5a0olWH|lc;1no#C)*4O|I$X9VCa&H6v}g zccr!7^ryM{J~2zJ_Vp)KZTgd;)1M~z=LOPZ_Azw%wtkw?$saoT+wn`Vgz1r{dpP66 zAO8{FY2ISu*I1Ooq36m>oiDX9Q=LyeD>0D!bh#}pq3YuUa-&V@<<{ul^P=V$9^~^a zC$z{@H6v!kSXJs1Jqnq{Wv--kBjc&Us>tP1o|w<@TjcKjLiPSFQhjphgCG@kC{Bf! z^qwNO6dvlKVX487RhRl$uT`35d^8m=bLk`MtwS#*skQ)>AFme0tE#|5AF7WJJsF@< z4#gQhR=OsrkKv=;u0M+>J`J7JtmCNT;R->LXrHVbgToq`5fw^?F3ib4%mj^S+ni3Y5R3)XwtC|6(n12qWm_vpZHngYK zB#bRSSxc1*PS-mBQQ-t+m=#Gp#uK7t>6YQ7s)UjCrQEX6c!eTFzWHeE8C{S|**jv}Q@c zgvB-0i^mmkt*%)-Ay2NDc;>R&+GS@>oOD)4P4$wqCfBsL3>nhWKD?%*WysK$4&5>) zPwQ05(rL;#g|(2@U~Kwt{Pd|}uTKNDQmp&^^j3a_KucB=-(@*;t=YUShrsg`-nM_G z318apJ~SIy=V&(l?;p_b{#Rul_sn8mIe!FvoKmW!3!e5b@+@B|& zR=TIz{9Nb{pT(~x=!&yS>AJp$m@$%X#>h}nhXnAeUwWJ{*MwVrGg_vZ=9uT)?p)vM z#nI2?9eTj{22g%oR%&f&a!OQex}Nk>OPUgg4xW}VBd@w`e78tdPW*xCI3hmkh67GLeC{q?!R&z~Y$R^%bT55MR6)f&@n* z%YQPyF#`R1q?&W+EMGBybeyZZ4mDP(oxNNB$#6HdN;#}ksMWKa(Y^o+yRQ{|tr(~d zYdu$nzx52=?%iqttXoZD~lCBFzyiKt#Yp`c)5dv!{3 za$He-3lgfPGH`Byn>dpup1FK@pgUmho}+j3 zi_B(D%{H1sqOk>F3@}CjZ3gfyS|ertl(i!hYvwhqY0g^n^zBmb-~ zG#%(YyZ5+%+7lKmIHJriC_v^rT~e1oYa#lLZsEL>Cbd6zC<*=Qj9K53c~$e9a|aEd z-?Xyr=^-^~;SuQ-IcsdmHc6 z(lW*5Z&uAVeHy=^Vph$}`jm^_X46Zst!k}_S(0@0s#Md_!ud58vnmzc{#EHxqYc~l zHSw!9`n_T$teZmA>-yJ|OyAV%Zd`l{GD7#woSfV$W34e3qFimusjRHRmLuQIo>MTq zdFZ&@jE0KTnq$Tn&z_JxBwr+Ahd!H(jArhP_0zRJVAH4Z z%QoSL9<9so(A{c!+d+Tq2mG;H(M1OvdS<`afvN;6wSKqla>i(c+Ar$0yoBdCt@1lO z(~WJOjs1%C06hQ-7A?o5WtIrOI#VM?uNyWbYvGW@s_cx4l-!A>d6TP?(?e78R#Y`E zu54>Qr@dy?ocO_kS&4}S@mbX=NyCRFmo5m(Ol?U>k1NVb&P$JsDW6bUI%${{9y}~J zcjW0ydry+vI&YqrGHmczcl4lw!RbX=Q3ErEjvP`pt3vCc#oj||H*Z5kBl3?z-E`UU z0frNwLWJZqh1~NchAD@>vIk{NB^OpTsetTyZs{p-{&7@{B z%jE9I+OR>*KXk6zq+8U9Lt9)$i(HA-XBF{AK$yVuEdGYW0GUJKjwsp1x6)3WK>re)Ko@x~uLI&HeP zP1*ETb{o?CbUivXU60Ny9h*^(8J+fhdW~$~H-q%F&1fOEA^7vtXG&?-!ghSU7PjNh z;_Z8V`Dp92O)n5H8QT!?EoDhRy;)U@E9`PX*BX{xE<-n(hmZfI{q94v(f1MFuN;K? z%F!3zuRMhN%F`Eqc)9fY`0)Jen0xhZgUzSjC9%V&h(GeKCat;6mf8Mry~elsZQ@N$ z0e-q(cmjnm!^vr8e8K4Cvl$bLFd*K=u%xkdyp$ zUu|d&gIb`}`QG=`E%b6Xy*!#_E$U%dnIPavfjPwg+p%y%5__N8mp7QFZ-mluel<)T*tK`MKDPQVZHu0^klwqgC%OGPBwCNA|>8;{Iqh;Il)qeU6 z?4;U$mBbh%Uq5}O_{@w!JHFn3u+yK#x?F4PHeJgMn_j?gP`>V`kN4B(V9y=qr~led zujB2&JcnZ>RWBLJCJTk8d7P7!uZdZ*)$=-0(C{NPu`t+lZDFwK(|Gfs zwvpO&ZS%D0GkIs$SM;(%&b}SwEoc0~ps|$cfu!fd_`oV`C>8PHRxYz=RfRV8+LPm< z;R~yVw+$aYHP$^~*8E`C;KJb{nbp~WL3z~~*`u;^>Viw##x!?SR%8vF)4RAcAviTH zc2eT7^l2%DgR<&|?%t*XveIcdMx@^y z?nYzMp)2J<<+~@BUt`lf_3(RhzjyB}bdMeWl$*X6T0rPhf9UYT?&&M5eXl+#dC;t$HTOBHb?!mW}S9O{em+eyN=Ak6$3p_TJ@>zs;Ze&{cc=)S-Uroa3VDkHe7a#q`H~ zG5oOp7#B}}>@UXcDi;Rvqw8!HX(1&xZd`-VLsFEh?0!DsPNDeuGhWsq_?zckVIgR%uw;slIyiZRxc58-V8O&ChwO9rU zpsl&a#zt##;*8sX-0Z%av=*gTrZ3ct%_yEUWY|#&15>JU;`0)Q6hsfn4b79WBN{u> zhD7JqB@9cOH@a-nkaNc@tsb?!ZhB`-@9pt2Av&z8D5o|fb97!(S=^AcNg)}-v+`?F z(gsxyN(f7eOU??74zEUB21 zQ(ur*pOaXa(uxX>WY#_ZM&3QmPGg6?O7d0Y_i9mIpENnQX=%;K_L|ZuNkviR=~*K) zv+D8(7e?j8C04dIG%T)2N*ECymtB{aQ=dIB+$ZI3RC-SR(B_mg-g-Af=X$%+eMi&X zYFg=6hB{c6#ZR4{<;W9xlhPI=J8o;iw@wN-Dm}y5DbEx?gKFeCKa1hiAv+)bei2Ab zBG28X4*SdVZ))aO)+`=ba?~K#y!pY&^HQ>h=L7}i*JS35&Ow-0bu=_DE-%PVmrs6o za9Ltb$&|sx>623m2WQt65~7V2N}MH_Q+O;PczGg)@B1hogLukrNC zG&(T1N(PNwGQ4U*O@2dhk}KWHYnoTxG-CPWp=l#$7w3-5$QYTMLoJVZ^E!E$4p|4i4t zd|PFRp$>hv<)-EgT~+eCyVW+``l4U_OIXJ^ZP<^V%Z@vA#`H9`*6g@z?)RF}+mG`& z_AHJt4rS!nrB!BlMfctwClg{qs|#~RWMqxb8_e)ZofQ0|!^YQ}_L@0!pVOPJ;1rqN zoA#RdPt%$A8hvx-UUe>f+SFq?W4x!22626C@@r|;ehGiN>Lo3nz{r+r~n_M8>&pR@K_dd|{iA=mOAGiT-Vl!C9M zdJn}8omFJdSP%Q>n!QTTST-LsYJKzAUbWGovbGU7I5o6Vw~?Q2IQT&xdL~=dFZB!j zsTZ`}?T@YJF+0zp<9zejURCI)&S{NCt}u_u59t+EeXA3!bpDZX#QxFWnk&awH|Jz6 z9FUz8-cKUO%J`V@szM}k*63U@Zj(P{$5nEG$f-~ z3*Uw;gl|NAV&>q%X)&=SiRpd)N$(-p{Nz!?Qe=6*U|;W6W+TyxUBodS`3(?$0j#H= zzmHkwbZ0p;uJ@yuP-Y9$o$c8|-deL{G}FMsna5Qv3-?U}(UD98dKJLRO|G^Au@SRt z$MFFqum5b3J2tiq>A!yL*lAN@S@jHv3(3ygx>ZhWy=(5G(D23qfu$pU)7pEVUMUrN z%aohC&g5w&GY0)eAKNPH6GygE%QRv+%R`?SlnF&+Y7#5cn+k^2XUL$a1&uWeYep;{ zUUhVAK=91r$Gm}j$*#={8c;AiliB0B*qnsXsTrwNS!<())DCYSRo_0mFf(#$@51VN zmGU|?+`+?Ar)zb$-t-zur$?uL8>Jqdi|x^=sfi+`g8ys%*Xna(k zeAd6#F5h5|Vo#IZT4#Qb$Ka$5>gaf}(~efLvukT7$^|kzH*0u0Q+Rb`er0o2@AEP; zV@Up(!pG>poMkoXkUsmqNRCSH)7rjhPBFY;z3Zp9^0cEq4a8ox_`O;NJ=(Oy%(!pt z(wJY0vGgiCGIQGe`SO}xW2vep)>m3japF%2IY8CyW z?uU9eDSW0@I@BCB>jvEeW)mmSwmon2h>=4EXk ziZHvlSS-Z1D%F4QoG0C!X6WUl#a^r)`lLmc|ExtkdPd*Qls;==nX!#9K?bhZ=PsI~ ziYj~tmxlTCgEC`cGcsahGBLhz0K*FEJAk1!_AXXAaVaTr@yW@W<2}?|j+)^wN!|^b z<5X`AznQIDH48-PA&{ zX+it`)(7@8_H0WWCmtbXw0-7ALLExmDOqBFp0AGylKRz5~v&vfMlGn@KW#l1a~` z_nt{INhXu&b!YqZZ8NjG>}+9+w52RviXsSCM7%DzaQy+If`IjU5kUnTB8Va@pjYJM z0~D?x2nahT-~Tx$nZoWO-}k{Llk=YUy!CmX{yZmeNBzU63(rqaZ+UqCk&8xuC2VI$ z?tAUwGIWalm!Xq76Z=4GR?^48ZcNa>PL>gUE2x*Vh>wxV@%EA5%SextC}w3}7so{P zF{Xu9wk@gspzLW@Db66z9$F|TXb{9+CZHD~4-Flziludtjp}Yc;XLU&U zaC)p#H%TMsy}L!%4yJZTr14JB1h7BGQma*D@e(1Q)J;n530Gn*&ck#zTv@SvJ;VbN zZSLF72ajJE2}bxIMZ7`l0vO@YmtlP-ctOM%(zr2^0 zl`AW5TO?W#E9~y=-`U!_tG{d zXN!ojg**hm!}7Cvkt2Sx%n{d-7N>l#UE+uv7dYa#h$AlF%}ZLG_<|PaEz;tY?oOs8 zj`*Pkp7kx_h{e0m;dGZd;`%6ZH`{mJ;?<+Y*h3pJ~65O4DjyDRf3LZ;6uojj$5RYFvb)p$6 zlQt-o>|X$C4vLmEID9r_^)=M!>uWVt5vC0`8C?yv#s-Z#Qla$;kDnBpp9;m4gQ{3x zggs}euU4z=dQZ+_uCHzMx%^q1@Xkqq{q{(zqery0N-)2;7VAiop|ymcd(Fa*L3Sza zOmt0Ic6p0K2UjZHFjdmQvA1zT{j%(WG*50NOT-rv3zk_`q*2vrGR7Iw%u(_do5Pc1Cv?GhZ`b37#re< zUjbZxAHTHZHBbH}ihr>|>>1&j7&~3K?4*0ZZV)EI>?^OFWUVE*N53LRI99?e*A>AN zmM{+VdZl#?rWeoNOQljjN2z$Wwj!cme1^Zz?ty+n)Zob8WRQb^A3+be7puRh1p}o_ zm#HTq%HyVZZy~z^ml=E_E#$W`Rb_8COpOWo@(=_T6gsI zZO^Rq^@PGberwV>;7pN`0~WeGcY~gbb^y}g1aj1^21aHg+9&L`&(V>rmv5P_Y0M4y z3tQ0dNU%2;=<-v)N`Gs$-fQ*UxEvxk;o4c`hr@cbUd2 z1C~N_0*%!>IjH(hDYQaW5yWA(NNlu-BieBGq6f-bIqM{6=*J9YkZEE#Y|R-&^( zXVU8L4TZV^KavD80-9Sd@&=fq%1?3!c!Da0x}(pmNDPIxup{TH{TbU9d3Z4Rz#=Cw zBJMxl;s6S=u8Vdb90uFYFT_4er6aGriqZn;J^ENEO)3FFMQA+Ph{&x|T}TAKqjn~D z5Oe{OagVrjsh#K>Ph+f+;=61o-bMpy8LP7(@PR-ATP;ym251U6c}B@M?2+hLQ^1mI z(z*4vm^qzw^)yHN?Y_p8PUFy7V+KdF%`;T#aAeKqYNO6zQL8lV5m(-;H??US@qS`M zgWl3mS!IushMYzxjzi>vwn=lJ!gR#aL!`;1I6%x~gb}Y3De7s=3#Fq~$586WOwJ@t zW~uJjdxYg9#pY#olYPWFMvL$8ApZhM^ka)BTP4j6h-m3Ls603kCCwsvbU>A`KReyl zIT7*uyseJ(#h^rf2|t$qdb#tmUdN6U0i4|}+8HXZ2pM+O?}(ra6Lwlo`S z^R?CfZhx%T!$w1HbHK1+t+0_zts%IH;cEpSCokc#w5XsEdpmFXj5DTJujb?bIV{}G z#)dH~msAsTh4&9meHQOkyBOuv!Xc3+N##jI2~n(Gtk^^?m+Hg!A(bFA^2_UFrVfgzbEIOo~TsRCVSNbIhGRs<_@#aQ0#}o z_MMHkn1yy#Y>RY?lod;)yT+#~Ba;cT@F5)aun|HGJ zA?rxB<7`UgEW~ntda0Z!KgyTQZts%k7Vj?^1@GkN9{2o`(cu24KX4zM#p0;=w&U&w zTcnx4&i=ZvS^>yy2TGK>LZsBv3J|51W*S{flv*k!N-dRc*hrLm1lFCXSpj|vdUPe=L(VId3&;Nbk=KOWL|4_@midbMaB+z@y_>fV z)SdhTYN&E9z&0IfJY(|@t~l?Z&6hg2xS*+dg)_4-%&fxyf*<8`%HORZs1~0V@$_XS zsD4hQ(^C0oFeWNj^0AAcr76`WO^j4~Ty}}bHEf@Vi@=DmBjT(n z5*^g_AW>JTl&GszI^rPeDwUG9he}Dec!?-;f=cpRcqNBWWEH62Be#56HUm(sS}7<$mRp%br8O=s(Esl=?5` z;XPFz7uur;J!+5blG@|lR3Ghc#kE}2jSHe~yot0YXP!hqPFj~`s+=;VF~XbiZ373FSvq3vG`yhFc^;w z1&0kjqsgx~_)I3RffpkE!C-$RG7$9l$4nukF=R3a@sIj&;_F92H>Vh@n7mkPGQ|GT;cfn+Ay5qo#6?@w|_N^G& z-+@6PtEf!&JiopaeMX$pUE5ai>*o(}ej)Xxqx%M!Rzh{xAj&jE8eIhUwte& z}Y*%R6oPh^O7jSmC8QO+?qXInlbk(r;g7 zw7T-XV5di`Wm~52g!Eq6Ug(@F5KItX{x1K#%q&CjhGf0(z>3mzsP5IXgugx}b^ zw<|rlKi@rapj~Nd+R&HYl<(Qo?d$MDPv>j*dO9k*4zBMxxNDGAa#W(ylb5A$e^t_*uj_~-uD++YX@Uiz?qa(M5(%l?Md zw967?2P55KZb1YRH4+Q^>CY@X=_DFyMIRc730OeAHBfNa1F^NK$I)WXn!Ek8&0(9>eDMz`R(oP+w%&4r{52! zw+?9fJ7IZnL?RAvJnj`&^-ZkmwOCa^`ZD+{^`e=m8Af-fM+4cf9&YvM^ui-4Au)C{)=a}7<^K8xKKv^E+m6&v-Rer|V1 zt;^7q@p`&h!lBMq+nLYpbt)^Wu2A=XQ(axp%qg$G6ZutTUKV0&`R#-ad-N_i%K{hX zQ~|bDc$z(uAJJb_$9|MGGnsHXv+&z!&b5HO_xRm_FM>Tfhb-VaekMH)?V0R2nUt1;HpS!(fJYpSg^*4CJ6x0;$wwYWCcN=3DnI{Yxkj2M#) z*=5h=uMkBVGc+1Kejb<|{Pf_=&^1H+l?R27KlmWK=t0cQjm(0dVq+Bqm6T*qZnxRua`AWOAO5c0XmmJ?M&jqf#VDS0NY72-xg0QG84E6X z?zg;s@i9C{Y*a138on!CfM~2j8mmAa2lVkQ`Ae%q*WzEQL)WFhTB?WNOs=X??NZb! zCX}_xU0g2TEmz8S$rXIJqDDEcs8#I5XF^${m`2$Q?oG?(@@dpfbCrB&g+k7+PHs&~ z{{Wljj71mHCuWpI_~2NQhU3Q4g(OB6{(Ddh(sDNf8TXs_c8il%_9u&F%avQ zYG1rq1*?qcwok~u!gk@@z<#{!v=V|M(CKk$bxx;F>zc%=TdfOdS*m~c-JSH==85Gu-)-#pfSf#f&)Y}bJ zMt!u~9QPU29-GahHuw^zZvG$YX!KyB-BnfP%7!kB#MGm5LoRc~*6JT+zP#;@L`o+g zrLlLT_fhl?h@2ADdjyr`9j7dFl&Qcs`X1^ZYI%;d3hAM+T)@6$OjVg`P zWO8a$27lb#HK2|~E(>R!s%mF0bXhdoFv@kQ#1UO0+{8w$p@jYm(f}xuZV!mSn<73Z zXDobnKXKr|6a3AodG8dBFpU~qsxg28k&w#x;|C5r{`o2Xhe@ijv$%;(qDG^H*@>&9 z#S?k_oy}{)!-1Xv{=tW{nFZ$V{ZuRzyWq(5^cT;Mg=1IWvlA^0qlLWGLJuuJEE2Tj z6wIh+`Q)ldxrxZCB=b`f;phcloSr^%K~!o2ZS0VJm2btH!AnrEgB=qpj)`kLhscc^ z7w^omr0}?OCnNhhVz3F@ldjj3x&MA98wHe<$}5!Y*PuNd*BSN(Yzbl(gL66+Ieooc zWtSWEfhE5)3U?x%a4VEfpIxQ0`*&1v0cbZ7P+`WmAnm zaDp=QIU~z(OS#XvxFVoOhv-(HTk@M*&}mD;rCjVnULJmzrHRiv5f#9n1f z=Xw0xPShx#$EaC{^!(B>vyP86Dmt?syyZbHTTu~!SBq@^T=2Ee$_~z-OLurTyt1Cd zoo8g1VqcW(8HM-+Z((Zw1o$XCfzoFW5>(oGx9mp#9Nwf2-w>tJsDizBXS2biT&ZmE z@aIgXewWH!NT8;Nx5y5I&#FRAFjs*bY{9D0gx;)LsZ_fSyv3v&^r);IEe+E6z9u^? z8$u2^8s9k>SD|4Bv|#j1|8RJ;n2YE*HTUX!A1rDn>-iwrJ2H zAO6?c+P-yC|8w^I{IjQ?*asc$7m7dU_sMnmr6T!`IMf_IS{SS2C(Y-k6MjCBdC2XdD zA&WU;X7~GIrbwebs8Uy&>uMZ9dt=mO3^l6iD}%P$hK5>O=m094!-(UhZ;Uiq{64Rd z>#=6=0vyofU}RBgvRySlGsI{OCc}7343-2j%tR z?pj4U1zbhx2Xl)OC-6U^X5;a`|7_L!@4vyG6yo1)-IQtFT1ad#DiH+Gw5iFP^{KEQ z2y%cl&wtr7|J~jzq)>pE&yHLsm+rLqn-L1&TxXA2yizCt!P>k0J~7r`gf+@QXT(SG zVX#(U2ZZYx+b?{UAJlXmmqoB;7Fh%bw^0^B_Sl-v)en6bh_T|&iyPQR*s+^%s)$_b zi7;YGL_SI+(x6dWyH6WV_qi{>y!B%v=|0!sAg`D_Jpcexn!{slga%Cl>NK zQCcAn*Ui8BEqQGzsna3hoes8rJNwS`)CcoAVNY>N5T}dxg#Zr0`1C*ySKyPAWF!z# zFoQr6nq&*abPvu57($T^aDh7j|H`fs9%E_YvHr|V=g_QaP|;utJ40y$tEjB3|Bcr* zQEP7r2KCr^vo${9 zQ$E&R@6rryYez=H`H8H?*OjQ&R(`JV>jGO}c)WnM+zoBzmGUn12%TvUfLL4d3o8fi zCy6VEu)TJC{Aglbb83BjYbiQh-gWGU>HZ%+bk+mHdF)13JzY-S zF+JUhXLegfG5a0i@UI(N{o(5YKIaZ((tM#Lvb6MEcJMGc$*!gVtbC(>Z(GQ15Y6E0-TM`9ci1 z92(>jHW7`c3z6VG@(Yh$W?CK&&VJm>)*crTj@^RIOpLmweJiy_*csX8#0YGS=XQ3Q z@NbOp@y8cKu~}^O(3(H9+k|`MY+TqP{2E-54Y5<-XIGO{2+by>Wl0yY-yM&;UGey9 zaTmVvA)ZJr$!g%2A1M;=H6=^4AG2FUiBj~T0B;S5ePQD2t0%6xhTVGY$hFswpx(Ib zHujK=-mNA|ZsTm9aKqao&%O`MJOKL{aQqxlyrkVCnSwZpvMvm8igkxt+7)){V zN@LP&fVl0|pmf`c*HNVL^GweR(oFWYmFx)a(b(v;~ zted|efwe5S(%&nIoUv;}O$^Ly!XL`NzBdBsnvKVpW`;z5HvVtvYz@1h&~lL1^T1^`6};*nb|2{vu|p4c7sn?vGDxg!@EBAv0dRX z{+zZe{5fik$)<~Ma1*2VRmslr`7#QYoMx56yX<~pVCwMUIqVbdO=s~9_AY8E(4Rt~ z_c8V^>QoAY?7!Hj4u4^15%Lh1t&nx_3Vsx|h$~hoGCm)19K+NY(+RIK_E}*+KUyr# z-FQT>j^YUmGSobUCzOC=*?z89D3UY}_7ontU-&01!u!~j!l7sI$W33km!6oCZDc>@ zy?_#68_Cy3f)nbg1S{7NNbp_}V1#!_Hq*+sv&-4{;E`QX{D*K4s50I+Q{01@*@4lo z#x=n9Z4>^%g8#W0I5Qx7hJ6JmMh$*H zE-PStAva*2 zJ?Dv7%tn2aIhu}{n)F7qIm*(OpwSxAX+u_H&}_! z15g5kugxCjhqMifHYTzbBJq;A39uQWg5#e$W3|>DF?L7wrm9AFgmfAW(dhh_6KSn{ z6zT=O5h?_ZvnrR}1b}&%Z-os+j18SDp>EPwC~;)<@d_!QtevX>;64x$`mk61d8aNq zm}(i0>KGi*tQ~D}YjAjbVQ5dkL(c7qT-GSu^TG>kobrr3TKqQq3$(AK)uxoN`2SJn7&~{IzjN#dWa34gHN~&9=TL{v zgG=So%E9((*RboFg!gA>nW9NJ{Ve{@h;X-X*9f~E_0=*Yrsq4U&7L%qdva+bd$=IH zcGVa=X9wRoe>01v{(yQT#hhp}E?JBze&Gb(UM&O4jnj+%UKO>?z3Q%HmGCE)g*s!= z>FZR3HEscX;ys4^H+&mTRulY&as-XA%Pg@^K~Pu%ZtO$uX<2|h7VmaCyW_Dgx4UbP z!)CK1#hHVBGv4KLb;aXUdMZjC^tnQq-NJ5RHIX&x)S5_SO$rg`Uu|w}ZEk5v3(Dx~ z<4f7~^G6uQs-jU>SeA`?6|ltr*T_F?X8-rI+7jz_xw>P^XZ-&#*ZJ#Cv=9WlfEt2b zqTjMHtz4c{8FR1RiU0QP+Yhk)HxTdB{s;e|Zmj5&|BhdQ>?6};(9C#_(v}N&N*AIn``m* zY{~}nrb@NCV|6GynPeUN2BPhOn#K)&uFz@C%>m=^HFJ9p@9Jo3o;rJ=aC*w`pV{Wh zM`~*1o~%1E7;@yFZJxb$w&RM6cXnjAU9z%$|5!3G7>ih1+=ov5WX!ePcm8t3FAxp z6;Tywl-v$V`t>qahJ7}jmIwH)mA-&gxV_4x39ri+rtL|4!4^$6H1Ha0Hf#dvOqNBj46g@>jR^BWHivPbK~>88l4c-+xrb!B{weoMu_8~kZopx`nFjM-Fw>(-9M z`huGYza^&|vLUgDfj@}Wl}{U_9TC^WR>kn|pJSur>@NIBtcuQ8@jK=>5hYF)CwLX) z?LHZh?VR{R0BQUuNcASURRDoY>HEcaE7HW;DL-5w3*O1EBu$GEX~oWPM~9>N9o@09 zp{8bQzRl*&djg#vSAVO!Wi(ou>UEe~)@E`${2}k4H_&47cL!X(IoDb>3w1aPgB&>! ztgZg5JQd!qL}o*a)~#Q!cc={!o5O3YtTG2$gDnFt?p7zde9q3a&23#_F)@QzZ}pj~ zD^31kL^L}F&!5R;X3ig?zb(_}4-X$4 z7&th*;_QK*gTDZEVl5M?*2$Erp>7BsNX<4|vt83D{3Esb(2C*nH>FaW&L3WJXme_H z-`T@!4)*t-y?W)rKHyyk?BG9zE|DUi!m>2ra&fmy)};@QlFUxn9=y-NQ?i+R^b{}n zX4|%Wep_2%Yd*iV9lS_rC>o(}=eRfM@w+p_jdcz6hW=o?n(@nzPnLPX0V`#_6o|L`LZw954xMz|O7Fip3D@*o& z>_pnvl(1Q2O-(VF#+r8N>~@{rYSZzYHDPIrTk&m4SW`B=)^5}5&=`|#De7hS@kam= zqULnV!~}oj*m@fMU{MEcE!`mui4&y9XK)<<@kfL&zA79+9ha<%Rr6EIb+E9g<9g+l zRpaCA$R3v3$npiA6HX9fP3TU9V+~UE=;*uR1K{tF*}39w0k`5ln~=DqxURNMa>PR zpp_kM*&RJnG+e01ALzwuoz7llJH(xk^~8CA6h*-0;EP%7t%=E%v*?t72$X4>5fY~RcamlVhNszCB zz2{pfnLw_|L6jh&INgfab3$@vY+rT<9gkHx8wSw!fgb*dY%ZUBO;uB5N_81 zmMZyGXm=Cn7L%>uPqI(Tr#}F=kwiyh2GU^Z^)rCDIvG0tP)zX0M)Lu#0~I zFz8I%Y-y(igDLhqWF0?sDP*O>9>t(4*cIjtftIdrJ;u_4cR_rq_$%52?CC5@kktV2 zL%U4yb3IB*@PqLt#qs`YI0*wzoe{4ZTx7~^}dyb^axyD6><__9D+WQfH`&!3BD z6FL%elSew6?D-F@O9?haT15Hu5T|tMtaWzsc6KNK%qhw}cilzjaujD_5Nl`0iId_@ zB|ke@zzE6YvSqRvIIYHQu!OBXwYN?)IJCl0<7~+E2Rfn7Q6H{>E<$6gRK$8J#*GRE zW6`KPqBnw}L@bqrYiS%kfgENCY11>^L<9LUdtZ4pybuHRxKN@VqK##p>_(I_Sr<-KhMT1)^qwwA?Pj8N1>g}U`h-@0O4Lh|k0tRK zKzR6dZ?Zob+S$@2<(<%UOSvX$OmSN|qbJs34Jb_|prMAW982|npxC7E6?bP%CWO5S z1~X}sw$Ws2)S7r>FqsSnQYpXIY}V>bVpMLJ{RBAw6hK- 0 then + local top = loveframes.collisions[#loveframes.collisions] + if not downobject then + loveframes.hoverobject = top + else + if downobject == top then + loveframes.hoverobject = top + end + end + end + + if loveframes.config["ENABLE_SYSTEM_CURSORS"] then + local hoverobject = loveframes.hoverobject + local arrow = love.mouse.getSystemCursor("arrow") + local curcursor = love.mouse.getCursor() + if hoverobject then + local ibeam = love.mouse.getSystemCursor("ibeam") + local mx, my = love.mouse.getPosition() + if hoverobject.type == "textinput" and not loveframes.resizeobject then + if curcursor ~= ibeam then + love.mouse.setCursor(ibeam) + end + elseif hoverobject.type == "frame" then + if not hoverobject.dragging and hoverobject.canresize then + if loveframes.BoundingBox(hoverobject.x, mx, hoverobject.y, my, 5, 1, 5, 1) then + local sizenwse = love.mouse.getSystemCursor("sizenwse") + if curcursor ~= sizenwse then + love.mouse.setCursor(sizenwse) + end + elseif loveframes.BoundingBox(hoverobject.x + hoverobject.width - 5, mx, hoverobject.y + hoverobject.height - 5, my, 5, 1, 5, 1) then + local sizenwse = love.mouse.getSystemCursor("sizenwse") + if curcursor ~= sizenwse then + love.mouse.setCursor(sizenwse) + end + elseif loveframes.BoundingBox(hoverobject.x + hoverobject.width - 5, mx, hoverobject.y, my, 5, 1, 5, 1) then + local sizenesw = love.mouse.getSystemCursor("sizenesw") + if curcursor ~= sizenesw then + love.mouse.setCursor(sizenesw) + end + elseif loveframes.BoundingBox(hoverobject.x, mx, hoverobject.y + hoverobject.height - 5, my, 5, 1, 5, 1) then + local sizenesw = love.mouse.getSystemCursor("sizenesw") + if curcursor ~= sizenesw then + love.mouse.setCursor(sizenesw) + end + elseif loveframes.BoundingBox(hoverobject.x + 5, mx, hoverobject.y, my, hoverobject.width - 10, 1, 2, 1) then + local sizens = love.mouse.getSystemCursor("sizens") + if curcursor ~= sizens then + love.mouse.setCursor(sizens) + end + elseif loveframes.BoundingBox(hoverobject.x + 5, mx, hoverobject.y + hoverobject.height - 2, my, hoverobject.width - 10, 1, 2, 1) then + local sizens = love.mouse.getSystemCursor("sizens") + if curcursor ~= sizens then + love.mouse.setCursor(sizens) + end + elseif loveframes.BoundingBox(hoverobject.x, mx, hoverobject.y + 5, my, 2, 1, hoverobject.height - 10, 1) then + local sizewe = love.mouse.getSystemCursor("sizewe") + if curcursor ~= sizewe then + love.mouse.setCursor(sizewe) + end + elseif loveframes.BoundingBox(hoverobject.x + hoverobject.width - 2, mx, hoverobject.y + 5, my, 2, 1, hoverobject.height - 10, 1) then + local sizewe = love.mouse.getSystemCursor("sizewe") + if curcursor ~= sizewe then + love.mouse.setCursor(sizewe) + end + else + if not loveframes.resizeobject then + local arrow = love.mouse.getSystemCursor("arrow") + if curcursor ~= arrow then + love.mouse.setCursor(arrow) + end + end + end + end + elseif hoverobject.type == "text" and hoverobject.linkcol and not loveframes.resizeobject then + local hand = love.mouse.getSystemCursor("hand") + if curcursor ~= hand then + love.mouse.setCursor(hand) + end + end + if curcursor ~= arrow then + if hoverobject.type ~= "textinput" and hoverobject.type ~= "frame" and not hoverobject.linkcol and not loveframes.resizeobject then + love.mouse.setCursor(arrow) + elseif hoverobject.type ~= "textinput" and curcursor == ibeam then + love.mouse.setCursor(arrow) + end + end + else + if curcursor ~= arrow and not loveframes.resizeobject then + love.mouse.setCursor(arrow) + end + end + end + + loveframes.collisions = {} + base:update(dt) + +end + +--[[--------------------------------------------------------- + - func: draw() + - desc: draws all library objects +--]]--------------------------------------------------------- +function loveframes.draw() + + local base = loveframes.base + local r, g, b, a = love.graphics.getColor() + local font = love.graphics.getFont() + + base:draw() + + loveframes.drawcount = 0 + + if loveframes.config["DEBUG"] then + loveframes.DebugDraw() + end + + love.graphics.setColor(r, g, b, a) + + if font then + love.graphics.setFont(font) + end + +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +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 + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function loveframes.mousereleased(x, y, button) + + local base = loveframes.base + base:mousereleased(x, y, button) + + -- reset the hover object + if button == 1 then + loveframes.downobject = false + loveframes.selectedobject = false + end + +end + +--[[--------------------------------------------------------- + - func: wheelmoved(x, y) + - desc: called when the player moves a mouse wheel +--]]--------------------------------------------------------- +function loveframes.wheelmoved(x, y) + + local base = loveframes.base + base:wheelmoved(x, y) + +end + +--[[--------------------------------------------------------- + - func: keypressed(key, isrepeat) + - desc: called when the player presses a key +--]]--------------------------------------------------------- +function loveframes.keypressed(key, isrepeat) + + local base = loveframes.base + base:keypressed(key, isrepeat) + +end + +--[[--------------------------------------------------------- + - func: keyreleased(key) + - desc: called when the player releases a key +--]]--------------------------------------------------------- +function loveframes.keyreleased(key) + + local base = loveframes.base + base:keyreleased(key) + +end + +--[[--------------------------------------------------------- + - func: textinput(text) + - desc: called when the user inputs text +--]]--------------------------------------------------------- +function loveframes.textinput(text) + + local base = loveframes.base + base:textinput(text) + +end + + +loveframes.LoadObjects(dir .. "/objects") +loveframes.LoadTemplates(dir .. "/templates") +loveframes.LoadSkins(dir .. "/skins") + +-- create the base gui object +local base = loveframes.objects["base"] +loveframes.base = base:new() + +return loveframes diff --git a/loveframes/libraries/objects.lua b/loveframes/libraries/objects.lua new file mode 100644 index 0000000..624b53d --- /dev/null +++ b/loveframes/libraries/objects.lua @@ -0,0 +1,150 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +loveframes.objects = {} + + +--[[--------------------------------------------------------- + - func: Create(type, parent) + - desc: creates a new object or multiple new objects + (based on the method used) and returns said + object or objects for further manipulation +--]]--------------------------------------------------------- +function loveframes.Create(data, parent) + + if type(data) == "string" then + + local objects = loveframes.objects + local object = objects[data] + local objectcount = loveframes.objectcount + + if not object then + loveframes.Error("Error creating object: Invalid object '" ..data.. "'.") + end + + -- create the object + local newobject = object:new() + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(newobject) + + -- if the object is a tooltip, return it and go no further + if data == "tooltip" then + return newobject + end + + -- remove the object if it is an internal + if newobject.internal then + newobject:Remove() + return + end + + -- parent the new object by default to the base gui object + newobject.parent = loveframes.base + table.insert(loveframes.base.children, newobject) + + -- if the parent argument is not nil, make that argument the object's new parent + if parent then + newobject:SetParent(parent) + end + + loveframes.objectcount = objectcount + 1 + + -- return the object for further manipulation + return newobject + + elseif type(data) == "table" then + + -- table for creation of multiple objects + local objects = {} + + -- this function reads a table that contains a layout of object properties and then + -- creates objects based on those properties + local function CreateObjects(t, o, c) + local child = c or false + local validobjects = loveframes.objects + for k, v in pairs(t) do + -- current default object + local object = validobjects[v.type]:new() + -- insert the object into the table of objects being created + table.insert(objects, object) + -- parent the new object by default to the base gui object + object.parent = loveframes.base + table.insert(loveframes.base.children, object) + if o then + object:SetParent(o) + end + -- loop through the current layout table and assign the properties found + -- to the current object + for i, j in pairs(v) do + if i ~= "children" and i ~= "func" then + if child then + if i == "x" then + object["staticx"] = j + elseif i == "y" then + object["staticy"] = j + else + object[i] = j + end + else + object[i] = j + end + elseif i == "children" then + CreateObjects(j, object, true) + end + end + if v.func then + v.func(object) + end + end + end + + -- create the objects + CreateObjects(data) + + return objects + + end + +end + +--[[--------------------------------------------------------- + - func: NewObject(id, name, inherit_from_base) + - desc: creates a new object +--]]--------------------------------------------------------- +function loveframes.NewObject(id, name, inherit_from_base) + + local objects = loveframes.objects + local object = false + + if inherit_from_base then + local base = objects["base"] + object = loveframes.class(name, base) + objects[id] = object + else + object = loveframes.class(name) + objects[id] = object + end + + return object + +end + +function loveframes.LoadObjects(dir) + local objectlist = loveframes.GetDirectoryContents(dir) + -- loop through a list of all gui objects and require them + for k, v in ipairs(objectlist) do + if v.extension == "lua" then + loveframes.require(v.requirepath) + end + end +end +--return objects + +---------- module end ---------- +end \ No newline at end of file diff --git a/loveframes/libraries/skins.lua b/loveframes/libraries/skins.lua new file mode 100644 index 0000000..1935f2a --- /dev/null +++ b/loveframes/libraries/skins.lua @@ -0,0 +1,117 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- skins library +loveframes.skins = {} + +--[[--------------------------------------------------------- + - func: RegisterSkin(skin) + - desc: registers a skin +--]]--------------------------------------------------------- +function loveframes.RegisterSkin(skin) + local skins = loveframes.skins + local name = skin.name + local author = skin.author + local version = skin.version + local basename = skin.base + local newskin = false + + if name == "" or not name then + loveframes.Error("Skin registration error: Invalid or missing name data.") + end + + if author == "" or not author then + loveframes.Error("Skin registration error: Invalid or missing author data.") + end + + if version == "" or not version then + loveframes.Error("Skin registration error: Invalid or missing version data.") + end + + local namecheck = skins[name] + if namecheck then + loveframes.Error("Skin registration error: A skin with the name '" ..name.. "' already exists.") + end + + local dir = skin.directory or loveframes.config["DIRECTORY"] .. "/skins/" ..name + local dircheck = love.filesystem.getInfo(dir) ~= nil and love.filesystem.getInfo(dir)["type"] == "directory" + if not dircheck then + loveframes.Error("Skin registration error: Could not find a directory for skin '" ..name.. "'.") + end + + local imagedir = skin.imagedir or dir .. "/images" + local imagedircheck = love.filesystem.getInfo(imagedir) ~= nil and love.filesystem.getInfo(imagedir)["type"] == "directory" + if not imagedircheck then + loveframes.Error("Skin registration error: Could not find an image directory for skin '" ..name.. "'.") + end + + if basename then + --local basename = base + local base = skins[basename] + if not base then + loveframes.Error("Could not find base skin '" ..basename.. "' for skin '" ..name.. "'.") + end + newskin = loveframes.DeepCopy(base) + newskin.name = name + newskin.author = author + newskin.version = version + newskin.imagedir = imagedir + local skincontrols = skin.controls + local basecontrols = base.controls + if skincontrols and basecontrols then + for k, v in pairs(skincontrols) do + newskin.controls[k] = v + end + for k, v in pairs(skin) do + if type(v) == "function" then + newskin[k] = v + end + end + end + end + + if not newskin then + newskin = skin + end + + newskin.dir = dir + local images = {} + + local indeximages = loveframes.config["INDEXSKINIMAGES"] + if indeximages then + local imagelist = loveframes.GetDirectoryContents(imagedir) + local filename, extension, image + for k, v in ipairs(imagelist) do + extension = v.extension + filename = v.name .. "." .. extension + if extension == "png" then + image = love.graphics.newImage(v.fullpath) + image:setFilter("nearest", "nearest") + images[filename] = image + end + end + end + newskin.images = images + skins[name] = newskin +end + +function loveframes.LoadSkins(dir) + local skinlist = loveframes.GetDirectoryContents(dir) + -- loop through a list of all gui skins and require them + local skin + for k, v in ipairs(skinlist) do + if v.extension == "lua" then + skin = loveframes.require(v.requirepath) + --loveframes.RegisterSkin(skin) + end + end +end +--return skins + +---------- module end ---------- +end diff --git a/loveframes/libraries/templates.lua b/loveframes/libraries/templates.lua new file mode 100644 index 0000000..663ead3 --- /dev/null +++ b/loveframes/libraries/templates.lua @@ -0,0 +1,85 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- templates library +loveframes.templates = {} + +--[[--------------------------------------------------------- + - func: RegisterTemplate(template) + - desc: registers a template +--]]--------------------------------------------------------- +function loveframes.RegisterTemplate(template) + -- display an error message if template is not a table + if type(template) ~= "table" then + loveframes.Error("Could not register template: Template argument must be a table.") + end + + local name = template.name + local base = loveframes.objects["base"] + + -- display an error message if a template name was not given + if not name then + loveframes.Error("Could not register template: No template name given.") + end + + if name == "Base" then + base:include(template.properties["*"]) + end + + -- insert the template into the available templates table + loveframes.templates[name] = template + +end + +--[[--------------------------------------------------------- + - func: ApplyTemplatesToObject(object) + - desc: applies the properties of registered templates + to an object +--]]--------------------------------------------------------- +function loveframes.ApplyTemplatesToObject(object) + local templates = loveframes.templates + local type = object.type + -- loop through all available templates + for k, v in pairs(templates) do + -- make sure the base template doesn't get applied more than once + if k ~= "Base" then + local properties = v.properties + local hasall = loveframes.TableHasKey(properties, "*") + local hasobject = false + if not hasall then + hasobject = loveframes.TableHasKey(properties, type) + end + if hasall then + for k, v in pairs(properties["*"]) do + object[k] = v + end + elseif hasobject then + -- apply the template properties to the object + for k, v in pairs(properties[type]) do + object[k] = v + end + end + end + end + +end + +function loveframes.LoadTemplates(dir) + local templatelist = loveframes.GetDirectoryContents(dir) + -- loop through a list of all gui templates and require them + for k, v in ipairs(templatelist) do + if v.extension == "lua" then + local template = require(v.requirepath) + loveframes.RegisterTemplate(template) + end + end +end +--return templates + +---------- module end ---------- +end diff --git a/loveframes/libraries/utils.lua b/loveframes/libraries/utils.lua new file mode 100644 index 0000000..3ee4be5 --- /dev/null +++ b/loveframes/libraries/utils.lua @@ -0,0 +1,452 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- util library +--local util = {} + +--[[--------------------------------------------------------- + - func: SetState(name) + - desc: sets the current state +--]]--------------------------------------------------------- +function loveframes.SetState(name) + + loveframes.state = name + loveframes.base.state = name + +end + +--[[--------------------------------------------------------- + - func: GetState() + - desc: gets the current state +--]]--------------------------------------------------------- +function loveframes.GetState() + + return loveframes.state + +end + +--[[--------------------------------------------------------- + - func: SetActiveSkin(name) + - desc: sets the active skin +--]]--------------------------------------------------------- +function loveframes.SetActiveSkin(name) + local skin = name and loveframes.skins[name] + if not skin then print("SetActiveSkin: no such skin") return end + + loveframes.config["ACTIVESKIN"] = name + local object = loveframes.base + object:SetSkin(name) +end + +--[[--------------------------------------------------------- + - func: GetActiveSkin() + - desc: gets the active skin +--]]--------------------------------------------------------- +function loveframes.GetActiveSkin() + local index = loveframes.config["ACTIVESKIN"] + return loveframes.skins[index] +end + +--[[--------------------------------------------------------- + - func: BoundingBox(x1, x2, y1, y2, w1, w2, h1, h2) + - desc: checks for a collision between two boxes + - note: I take no credit for this function +--]]--------------------------------------------------------- +function loveframes.BoundingBox(x1, x2, y1, y2, w1, w2, h1, h2) + if x1 > x2 + w2 - 1 or y1 > y2 + h2 - 1 or x2 > x1 + w1 - 1 or y2 > y1 + h1 - 1 then + return false + else + return true + end +end + +--[[--------------------------------------------------------- + - func: GetCollisions(object, table) + - desc: gets all objects colliding with the mouse +--]]--------------------------------------------------------- +function loveframes.GetCollisions(object, t) + local x, y = love.mouse.getPosition() + local curstate = loveframes.state + local object = object or loveframes.base + local visible = object.visible + local children = object.children + local internals = object.internals + local objectstate = object.state + local t = t or {} + + if objectstate == curstate and visible then + local objectx = object.x + local objecty = object.y + local objectwidth = object.width + local objectheight = object.height + local col = loveframes.BoundingBox(x, objectx, y, objecty, 1, objectwidth, 1, objectheight) + local collide = object.collide + if col and collide then + local clickbounds = object.clickbounds + if clickbounds then + local cx = clickbounds.x + local cy = clickbounds.y + local cwidth = clickbounds.width + local cheight = clickbounds.height + local clickcol = loveframes.BoundingBox(x, cx, y, cy, 1, cwidth, 1, cheight) + if clickcol then + table.insert(t, object) + end + else + table.insert(t, object) + end + end + if children then + for k, v in ipairs(children) do + loveframes.GetCollisions(v, t) + end + end + if internals then + for k, v in ipairs(internals) do + local type = v.type + if type ~= "tooltip" then + loveframes.GetCollisions(v, t) + end + end + end + end + + return t +end + +--[[--------------------------------------------------------- + - func: GetAllObjects(object, table) + - desc: gets all active objects +--]]--------------------------------------------------------- +function loveframes.GetAllObjects(object, t) + local object = object or loveframes.base + local internals = object.internals + local children = object.children + local t = t or {} + + table.insert(t, object) + + if internals then + for k, v in ipairs(internals) do + loveframes.GetAllObjects(v, t) + end + end + + if children then + for k, v in ipairs(children) do + loveframes.GetAllObjects(v, t) + end + end + + return t + +end + +--[[--------------------------------------------------------- + - func: GetDirectoryContents(directory, table) + - desc: gets the contents of a directory and all of + its subdirectories +--]]--------------------------------------------------------- +function loveframes.GetDirectoryContents(dir, t) + local dir = dir + local t = t or {} + local dirs = {} + local files = love.filesystem.getDirectoryItems(dir) + + for k, v in ipairs(files) do + local isdir = love.filesystem.getInfo(dir.. "/" ..v) ~= nil and love.filesystem.getInfo(dir.. "/" ..v)["type"] == "directory" --love.filesystem.isDirectory(dir.. "/" ..v) + if isdir == true then + table.insert(dirs, dir.. "/" ..v) + else + local parts = loveframes.SplitString(v, "([.])") + local extension = #parts > 1 and parts[#parts] + if #parts > 1 then + parts[#parts] = nil + end + local name = table.concat(parts, ".") + table.insert(t, { + path = dir, + fullpath = dir.. "/" ..v, + requirepath = loveframes.utf8.gsub(dir, "/", ".") .. "." ..name, + name = name, + extension = extension + }) + end + end + + for k, v in ipairs(dirs) do + t = loveframes.GetDirectoryContents(v, t) + end + + return t +end + + +--[[--------------------------------------------------------- + - func: Round(num, idp) + - desc: rounds a number based on the decimal limit + - note: I take no credit for this function +--]]--------------------------------------------------------- +function loveframes.Round(num, idp) + local mult = 10^(idp or 0) + + if num >= 0 then + return math.floor(num * mult + 0.5) / mult + else + return math.ceil(num * mult - 0.5) / mult + end +end + +--[[--------------------------------------------------------- + - func: SplitString(string, pattern) + - desc: splits a string into a table based on a given pattern + - note: I take no credit for this function +--]]--------------------------------------------------------- +function loveframes.SplitString(str, pat) + local t = {} -- NOTE: use {n = 0} in Lua-5.0 + + if pat == " " then + local fpat = "(.-)" .. pat + local last_end = 1 + local s, e, cap = loveframes.utf8.find(str, fpat, 1) + while s do + if s ~= #str then + cap = cap .. " " + end + if s ~= 1 or cap ~= "" then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = loveframes.utf8.find(str, fpat, last_end) + end + if last_end <= #str then + cap = loveframes.utf8.sub(str, last_end) + table.insert(t, cap) + end + else + local fpat = "(.-)" .. pat + local last_end = 1 + local s, e, cap = loveframes.utf8.find(str, fpat, 1) + while s do + if s ~= 1 or cap ~= "" then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = loveframes.utf8.find(str, fpat, last_end) + end + if last_end <= #str then + cap = loveframes.utf8.sub(str, last_end) + table.insert(t, cap) + end + end + + return t +end + +--[[--------------------------------------------------------- + - func: RemoveAll() + - desc: removes all gui elements +--]]--------------------------------------------------------- +function loveframes.RemoveAll() + loveframes.base.children = {} + loveframes.base.internals = {} + + loveframes.hoverobject = false + loveframes.downobject = false + loveframes.modalobject = false + loveframes.inputobject = false + loveframes.hover = false +end + +--[[--------------------------------------------------------- + - func: TableHasValue(table, value) + - desc: checks to see if a table has a specific value +--]]--------------------------------------------------------- +function loveframes.TableHasValue(table, value) + for k, v in pairs(table) do + if v == value then + return true + end + end + + return false +end + +--[[--------------------------------------------------------- + - func: TableHasKey(table, key) + - desc: checks to see if a table has a specific key +--]]--------------------------------------------------------- +function loveframes.TableHasKey(table, key) + return table[key] ~= nil + +end + +--[[--------------------------------------------------------- + - func: Error(message) + - desc: displays a formatted error message +--]]--------------------------------------------------------- +function loveframes.Error(message) + error("[Love Frames] " ..message) +end + +--[[--------------------------------------------------------- + - func: GetCollisionCount() + - desc: gets the total number of objects colliding with + the mouse +--]]--------------------------------------------------------- +function loveframes.GetCollisionCount() + return loveframes.collisioncount +end + +--[[--------------------------------------------------------- + - func: GetHover() + - desc: returns loveframes.hover, can be used to check + if the mouse is colliding with a visible + Love Frames object +--]]--------------------------------------------------------- +function loveframes.GetHover() + return loveframes.hover +end + +--[[--------------------------------------------------------- + - func: RectangleCollisionCheck(rect1, rect2) + - desc: checks for a collision between two rectangles + based on two tables containing rectangle sizes + and positions +--]]--------------------------------------------------------- +function loveframes.RectangleCollisionCheck(rect1, rect2) + return loveframes.BoundingBox(rect1.x, rect2.x, rect1.y, rect2.y, rect1.width, rect2.width, rect1.height, rect2.height) +end + +--[[--------------------------------------------------------- + - func: DeepCopy(orig) + - desc: copies a table + - note: I take not credit for this function +--]]--------------------------------------------------------- +function loveframes.DeepCopy(orig) + local orig_type = type(orig) + local copy + if orig_type == 'table' then + copy = {} + for orig_key, orig_value in next, orig, nil do + copy[loveframes.DeepCopy(orig_key)] = loveframes.DeepCopy(orig_value) + end + setmetatable(copy, loveframes.DeepCopy(getmetatable(orig))) + else -- number, string, boolean, etc + copy = orig + end + return copy +end + +--[[--------------------------------------------------------- + - func: GetHoverObject() + - desc: returns loveframes.hoverobject +--]]--------------------------------------------------------- +function loveframes.GetHoverObject() + + return loveframes.hoverobject + +end + +--[[--------------------------------------------------------- + - func: IsCtrlDown() + - desc: checks for ctrl, for use with multiselect, copy, + paste, and such. On OS X it actually looks for cmd. +--]]--------------------------------------------------------- +function loveframes.IsCtrlDown() + if love._os == "OS X" then + return love.keyboard.isDown("lgui") or love.keyboard.isDown("rgui") + end + return love.keyboard.isDown("lctrl") or love.keyboard.isDown("rctrl") +end + +function loveframes.Color(s, a) + local r, g, b = string.match(s, '#?(%x%x)(%x%x)(%x%x)') + if r == nil then return end + return tonumber(r, 16) / 0xFF, tonumber(g, 16) / 0xFF, tonumber(b, 16) / 0xFF, a or 1 +end + +--[[--------------------------------------------------------- + - func: draw() + - desc: draws debug information +--]]--------------------------------------------------------- +function loveframes.DebugDraw() + local infox = 5 + local infoy = 40 + local topcol = {type = "None", children = {}, x = 0, y = 0, width = 0, height = 0} + local hoverobject = loveframes.hoverobject + --local objects = loveframes.GetAllObjects() + local version = loveframes.version + local stage = loveframes.stage + local basedir = loveframes.config["DIRECTORY"] + local loveversion = love._version + local fps = love.timer.getFPS() + local deltatime = love.timer.getDelta() + local font = loveframes.basicfontsmall + + if hoverobject then + topcol = hoverobject + end + + -- show frame docking zones + if topcol.type == "frame" then + for k, v in pairs(topcol.dockzones) do + love.graphics.setLineWidth(1) + love.graphics.setColor(255/255, 0, 0, 100/255) + love.graphics.rectangle("fill", v.x, v.y, v.width, v.height) + love.graphics.setColor(255/255, 0, 0, 255/255) + love.graphics.rectangle("line", v.x, v.y, v.width, v.height) + end + end + + -- outline the object that the mouse is hovering over + love.graphics.setColor(255/255, 204/255, 51/255, 255/255) + love.graphics.setLineWidth(2) + love.graphics.rectangle("line", topcol.x - 1, topcol.y - 1, topcol.width + 2, topcol.height + 2) + + -- draw main debug box + love.graphics.setFont(font) + love.graphics.setColor(0, 0, 0, 200/255) + love.graphics.rectangle("fill", infox, infoy, 200, 70) + love.graphics.setColor(255/255, 0, 0, 255/255) + love.graphics.print("Love Frames - Debug (" ..version.. " - " ..stage.. ")", infox + 5, infoy + 5) + love.graphics.setColor(255/255, 255/255, 255/255, 255/255) + love.graphics.print("LOVE Version: " ..loveversion, infox + 10, infoy + 20) + love.graphics.print("FPS: " ..fps, infox + 10, infoy + 30) + love.graphics.print("Delta Time: " ..deltatime, infox + 10, infoy + 40) + love.graphics.print("Total Objects: " ..loveframes.objectcount, infox + 10, infoy + 50) + + -- draw object information if needed + if topcol.type ~= "base" then + love.graphics.setColor(0, 0, 0, 200/255) + love.graphics.rectangle("fill", infox, infoy + 75, 200, 100) + love.graphics.setColor(255/255, 0, 0, 255/255) + love.graphics.print("Object Information", infox + 5, infoy + 80) + love.graphics.setColor(255/255, 255/255, 255/255, 255/255) + love.graphics.print("Type: " ..topcol.type, infox + 10, infoy + 95) + if topcol.children then + love.graphics.print("# of children: " .. #topcol.children, infox + 10, infoy + 105) + else + love.graphics.print("# of children: 0", infox + 10, infoy + 105) + end + if topcol.internals then + love.graphics.print("# of internals: " .. #topcol.internals, infox + 10, infoy + 115) + else + love.graphics.print("# of internals: 0", infox + 10, infoy + 115) + end + love.graphics.print("X: " ..topcol.x, infox + 10, infoy + 125) + love.graphics.print("Y: " ..topcol.y, infox + 10, infoy + 135) + love.graphics.print("Width: " ..topcol.width, infox + 10, infoy + 145) + love.graphics.print("Height: " ..topcol.height, infox + 10, infoy + 155) + end +end + +--return util + +---------- module end ---------- +end diff --git a/loveframes/license.txt b/loveframes/license.txt new file mode 100644 index 0000000..c71303f --- /dev/null +++ b/loveframes/license.txt @@ -0,0 +1,20 @@ +Copyright (c) 2014 Kenny Shields + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from +the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software in a +product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not +be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. diff --git a/loveframes/objects/base.lua b/loveframes/objects/base.lua new file mode 100644 index 0000000..67d8bda --- /dev/null +++ b/loveframes/objects/base.lua @@ -0,0 +1,1295 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- base object +local newobject = loveframes.NewObject("base", "loveframes_object_base") + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the element +--]]--------------------------------------------------------- +function newobject:initialize() + self.type = "base" + self.width, self.height = love.graphics.getDimensions() + self.internal = true + self.children = {} + self.internals = {} + +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the object +--]]--------------------------------------------------------- +function newobject:update(dt) + if loveframes.state ~= self.state then + return + end + + local width, height = love.graphics.getDimensions() + + if self.width ~= width then + self.width = width + end + + if self.height ~= height then + self.height = height + end + + local children = self.children + if children then + for k, v in ipairs(children) do + v:update(dt) + end + end + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + v:update(dt) + end + end +end + +--[[--------------------------------------------------------- + - func: draw() + - desc: draws the object +--]]--------------------------------------------------------- +function newobject:draw() + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + self:SetDrawOrder() + + local drawfunc = self.Draw or self.drawfunc + if drawfunc then + drawfunc(self) + end + + local children = self.children + if children then + for k, v in ipairs(children) do + v:draw() + end + end + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + v:draw() + end + end + + drawfunc = self.DrawOver or self.drawoverfunc + if drawfunc then + drawfunc(self) + end +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +function newobject:mousepressed(x, y, button) + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + local children = self.children + if children then + for k, v in ipairs(children) do + v:mousepressed(x, y, button) + end + end + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + v:mousepressed(x, y, button) + end + end +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + local children = self.children + if children then + for k, v in ipairs(children) do + v:mousereleased(x, y, button) + end + end + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + v:mousereleased(x, y, button) + end + end +end + +--[[--------------------------------------------------------- + - func: wheelmoved(x, y) + - desc: called when the player moves a mouse wheel +--]]--------------------------------------------------------- +function newobject:wheelmoved(x, y) + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + local children = self.children + if children then + for k, v in ipairs(children) do + v:wheelmoved(x, y) + end + end + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + v:wheelmoved(x, y) + end + end +end + +--[[--------------------------------------------------------- + - func: keypressed(key, isrepeat) + - desc: called when the player presses a key +--]]--------------------------------------------------------- +function newobject:keypressed(key, isrepeat) + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + local children = self.children + if children then + for k, v in ipairs(children) do + v:keypressed(key, isrepeat) + end + end + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + v:keypressed(key, isrepeat) + end + end +end + +--[[--------------------------------------------------------- + - func: keyreleased(key) + - desc: called when the player releases a key +--]]--------------------------------------------------------- +function newobject:keyreleased(key) + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + local children = self.children + if children then + for k, v in ipairs(children) do + v:keyreleased(key) + end + end + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + v:keyreleased(key) + end + end +end + + +--[[--------------------------------------------------------- + - func: textinput(text) + - desc: called when the user inputs text +--]]--------------------------------------------------------- +function newobject:textinput(text) + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + local children = self.children + if children then + for k, v in ipairs(children) do + v:textinput(text) + end + end + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + v:textinput(text) + end + end +end + + +--[[--------------------------------------------------------- + - func: SetPos(x, y, center) + - desc: sets the object's position +--]]--------------------------------------------------------- +function newobject:SetPos(x, y, center) + + local base = loveframes.base + local parent = self.parent + + if center then + local width = self.width + local height = self.height + x = x - width/2 + y = y - height/2 + end + + if parent == base then + self.x = x + self.y = y + else + self.staticx = x + self.staticy = y + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetX(x, center) + - desc: sets the object's x position +--]]--------------------------------------------------------- +function newobject:SetX(x, center) + + local base = loveframes.base + local parent = self.parent + + if center then + local width = self.width + x = x - width/2 + end + + if parent == base then + self.x = x + else + self.staticx = x + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetY(y, center) + - desc: sets the object's y position +--]]--------------------------------------------------------- +function newobject:SetY(y, center) + + local base = loveframes.base + local parent = self.parent + + if center then + local height = self.height + y = y - height/2 + end + + if parent == base then + self.y = y + else + self.staticy = y + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetPos() + - desc: gets the object's position +--]]--------------------------------------------------------- +function newobject:GetPos() + + return self.x, self.y + +end + +--[[--------------------------------------------------------- + - func: GetX() + - desc: gets the object's x position +--]]--------------------------------------------------------- +function newobject:GetX() + + return self.x + +end + +--[[--------------------------------------------------------- + - func: GetY() + - desc: gets the object's y position +--]]--------------------------------------------------------- +function newobject:GetY() + + return self.y + +end + +--[[--------------------------------------------------------- + - func: GetStaticPos() + - desc: gets the object's static position +--]]--------------------------------------------------------- +function newobject:GetStaticPos() + + return self.staticx, self.staticy + +end + +--[[--------------------------------------------------------- + - func: GetStaticX() + - desc: gets the object's static x position +--]]--------------------------------------------------------- +function newobject:GetStaticX() + + return self.staticx + +end + +--[[--------------------------------------------------------- + - func: GetStaticY() + - desc: gets the object's static y position +--]]--------------------------------------------------------- +function newobject:GetStaticY() + + return self.staticy + +end + +--[[--------------------------------------------------------- + - func: Center() + - desc: centers the object in the game window or in + its parent if it has one +--]]--------------------------------------------------------- +function newobject:Center() + + local base = loveframes.base + local parent = self.parent + + if parent == base then + local width = love.graphics.getWidth() + local height = love.graphics.getHeight() + self.x = width/2 - self.width * (self.scalex or 1)/2 + self.y = height/2 - self.height * (self.scaley or 1)/2 + else + local width = parent.width + local height = parent.height + self.staticx = width/2 - self.width * (self.scalex or 1)/2 + self.staticy = height/2 - self.height * (self.scaley or 1)/2 + end + + return self + +end + +--[[--------------------------------------------------------- + - func: CenterX() + - desc: centers the object by its x value +--]]--------------------------------------------------------- +function newobject:CenterX() + + local base = loveframes.base + local parent = self.parent + + if parent == base then + local width = love.graphics.getWidth() + self.x = width/2 - self.width * (self.scalex or 1)/2 + else + local width = parent.width + self.staticx = width/2 - self.width * (self.scalex or 1)/2 + end + + return self + +end + +--[[--------------------------------------------------------- + - func: CenterY() + - desc: centers the object by its y value +--]]--------------------------------------------------------- +function newobject:CenterY() + + local base = loveframes.base + local parent = self.parent + + if parent == base then + local height = love.graphics.getHeight() + self.y = height/2 - self.height * (self.scaley or 1)/2 + else + local height = parent.height + self.staticy = height/2 - self.height * (self.scaley or 1)/2 + end + + return self + +end + +--[[--------------------------------------------------------- + - func: CenterWithinArea() + - desc: centers the object within the given area +--]]--------------------------------------------------------- +function newobject:CenterWithinArea(x, y, width, height) + + local selfwidth = self.width + local selfheight = self.height + + self.x = x + width/2 - selfwidth/2 + self.y = y + height/2 - selfheight/2 + + return self + +end + +--[[--------------------------------------------------------- + - func: SetSize(width, height, r1, r2) + - desc: sets the object's size +--]]--------------------------------------------------------- +function newobject:SetSize(width, height, r1, r2) + + if r1 then + self.width = self.parent.width * width + else + self.width = width + end + + if r2 then + self.height = self.parent.height * height + else + self.height = height + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetWidth(width, relative) + - desc: sets the object's width +--]]--------------------------------------------------------- +function newobject:SetWidth(width, relative) + + if relative then + self.width = self.parent.width * width + else + self.width = width + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetHeight(height, relative) + - desc: sets the object's height +--]]--------------------------------------------------------- +function newobject:SetHeight(height, relative) + + if relative then + self.height = self.parent.height * height + else + self.height = height + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetSize() + - desc: gets the object's size +--]]--------------------------------------------------------- +function newobject:GetSize() + + return self.width, self.height + +end + +--[[--------------------------------------------------------- + - func: GetWidth() + - desc: gets the object's width +--]]--------------------------------------------------------- +function newobject:GetWidth() + + return self.width + +end + +--[[--------------------------------------------------------- + - func: GetHeight() + - desc: gets the object's height +--]]--------------------------------------------------------- +function newobject:GetHeight() + + return self.height + +end + +--[[--------------------------------------------------------- + - func: SetVisible(bool) + - desc: sets the object's visibility +--]]--------------------------------------------------------- +function newobject:SetVisible(bool) + + local children = self.children + local internals = self.internals + + self.visible = bool + + if children then + for k, v in ipairs(children) do + v:SetVisible(bool) + end + end + + if internals then + for k, v in ipairs(internals) do + v:SetVisible(bool) + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetVisible() + - desc: gets the object's visibility +--]]--------------------------------------------------------- +function newobject:GetVisible() + + return self.visible + +end + +--[[--------------------------------------------------------- + - func: SetParent(parent) + - desc: sets the object's parent +--]]--------------------------------------------------------- +function newobject:SetParent(parent) + + local tparent = parent + local cparent = self.parent + local ptype = tparent.type + local stype = self.type + + if ptype ~= "frame" and ptype ~= "panel" and ptype ~= "list" then + return + end + + self:Remove() + self.parent = tparent + self:SetState(tparent.state) + + table.insert(tparent.children, self) + return self + +end + +--[[--------------------------------------------------------- + - func: GetParent() + - desc: gets the object's parent +--]]--------------------------------------------------------- +function newobject:GetParent() + + local parent = self.parent + return parent + +end + +--[[--------------------------------------------------------- + - func: Remove() + - desc: removes the object +--]]--------------------------------------------------------- +function newobject:Remove() + + local pinternals = self.parent.internals + local pchildren = self.parent.children + + if pinternals then + for k, v in ipairs(pinternals) do + if v == self then + table.remove(pinternals, k) + end + end + end + + if pchildren then + for k, v in ipairs(pchildren) do + if v == self then + table.remove(pchildren, k) + end + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetClickBounds(x, y, width, height) + - desc: sets a boundary box for the object's collision + detection +--]]--------------------------------------------------------- +function newobject:SetClickBounds(x, y, width, height) + + local internals = self.internals + local children = self.children + + self.clickbounds = {x = x, y = y, width = width, height = height} + + if internals then + for k, v in ipairs(internals) do + v:SetClickBounds(x, y, width, height) + end + end + + if children then + for k, v in ipairs(children) do + v:SetClickBounds(x, y, width, height) + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetClickBounds() + - desc: gets the boundary box for the object's collision + detection +--]]--------------------------------------------------------- +function newobject:GetClickBounds() + + return self.clickbounds + +end + +--[[--------------------------------------------------------- + - func: RemoveClickBounds() + - desc: removes the collision detection boundary for the + object +--]]--------------------------------------------------------- +function newobject:RemoveClickBounds() + + local internals = self.internals + local children = self.children + + self.clickbounds = nil + + if internals then + for k, v in ipairs(internals) do + v:RemoveClickBounds() + end + end + + if children then + for k, v in ipairs(children) do + v:RemoveClickBounds() + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: InClickBounds() + - desc: checks if the mouse is inside the object's + collision detection boundaries +--]]--------------------------------------------------------- +function newobject:InClickBounds() + + local x, y = love.mouse.getPosition() + local bounds = self.clickbounds + + if bounds then + local col = loveframes.BoundingBox(x, bounds.x, y, bounds.y, 1, bounds.width, 1, bounds.height) + return col + else + return false + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetBaseParent(object, t) + - desc: finds the object's base parent +--]]--------------------------------------------------------- +function newobject:GetBaseParent(t) + + local t = t or {} + local base = loveframes.base + local parent = self.parent + + if parent ~= base then + table.insert(t, parent) + parent:GetBaseParent(t) + end + + return t[#t] + +end + +--[[--------------------------------------------------------- + - func: CheckHover() + - desc: checks to see if the object should be in a + hover state +--]]--------------------------------------------------------- +function newobject:CheckHover() + + local x = self.x + local y = self.y + local width = self.width + local height = self.height + local mx, my = love.mouse.getPosition() + local selfcol = loveframes.BoundingBox(mx, x, my, y, 1, width, 1, height) + local collisioncount = loveframes.collisioncount + local curstate = loveframes.state + local state = self.state + local visible = self.visible + local type = self.type + local hoverobject = loveframes.hoverobject + + -- check if the mouse is colliding with the object + if state == curstate and visible then + local collide = self.collide + if selfcol and collide then + loveframes.collisioncount = collisioncount + 1 + local clickbounds = self.clickbounds + if clickbounds then + local cx = clickbounds.x + local cy = clickbounds.y + local cwidth = clickbounds.width + local cheight = clickbounds.height + local clickcol = loveframes.BoundingBox(mx, cx, my, cy, 1, cwidth, 1, cheight) + if clickcol then + table.insert(loveframes.collisions, self) + end + else + table.insert(loveframes.collisions, self) + end + end + end + + -- check if the object is being hovered + if hoverobject == self and type ~= "base" then + self.hover = true + else + self.hover = false + end + + local hover = self.hover + local calledmousefunc = self.calledmousefunc + + -- check for mouse enter and exit events + if hover then + loveframes.hover = true + if not calledmousefunc then + local on_mouse_enter = self.OnMouseEnter + if on_mouse_enter then + on_mouse_enter(self) + self.calledmousefunc = true + else + self.calledmousefunc = true + end + end + else + if calledmousefunc then + local on_mouse_exit = self.OnMouseExit + if on_mouse_exit then + on_mouse_exit(self) + self.calledmousefunc = false + else + self.calledmousefunc = false + end + end + end + +end + +--[[--------------------------------------------------------- + - func: GetHover() + - desc: return if the object is in a hover state or not +--]]--------------------------------------------------------- +function newobject:GetHover() + + return self.hover + +end + +--[[--------------------------------------------------------- + - func: GetChildren() + - desc: returns the object's children +--]]--------------------------------------------------------- +function newobject:GetChildren() + + local children = self.children + + if children then + return children + end + +end + +--[[--------------------------------------------------------- + - func: GetInternals() + - desc: returns the object's internals +--]]--------------------------------------------------------- +function newobject:GetInternals() + + local internals = self.internals + + if internals then + return internals + end + +end + + +--[[--------------------------------------------------------- + - func: IsTopList() + - desc: returns true if the object is the top most list + object or false if not +--]]--------------------------------------------------------- +function newobject:IsTopList() + + local cols = loveframes.GetCollisions() + local children = self:GetChildren() + local order = self.draworder + local top = true + local found = false + + local function IsChild(object) + local parents = object:GetParents() + for k, v in ipairs(parents) do + if v == self then + return true + end + end + return false + end + + for k, v in ipairs(cols) do + if v == self then + found = true + else + if v.draworder > order then + if IsChild(v) ~= true then + top = false + break + end + end + end + end + + if found == false then + top = false + end + + return top + +end + +--[[--------------------------------------------------------- + - func: IsTopChild() + - desc: returns true if the object is the top most child + in its parent's children table or false if not +--]]--------------------------------------------------------- +function newobject:IsTopChild() + + local children = self.parent.children + local num = #children + + if children[num] == self then + return true + else + return false + end + +end + +--[[--------------------------------------------------------- + - func: MoveToTop() + - desc: moves the object to the top of its parent's + children table +--]]--------------------------------------------------------- +function newobject:MoveToTop() + + local pchildren = self.parent.children + local pinternals = self.parent.internals + + local internal = false + + if pinternals then + for k, v in ipairs(pinternals) do + if v == self then + internal = true + end + end + end + + self:Remove() + + if internal then + table.insert(pinternals, self) + else + table.insert(pchildren, self) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetDrawFunc() + - desc: sets the objects skin based draw function +--]]--------------------------------------------------------- +function newobject:SetDrawFunc() + local skins = loveframes.skins + local activeskin = skins[loveframes.config["ACTIVESKIN"]] + --local defaultskin = skins[loveframes.config["DEFAULTSKIN"]] + + local funcname = self.type + self.drawfunc = activeskin[funcname] -- or defaultskin[funcname] + + funcname = self.type .. "_over" + self.drawoverfunc = activeskin[funcname] -- or defaultskin[funcname] +end + +--[[--------------------------------------------------------- + - func: SetSkin(name) + - desc: sets the object's skin +--]]--------------------------------------------------------- +function newobject:SetSkin(name) + + local children = self.children + local internals = self.internals + + self.skin = name + + local selfskin = loveframes.skins[name] + + local funcname = self.type + + self.drawfunc = selfskin[funcname] + self.drawoverfunc = selfskin[funcname.."_over"] + + if children then + for k, v in ipairs(children) do + v:SetSkin(name) + end + end + + if internals then + for k, v in ipairs(internals) do + v:SetSkin(name) + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetSkin() + - desc: gets the object's skin +--]]--------------------------------------------------------- +function newobject:GetSkin() + + local skins = loveframes.skins + local skinindex = loveframes.config["ACTIVESKIN"] + local defaultskin = loveframes.config["DEFAULTSKIN"] + local selfskin = self.skin + local skin = skins[selfskin] or skins[skinindex] + + return skin + +end + +--[[--------------------------------------------------------- + - func: GetSkinName() + - desc: gets the name of the object's skin +--]]--------------------------------------------------------- +function newobject:GetSkinName() + + return self.skin + +end + +--[[--------------------------------------------------------- + - func: SetAlwaysUpdate(bool) + - desc: sets the object's skin +--]]--------------------------------------------------------- +function newobject:SetAlwaysUpdate(bool) + + self.alwaysupdate = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetAlwaysUpdate() + - desc: gets whether or not the object will always update +--]]--------------------------------------------------------- +function newobject:GetAlwaysUpdate() + + return self.alwaysupdate + +end + +--[[--------------------------------------------------------- + - func: SetRetainSize(bool) + - desc: sets whether or not the object should retain its + size when another object tries to resize it +--]]--------------------------------------------------------- +function newobject:SetRetainSize(bool) + + self.retainsize = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetRetainSize() + - desc: gets whether or not the object should retain its + size when another object tries to resize it +--]]--------------------------------------------------------- +function newobject:GetRetainSize() + + return self.retainsize + +end + +--[[--------------------------------------------------------- + - func: IsActive() + - desc: gets whether or not the object is active within + its parent's child table +--]]--------------------------------------------------------- +function newobject:IsActive() + + local parent = self.parent + local pchildren = parent.children + local valid = false + + for k, v in ipairs(pchildren) do + if v == self then + valid = true + end + end + + return valid + +end + +--[[--------------------------------------------------------- + - func: GetParents() + - desc: returns a table of the object's parents and its + sub-parents +--]]--------------------------------------------------------- +function newobject:GetParents() + + local function GetParents(object, t) + local t = t or {} + local type = object.type + local parent = object.parent + if type ~= "base" then + table.insert(t, parent) + GetParents(parent, t) + end + return t + end + + local parents = GetParents(self) + return parents + +end + +--[[--------------------------------------------------------- + - func: IsTopInternal() + - desc: returns true if the object is the top most + internal in its parent's internals table or + false if not +--]]--------------------------------------------------------- +function newobject:IsTopInternal() + + local parent = self.parent + local internals = parent.internals + local topitem = internals[#internals] + + if topitem ~= self then + return false + else + return true + end + +end + +--[[--------------------------------------------------------- + - func: IsInternal() + - desc: returns true if the object is internal or + false if not +--]]--------------------------------------------------------- +function newobject:IsInternal() + + return self.internal + +end + +--[[--------------------------------------------------------- + - func: GetType() + - desc: gets the type of the object +--]]--------------------------------------------------------- +function newobject:GetType() + + return self.type + +end + +--[[--------------------------------------------------------- + - func: SetDrawOrder() + - desc: sets the object's draw order +--]]--------------------------------------------------------- +function newobject:SetDrawOrder() + + loveframes.drawcount = loveframes.drawcount + 1 + self.draworder = loveframes.drawcount + return self + +end + +--[[--------------------------------------------------------- + - func: GetDrawOrder() + - desc: sets the object's draw order +--]]--------------------------------------------------------- +function newobject:GetDrawOrder() + + return self.draworder + +end + +--[[--------------------------------------------------------- + - func: SetProperty(name, value) + - desc: sets a property on the object +--]]--------------------------------------------------------- +function newobject:SetProperty(name, value) + + self[name] = value + return self + +end + +--[[--------------------------------------------------------- + - func: GetProperty(name) + - desc: gets the value of an object's property +--]]--------------------------------------------------------- +function newobject:GetProperty(name) + + return self[name] + +end + +--[[--------------------------------------------------------- + - func: IsInList() + - desc: checks to see if an object is in a list +--]]--------------------------------------------------------- +function newobject:IsInList() + + local parents = self:GetParents() + + for k, v in ipairs(parents) do + if v.type == "list" then + return true, v + end + end + + return false, false + +end + +--[[--------------------------------------------------------- + - func: SetState(name) + - desc: sets the object's state +--]]--------------------------------------------------------- +function newobject:SetState(name) + + local children = self.children + local internals = self.internals + + self.state = name + + if children then + for k, v in ipairs(children) do + v:SetState(name) + end + end + + if internals then + for k, v in ipairs(internals) do + v:SetState(name) + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetState() + - desc: gets the object's state +--]]--------------------------------------------------------- +function newobject:GetState() + + return self.state + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/button.lua b/loveframes/objects/button.lua new file mode 100644 index 0000000..b3877a6 --- /dev/null +++ b/loveframes/objects/button.lua @@ -0,0 +1,298 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- button object +local newobject = loveframes.NewObject("button", "loveframes_object_button", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "button" + self.text = "Button" + self.width = 80 + self.height = 25 + self.internal = false + self.down = false + self.clickable = true + self.enabled = true + self.toggleable = false + self.toggle = false + self.OnClick = nil + self.groupIndex = 0 + self.checked = false + + self:SetDrawFunc() +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 down = self.down + local downobject = loveframes.downobject + local parent = self.parent + local base = loveframes.base + local update = self.Update + + if not hover then + self.down = false + if downobject == self then + self.hover = true + end + else + if downobject == self then + self.down = true + 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: 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 + + local hover = self.hover + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + self.down = true + loveframes.downobject = self + 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 down = self.down + local clickable = self.clickable + local enabled = self.enabled + local onclick = self.OnClick + + if hover and down and clickable and button == 1 then + if enabled then + if self.groupIndex ~= 0 then + local baseparent = self.parent + if baseparent then + for k, v in ipairs(baseparent.children) do + if v.groupIndex then + if v.groupIndex == self.groupIndex then + v.checked = false + end + end + end + end + self.checked = true + end + if onclick then + onclick(self, x, y) + end + if self.toggleable then + local ontoggle = self.OnToggle + self.toggle = not self.toggle + if ontoggle then + ontoggle(self, self.toggle) + end + end + end + end + + self.down = false + +end + +--[[--------------------------------------------------------- + - func: SetText(text) + - desc: sets the object's text +--]]--------------------------------------------------------- +function newobject:SetText(text) + + self.text = text + return self + +end + +--[[--------------------------------------------------------- + - func: GetText() + - desc: gets the object's text +--]]--------------------------------------------------------- +function newobject:GetText() + + return self.text + +end + +--[[--------------------------------------------------------- + - func: SetImage(image) + - desc: adds an image to the object +--]]--------------------------------------------------------- +function newobject:SetImage(image) + + if type(image) == "string" then + self.image = love.graphics.newImage(image) + self.image:setFilter("nearest", "nearest") + else + self.image = image + end +end + +--[[--------------------------------------------------------- + - func: GetImage() + - desc: gets the object's image +--]]--------------------------------------------------------- +function newobject:GetImage() + + return self.image + +end + +--[[--------------------------------------------------------- + - func: SetClickable(bool) + - desc: sets whether the object can be clicked or not +--]]--------------------------------------------------------- +function newobject:SetClickable(bool) + + self.clickable = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetClickable(bool) + - desc: gets whether the object can be clicked or not +--]]--------------------------------------------------------- +function newobject:GetClickable() + + return self.clickable + +end + +--[[--------------------------------------------------------- + - func: SetClickable(bool) + - desc: sets whether or not the object is enabled +--]]--------------------------------------------------------- +function newobject:SetEnabled(bool) + + self.enabled = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetEnabled() + - desc: gets whether or not the object is enabled +--]]--------------------------------------------------------- +function newobject:GetEnabled() + + return self.enabled + +end + +--[[--------------------------------------------------------- + - func: GetDown() + - desc: gets whether or not the object is currently + being pressed +--]]--------------------------------------------------------- +function newobject:GetDown() + + return self.down + +end + +--[[--------------------------------------------------------- + - func: SetToggleable(bool) + - desc: sets whether or not the object is toggleable +--]]--------------------------------------------------------- +function newobject:SetToggleable(bool) + + self.toggleable = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetToggleable() + - desc: gets whether or not the object is toggleable +--]]--------------------------------------------------------- +function newobject:GetToggleable() + + return self.toggleable + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/checkbox.lua b/loveframes/objects/checkbox.lua new file mode 100644 index 0000000..14d4477 --- /dev/null +++ b/loveframes/objects/checkbox.lua @@ -0,0 +1,429 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- checkbox object +local newobject = loveframes.NewObject("checkbox", "loveframes_object_checkbox", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + self.type = "checkbox" + self.width = 0 + self.height = 0 + self.boxwidth = 16 + self.boxheight = 16 + self.font = loveframes.basicfont + self.checked = false + self.lastvalue = false + self.internal = false + self.down = true + self.enabled = true + self.internals = {} + self.OnChanged = nil + self.groupIndex = 0 + + self:SetDrawFunc() +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 internals = self.internals + local boxwidth = self.boxwidth + local boxheight = self.boxheight + local parent = self.parent + local base = loveframes.base + local update = self.Update + + if not hover then + self.down = false + else + if loveframes.downobject == self then + self.down = true + end + end + + if not self.down and loveframes.downobject == self then + self.hover = true + end + + -- move to parent if there is a parent + if parent ~= base and parent.type ~= "list" then + self.x = self.parent.x + self.staticx + self.y = self.parent.y + self.staticy + end + + if internals[1] then + self.width = boxwidth + 5 + internals[1].width + if internals[1].height == boxheight then + self.height = boxheight + else + if internals[1].height > boxheight then + self.height = internals[1].height + else + self.height = boxheight + end + end + else + self.width = boxwidth + self.height = boxheight + end + + for k, v in ipairs(internals) do + v:update(dt) + end + + if update then + update(self, dt) + 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 + + local hover = self.hover + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + self.down = true + loveframes.downobject = self + 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 down = self.down + local enabled = self.enabled + local checked = self.checked + local onchanged = self.OnChanged + + if hover and down and enabled and button == 1 then + if checked then + if self.groupIndex == 0 then self.checked = false end + else + if self.groupIndex ~= 0 then + local baseparent = self.parent + if baseparent then + for k, v in ipairs(baseparent.children) do + if v.groupIndex then + if v.groupIndex == self.groupIndex then + v.checked = false + end + end + end + end + end + self.checked = true + end + if onchanged then + onchanged(self, self.checked) + end + end + +end + +--[[--------------------------------------------------------- + - func: SetText(text) + - desc: sets the object's text +--]]--------------------------------------------------------- +function newobject:SetText(text) + + local boxwidth = self.boxwidth + local boxheight = self.boxheight + + if text ~= "" then + self.internals = {} + local textobject = loveframes.Create("text") + local skin = loveframes.GetActiveSkin() + if not skin then + skin = loveframes.config["DEFAULTSKIN"] + end + local directives = skin.directives + if directives then + local default_color = directives.checkbox_text_default_color + local default_shadowcolor = directives.checkbox_text_default_shadowcolor + local default_font = directives.checkbox_text_default_font + if default_color then + textobject.defaultcolor = default_color + end + if default_shadowcolor then + textobject.shadowcolor = default_shadowcolor + end + if default_font then + self.font = default_font + end + end + textobject:Remove() + textobject.parent = self + textobject.state = self.state + textobject.collide = false + textobject:SetFont(self.font) + textobject:SetText(text) + textobject.Update = function(object, dt) + if object.height > boxheight then + object:SetPos(boxwidth + 5, 0) + else + object:SetPos(boxwidth + 5, boxheight/2 - object.height/2) + end + end + table.insert(self.internals, textobject) + else + self.width = boxwidth + self.height = boxheight + self.internals = {} + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetText() + - desc: gets the object's text +--]]--------------------------------------------------------- +function newobject:GetText() + + local internals = self.internals + local text = internals[1] + + if text then + return text.text + else + return false + end + +end + +--[[--------------------------------------------------------- + - func: SetSize(width, height, r1, r2) + - desc: sets the object's size +--]]--------------------------------------------------------- +function newobject:SetSize(width, height, r1, r2) + + if r1 then + self.boxwidth = self.parent.width * width + else + self.boxwidth = width + end + + if r2 then + self.boxheight = self.parent.height * height + else + self.boxheight = height + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetWidth(width, relative) + - desc: sets the object's width +--]]--------------------------------------------------------- +function newobject:SetWidth(width, relative) + + if relative then + self.boxwidth = self.parent.width * width + else + self.boxwidth = width + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetHeight(height, relative) + - desc: sets the object's height +--]]--------------------------------------------------------- +function newobject:SetHeight(height, relative) + + if relative then + self.boxheight = self.parent.height * height + else + self.boxheight = height + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetChecked(bool) + - desc: sets whether the object is checked or not +--]]--------------------------------------------------------- +function newobject:SetChecked(bool) + + local onchanged = self.OnChanged + + self.checked = bool + + if onchanged then + onchanged(self) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetChecked() + - desc: gets whether the object is checked or not +--]]--------------------------------------------------------- +function newobject:GetChecked() + + return self.checked + +end + +--[[--------------------------------------------------------- + - func: SetFont(font) + - desc: sets the font of the object's text +--]]--------------------------------------------------------- +function newobject:SetFont(font) + + local internals = self.internals + local text = internals[1] + + self.font = font + + if text then + text:SetFont(font) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: newobject:GetFont() + - desc: gets the font of the object's text +--]]--------------------------------------------------------- +function newobject:GetFont() + + return self.font + +end + +--[[--------------------------------------------------------- + - func: newobject:GetBoxHeight() + - desc: gets the object's box size +--]]--------------------------------------------------------- +function newobject:GetBoxSize() + + return self.boxwidth, self.boxheight + +end + +--[[--------------------------------------------------------- + - func: newobject:GetBoxWidth() + - desc: gets the object's box width +--]]--------------------------------------------------------- +function newobject:GetBoxWidth() + + return self.boxwidth + +end + +--[[--------------------------------------------------------- + - func: newobject:GetBoxHeight() + - desc: gets the object's box height +--]]--------------------------------------------------------- +function newobject:GetBoxHeight() + + return self.boxheight + +end + +--[[--------------------------------------------------------- + - func: SetClickable(bool) + - desc: sets whether or not the object is enabled +--]]--------------------------------------------------------- +function newobject:SetEnabled(bool) + + self.enabled = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetEnabled() + - desc: gets whether or not the object is enabled +--]]--------------------------------------------------------- +function newobject:GetEnabled() + + return self.enabled + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/collapsiblecategory.lua b/loveframes/objects/collapsiblecategory.lua new file mode 100644 index 0000000..fdd8d6e --- /dev/null +++ b/loveframes/objects/collapsiblecategory.lua @@ -0,0 +1,328 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- collapsiblecategory object +local newobject = loveframes.NewObject("collapsiblecategory", "loveframes_object_collapsiblecategory", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "collapsiblecategory" + self.text = "Category" + self.width = 200 + self.height = 25 + self.closedheight = 25 + self.padding = 5 + self.internal = false + self.open = false + self.down = false + self.children = {} + self.OnOpenedClosed = nil + + self:SetDrawFunc() +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 + + local open = self.open + local children = self.children + local curobject = children[1] + local parent = self.parent + local base = loveframes.base + local update = self.Update + + self:CheckHover() + + -- move to parent if there is a parent + if parent ~= base and parent.type ~= "list" then + self.x = self.parent.x + self.staticx + self.y = self.parent.y + self.staticy + end + + if open and curobject then + curobject:SetWidth(self.width - self.padding * 2) + curobject:update(dt) + elseif not open and curobject then + if curobject:GetVisible() then + curobject:SetVisible(false) + end + end + + if update then + update(self, dt) + 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 + + local hover = self.hover + local open = self.open + local children = self.children + local curobject = children[1] + + if hover then + local col = loveframes.BoundingBox(self.x, x, self.y, y, self.width, 1, self.closedheight, 1) + if button == 1 and col then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + self.down = true + loveframes.downobject = self + end + end + + if open and curobject then + curobject:mousepressed(x, y, button) + 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 down = self.down + local clickable = self.clickable + local enabled = self.enabled + local open = self.open + local col = loveframes.BoundingBox(self.x, x, self.y, y, self.width, 1, self.closedheight, 1) + local children = self.children + local curobject = children[1] + + if hover and col and down and button == 1 then + if open then + self:SetOpen(false) + else + self:SetOpen(true) + end + self.down = false + end + + if open and curobject then + curobject:mousereleased(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: SetText(text) + - desc: sets the object's text +--]]--------------------------------------------------------- +function newobject:SetText(text) + + self.text = text + return self + +end + +--[[--------------------------------------------------------- + - func: GetText() + - desc: gets the object's text +--]]--------------------------------------------------------- +function newobject:GetText() + + return self.text + +end + +--[[--------------------------------------------------------- + - func: SetObject(object) + - desc: sets the category's object +--]]--------------------------------------------------------- +function newobject:SetObject(object) + + local children = self.children + local curobject = children[1] + + if curobject then + curobject:Remove() + self.children = {} + end + + object:Remove() + object.parent = self + object:SetState(self.state) + object:SetWidth(self.width - self.padding*2) + object:SetPos(self.padding, self.closedheight + self.padding) + table.insert(self.children, object) + + return self + +end + +--[[--------------------------------------------------------- + - func: SetObject(object) + - desc: sets the category's object +--]]--------------------------------------------------------- +function newobject:GetObject() + + local children = self.children + local curobject = children[1] + + if curobject then + return curobject + else + return false + end + +end + +--[[--------------------------------------------------------- + - func: SetSize(width, height, relative) + - desc: sets the object's size +--]]--------------------------------------------------------- +function newobject:SetSize(width, height, relative) + + if relative then + self.width = self.parent.width * width + else + self.width = width + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetHeight(height) + - desc: sets the object's height +--]]--------------------------------------------------------- +function newobject:SetHeight(height) + + return self + +end + +--[[--------------------------------------------------------- + - func: SetClosedHeight(height) + - desc: sets the object's closed height +--]]--------------------------------------------------------- +function newobject:SetClosedHeight(height) + + self.closedheight = height + return self + +end + +--[[--------------------------------------------------------- + - func: GetClosedHeight() + - desc: gets the object's closed height +--]]--------------------------------------------------------- +function newobject:GetClosedHeight() + + return self.closedheight + +end + +--[[--------------------------------------------------------- + - func: SetOpen(bool) + - desc: sets whether the object is opened or closed +--]]--------------------------------------------------------- +function newobject:SetOpen(bool) + + local children = self.children + local curobject = children[1] + local closedheight = self.closedheight + local padding = self.padding + local onopenedclosed = self.OnOpenedClosed + + self.open = bool + + if not bool then + self.height = closedheight + if curobject then + local curobjectheight = curobject.height + curobject:SetVisible(false) + end + else + if curobject then + local curobjectheight = curobject.height + self.height = closedheight + padding * 2 + curobjectheight + curobject:SetVisible(true) + end + end + + -- call the on opened closed callback if it exists + if onopenedclosed then + onopenedclosed(self) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetOpen() + - desc: gets whether the object is opened or closed +--]]--------------------------------------------------------- +function newobject:GetOpen() + + return self.open + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/columnlist.lua b/loveframes/objects/columnlist.lua new file mode 100644 index 0000000..5872f92 --- /dev/null +++ b/loveframes/objects/columnlist.lua @@ -0,0 +1,984 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- columnlist object +local newobject = loveframes.NewObject("columnlist", "loveframes_object_columnlist", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: intializes the element +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "columnlist" + self.width = 300 + self.height = 100 + self.defaultcolumnwidth = 100 + self.columnheight = 16 + self.buttonscrollamount = 200 + self.mousewheelscrollamount = 1500 + self.autoscroll = false + self.dtscrolling = true + self.internal = false + self.selectionenabled = true + self.multiselect = false + self.startadjustment = false + self.canresizecolumns = true + self.children = {} + self.internals = {} + self.resizecolumn = nil + self.OnRowClicked = nil + self.OnRowRightClicked = nil + self.OnRowSelected = nil + self.OnScroll = nil + + local list = loveframes.objects["columnlistarea"]:new(self) + table.insert(self.internals, list) + + self:SetDrawFunc() +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 + + local parent = self.parent + local base = loveframes.base + local children = self.children + local internals = self.internals + local update = self.Update + + self:CheckHover() + + -- 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(internals) do + v:update(dt) + end + + for k, v in ipairs(children) do + v.columnid = k + v:update(dt) + end + + self.startadjustment = false + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: draw() + - desc: draws the object +--]]--------------------------------------------------------- +function newobject:draw() + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + local vbody = self.internals[1]:GetVerticalScrollBody() + local hbody = self.internals[1]:GetHorizontalScrollBody() + local width = self.width + local height = self.height + + if vbody then + width = width - vbody.width + end + + if hbody then + height = height - hbody.height + end + + local stencilfunc = function() + love.graphics.rectangle("fill", self.x, self.y, width, height) + end + + -- set the object's draw order + self:SetDrawOrder() + + local drawfunc = self.Draw or self.drawfunc + if drawfunc then + drawfunc(self) + end + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + v:draw() + end + end + + love.graphics.stencil(stencilfunc) + love.graphics.setStencilTest("greater", 0) + + local children = self.children + if children then + for k, v in ipairs(children) do + v:draw() + end + end + + local drawfunc = self.DrawOver or self.drawoverfunc + if drawfunc then + drawfunc(self) + end + love.graphics.setStencilTest() + +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 + + local hover = self.hover + local children = self.children + local internals = self.internals + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + end + + for k, v in ipairs(internals) do + v:mousepressed(x, y, button) + end + + for k, v in ipairs(children) do + v:mousepressed(x, y, button) + 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 children = self.children + local internals = self.internals + + for k, v in ipairs(internals) do + v:mousereleased(x, y, button) + end + + for k, v in ipairs(children) do + v:mousereleased(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: PositionColumns() + - desc: positions the object's columns +--]]--------------------------------------------------------- +function newobject:PositionColumns() + + local x = 0 + + for k, v in ipairs(self.children) do + v:SetPos(x, 0) + x = x + v.width + end + + return self + +end + +--[[--------------------------------------------------------- + - func: AddColumn(name) + - desc: gives the object a new column with the specified + name +--]]--------------------------------------------------------- +function newobject:AddColumn(name) + + local internals = self.internals + local list = internals[1] + local width = self.width + local height = self.height + + loveframes.objects["columnlistheader"]:new(name, self) + self:PositionColumns() + + list:SetSize(width, height) + list:SetPos(0, 0) + + return self + +end + +--[[--------------------------------------------------------- + - func: AddRow(...) + - desc: adds a row of data to the object's list +--]]--------------------------------------------------------- +function newobject:AddRow(...) + + local arg = {...} + local internals = self.internals + local list = internals[1] + + list:AddRow(arg) + return self + +end + +--[[--------------------------------------------------------- + - func: Getchildrenize() + - desc: gets the size of the object's children +--]]--------------------------------------------------------- +function newobject:GetColumnSize() + + local children = self.children + local numchildren = #self.children + + if numchildren > 0 then + local column = self.children[1] + local colwidth = column.width + local colheight = column.height + return colwidth, colheight + else + return 0, 0 + end + +end + +--[[--------------------------------------------------------- + - func: SetSize(width, height, r1, r2) + - desc: sets the object's size +--]]--------------------------------------------------------- +function newobject:SetSize(width, height, r1, r2) + + local internals = self.internals + local list = internals[1] + + if r1 then + self.width = self.parent.width * width + else + self.width = width + end + + if r2 then + self.height = self.parent.height * height + else + self.height = height + end + + self:PositionColumns() + + list:SetSize(width, height) + list:SetPos(0, 0) + list:CalculateSize() + list:RedoLayout() + + return self + +end + +--[[--------------------------------------------------------- + - func: SetWidth(width, relative) + - desc: sets the object's width +--]]--------------------------------------------------------- +function newobject:SetWidth(width, relative) + + local internals = self.internals + local list = internals[1] + + if relative then + self.width = self.parent.width * width + else + self.width = width + end + + self:PositionColumns() + + list:SetSize(width) + list:SetPos(0, 0) + list:CalculateSize() + list:RedoLayout() + + return self + +end + +--[[--------------------------------------------------------- + - func: SetHeight(height, relative) + - desc: sets the object's height +--]]--------------------------------------------------------- +function newobject:SetHeight(height, relative) + + local internals = self.internals + local list = internals[1] + + if relative then + self.height = self.parent.height * height + else + self.height = height + end + + self:PositionColumns() + + list:SetSize(height) + list:SetPos(0, 0) + list:CalculateSize() + list:RedoLayout() + + return self + +end + +--[[--------------------------------------------------------- + - func: SetMaxColorIndex(num) + - desc: sets the object's max color index for + alternating row colors +--]]--------------------------------------------------------- +function newobject:SetMaxColorIndex(num) + + local internals = self.internals + local list = internals[1] + + list.colorindexmax = num + return self + +end + +--[[--------------------------------------------------------- + - func: Clear() + - desc: removes all items from the object's list +--]]--------------------------------------------------------- +function newobject:Clear() + + local internals = self.internals + local list = internals[1] + + list:Clear() + return self + +end + +--[[--------------------------------------------------------- + - func: SetAutoScroll(bool) + - desc: sets whether or not the list's scrollbar should + auto scroll to the bottom when a new object is + added to the list +--]]--------------------------------------------------------- +function newobject:SetAutoScroll(bool) + + local internals = self.internals + local list = internals[1] + local scrollbar = list:GetScrollBar() + + self.autoscroll = bool + + if list then + if scrollbar then + scrollbar.autoscroll = bool + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetButtonScrollAmount(speed) + - desc: sets the scroll amount of the object's scrollbar + buttons +--]]--------------------------------------------------------- +function newobject:SetButtonScrollAmount(amount) + + self.buttonscrollamount = amount + self.internals[1].buttonscrollamount = amount + return self + +end + +--[[--------------------------------------------------------- + - func: GetButtonScrollAmount() + - desc: gets the scroll amount of the object's scrollbar + buttons +--]]--------------------------------------------------------- +function newobject:GetButtonScrollAmount() + + return self.buttonscrollamount + +end + +--[[--------------------------------------------------------- + - func: SetMouseWheelScrollAmount(amount) + - desc: sets the scroll amount of the mouse wheel +--]]--------------------------------------------------------- +function newobject:SetMouseWheelScrollAmount(amount) + + self.mousewheelscrollamount = amount + self.internals[1].mousewheelscrollamount = amount + return self + +end + +--[[--------------------------------------------------------- + - func: GetMouseWheelScrollAmount() + - desc: gets the scroll amount of the mouse wheel +--]]--------------------------------------------------------- +function newobject:GetButtonScrollAmount() + + return self.mousewheelscrollamount + +end + +--[[--------------------------------------------------------- + - func: SetColumnHeight(height) + - desc: sets the height of the object's columns +--]]--------------------------------------------------------- +function newobject:SetColumnHeight(height) + + local children = self.children + local internals = self.internals + local list = internals[1] + + self.columnheight = height + + for k, v in ipairs(children) do + v:SetHeight(height) + end + + list:CalculateSize() + list:RedoLayout() + return self + +end + +--[[--------------------------------------------------------- + - func: SetDTScrolling(bool) + - desc: sets whether or not the object should use delta + time when scrolling +--]]--------------------------------------------------------- +function newobject:SetDTScrolling(bool) + + self.dtscrolling = bool + self.internals[1].dtscrolling = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetDTScrolling() + - desc: gets whether or not the object should use delta + time when scrolling +--]]--------------------------------------------------------- +function newobject:GetDTScrolling() + + return self.dtscrolling + +end + +--[[--------------------------------------------------------- + - func: SelectRow(row, ctrl) + - desc: selects the specfied row in the object's list + of rows +--]]--------------------------------------------------------- +function newobject:SelectRow(row, ctrl) + + local selectionenabled = self.selectionenabled + + if not selectionenabled then + return + end + + local list = self.internals[1] + local children = list.children + local multiselect = self.multiselect + local onrowselected = self.OnRowSelected + + for k, v in ipairs(children) do + if v == row then + if v.selected and ctrl then + v.selected = false + else + v.selected = true + if onrowselected then + onrowselected(self, row, row:GetColumnData()) + end + end + elseif v ~= row then + if not (multiselect and ctrl) then + v.selected = false + end + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: DeselectRow(row) + - desc: deselects the specfied row in the object's list + of rows +--]]--------------------------------------------------------- +function newobject:DeselectRow(row) + + row.selected = false + return self + +end + +--[[--------------------------------------------------------- + - func: GetSelectedRows() + - desc: gets the object's selected rows +--]]--------------------------------------------------------- +function newobject:GetSelectedRows() + + local rows = {} + local list = self.internals[1] + local children = list.children + + for k, v in ipairs(children) do + if v.selected then + table.insert(rows, v) + end + end + + return rows + +end + +--[[--------------------------------------------------------- + - func: SetSelectionEnabled(bool) + - desc: sets whether or not the object's rows can be + selected +--]]--------------------------------------------------------- +function newobject:SetSelectionEnabled(bool) + + self.selectionenabled = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetSelectionEnabled() + - desc: gets whether or not the object's rows can be + selected +--]]--------------------------------------------------------- +function newobject:GetSelectionEnabled() + + return self.selectionenabled + +end + +--[[--------------------------------------------------------- + - func: SetMultiselectEnabled(bool) + - desc: sets whether or not the object can have more + than one row selected +--]]--------------------------------------------------------- +function newobject:SetMultiselectEnabled(bool) + + self.multiselect = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetMultiselectEnabled() + - desc: gets whether or not the object can have more + than one row selected +--]]--------------------------------------------------------- +function newobject:GetMultiselectEnabled() + + return self.multiselect + +end + +--[[--------------------------------------------------------- + - func: RemoveColumn(id) + - desc: removes a column +--]]--------------------------------------------------------- +function newobject:RemoveColumn(id) + + local children = self.children + + for k, v in ipairs(children) do + if k == id then + v:Remove() + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetColumnName(id, name) + - desc: sets a column's name +--]]--------------------------------------------------------- +function newobject:SetColumnName(id, name) + + local children = self.children + + for k, v in ipairs(children) do + if k == id then + v.name = name + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetColumnName(id) + - desc: gets a column's name +--]]--------------------------------------------------------- +function newobject:GetColumnName(id) + + local children = self.children + + for k, v in ipairs(children) do + if k == id then + return v.name + end + end + + return false + +end + +--[[--------------------------------------------------------- + - func: SizeToChildren(max) + - desc: sizes the object to match the combined height + of its children + - note: Credit to retupmoc258, the original author of + this method. This version has a few slight + modifications. +--]]--------------------------------------------------------- +function newobject:SizeToChildren(max) + + local oldheight = self.height + local list = self.internals[1] + local listchildren = list.children + local children = self.children + local width = self.width + local buf = children[1].height + local h = listchildren[1].height + local c = #listchildren + local height = buf + h*c + + if max then + height = math.min(max, oldheight) + end + + self:SetSize(width, height) + self:PositionColumns() + return self + +end + +--[[--------------------------------------------------------- + - func: RemoveRow(id) + - desc: removes a row from the object's list +--]]--------------------------------------------------------- +function newobject:RemoveRow(id) + + local list = self.internals[1] + local listchildren = list.children + local row = listchildren[id] + + if row then + row:Remove() + end + + list:CalculateSize() + list:RedoLayout() + return self + +end + +--[[--------------------------------------------------------- + - func: SetCellText(text, rowid, columnid) + - desc: sets a cell's text +--]]--------------------------------------------------------- +function newobject:SetCellText(text, rowid, columnid) + + local list = self.internals[1] + local listchildren = list.children + local row = listchildren[rowid] + + if row and row.columndata[columnid]then + row.columndata[columnid] = text + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetCellText(rowid, columnid) + - desc: gets a cell's text +--]]--------------------------------------------------------- +function newobject:GetCellText(rowid, columnid) + + local row = self.internals[1].children[rowid] + + if row and row.columndata[columnid] then + return row.columndata[columnid] + else + return false + end + +end + +--[[--------------------------------------------------------- + - func: SetRowColumnData(rowid, columndata) + - desc: sets the columndata of the specified row +--]]--------------------------------------------------------- +function newobject:SetRowColumnData(rowid, columndata) + + local list = self.internals[1] + local listchildren = list.children + local row = listchildren[rowid] + + if row then + for k, v in ipairs(columndata) do + row.columndata[k] = tostring(v) + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetTotalColumnWidth() + - desc: gets the combined width of the object's columns +--]]--------------------------------------------------------- +function newobject:GetTotalColumnWidth() + + local width = 0 + + for k, v in ipairs(self.children) do + width = width + v.width + end + + return width + +end + +--[[--------------------------------------------------------- + - func: SetColumnWidth(id, width) + - desc: sets the width of the specified column +--]]--------------------------------------------------------- +function newobject:SetColumnWidth(id, width) + + local column = self.children[id] + if column then + column.width = width + local x = 0 + for k, v in ipairs(self.children) do + v:SetPos(x) + x = x + v.width + end + self.internals[1]:CalculateSize() + self.internals[1]:RedoLayout() + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetColumnWidth(id) + - desc: gets the width of the specified column +--]]--------------------------------------------------------- +function newobject:GetColumnWidth(id) + + local column = self.children[id] + if column then + return column.width + end + + return false + +end + +--[[--------------------------------------------------------- + - func: ResizeColumns() + - desc: resizes the object's columns to fit within the + width of the object's list area +--]]--------------------------------------------------------- +function newobject:ResizeColumns() + + local children = self.children + local width = 0 + local vbody = self.internals[1]:GetVerticalScrollBody() + + if vbody then + width = (self:GetWidth() - vbody:GetWidth())/#children + else + width = self:GetWidth()/#children + end + + for k, v in ipairs(children) do + v:SetWidth(width) + self:PositionColumns() + self.internals[1]:CalculateSize() + self.internals[1]:RedoLayout() + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetDefaultColumnWidth(width) + - desc: sets the object's default column width +--]]--------------------------------------------------------- +function newobject:SetDefaultColumnWidth(width) + + self.defaultcolumnwidth = width + return self + +end + +--[[--------------------------------------------------------- + - func: GetDefaultColumnWidth() + - desc: gets the object's default column width +--]]--------------------------------------------------------- +function newobject:GetDefaultColumnWidth() + + return self.defaultcolumnwidth + +end + +--[[--------------------------------------------------------- + - func: SetColumnResizeEnabled(bool) + - desc: sets whether or not the object's columns can + be resized +--]]--------------------------------------------------------- +function newobject:SetColumnResizeEnabled(bool) + + self.canresizecolumns = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetColumnResizeEnabled() + - desc: gets whether or not the object's columns can + be resized +--]]--------------------------------------------------------- +function newobject:GetColumnResizeEnabled() + + return self.canresizecolumns + +end + +--[[--------------------------------------------------------- + - func: SizeColumnToData(columnid) + - desc: sizes a column to the width of its largest data + string +--]]--------------------------------------------------------- +function newobject:SizeColumnToData(columnid) + + local column = self.children[columnid] + local list = self.internals[1] + local largest = 0 + + for k, v in ipairs(list.children) do + local width = v:GetFont():getWidth(self:GetCellText(k, columnid)) + if width > largest then + largest = width + v.textx + end + end + + if largest <= 0 then + largest = 10 + end + + self:SetColumnWidth(columnid, largest) + return self + +end + +--[[--------------------------------------------------------- + - func: SetColumnOrder(curid, newid) + - desc: sets the order of the specified column +--]]--------------------------------------------------------- +function newobject:SetColumnOrder(curid, newid) + + local column = self.children[curid] + local totalcolumns = #self.children + + if column and totalcolumns > 1 and newid <= totalcolumns and newid >= 1 then + column:Remove() + table.insert(self.children, newid, column) + self:PositionColumns() + end + + return self + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/form.lua b/loveframes/objects/form.lua new file mode 100644 index 0000000..437de01 --- /dev/null +++ b/loveframes/objects/form.lua @@ -0,0 +1,303 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- form object +local newobject = loveframes.NewObject("form", "loveframes_object_form", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "form" + self.name = "Form" + self.layout = "vertical" + self.width = 200 + self.height = 50 + self.padding = 5 + self.spacing = 5 + self.topmargin = 12 + self.internal = false + self.children = {} + + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the element +--]]--------------------------------------------------------- +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 + + local children = self.children + local parent = self.parent + local base = loveframes.base + local update = self.Update + + -- move to parent if there is a parent + if parent ~= base and parent.type ~= "list" then + self.x = self.parent.x + self.staticx + self.y = self.parent.y + self.staticy + end + + self:CheckHover() + + for k, v in ipairs(children) do + v:update(dt) + end + + if update then + update(self, dt) + 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 + + local children = self.children + local hover = self.hover + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + end + + for k, v in ipairs(children) do + v:mousepressed(x, y, button) + 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 + local children = self.children + + if not visible then + return + end + + for k, v in ipairs(children) do + v:mousereleased(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: AddItem(object) + - desc: adds an item to the object +--]]--------------------------------------------------------- +function newobject:AddItem(object) + + local objtype = object.type + if objtype == "frame" then + return + end + + local children = self.children + local state = self.state + + object:Remove() + object.parent = self + object:SetState(state) + + table.insert(children, object) + self:LayoutObjects() + + return self + +end + +--[[--------------------------------------------------------- + - func: RemoveItem(object or number) + - desc: removes an item from the object +--]]--------------------------------------------------------- +function newobject:RemoveItem(data) + + local dtype = type(data) + + if dtype == "number" then + local children = self.children + local item = children[data] + if item then + item:Remove() + end + else + data:Remove() + end + + self:LayoutObjects() + return self + +end + +--[[--------------------------------------------------------- + - func: LayoutObjects() + - desc: positions the object's children and calculates + a new size for the object +--]]--------------------------------------------------------- +function newobject:LayoutObjects() + + local layout = self.layout + local padding = self.padding + local spacing = self.spacing + local topmargin = self.topmargin + local children = self.children + local width = padding * 2 + local height = padding * 2 + topmargin + local x = padding + local y = padding + topmargin + + if layout == "vertical" then + local largest_width = 0 + for k, v in ipairs(children) do + v.staticx = x + v.staticy = y + y = y + v.height + spacing + height = height + v.height + spacing + if v.width > largest_width then + largest_width = v.width + end + end + height = height - spacing + self.width = width + largest_width + self.height = height + elseif layout == "horizontal" then + local largest_height = 0 + for k, v in ipairs(children) do + v.staticx = x + v.staticy = y + x = x + v.width + spacing + width = width + v.width + spacing + if v.height > largest_height then + largest_height = v.height + end + end + width = width - spacing + self.width = width + self.height = height + largest_height + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetLayoutType(ltype) + - desc: sets the object's layout type +--]]--------------------------------------------------------- +function newobject:SetLayoutType(ltype) + + self.layout = ltype + return self + +end + +--[[--------------------------------------------------------- + - func: GetLayoutType() + - desc: gets the object's layout type +--]]--------------------------------------------------------- +function newobject:GetLayoutType() + + return self.layout + +end + +--[[--------------------------------------------------------- + - func: SetTopMargin(margin) + - desc: sets the margin between the top of the object + and its children +--]]--------------------------------------------------------- +function newobject:SetTopMargin(margin) + + self.topmargin = margin + return self + +end + +--[[--------------------------------------------------------- + - func: GetTopMargin() + - desc: gets the margin between the top of the object + and its children +--]]--------------------------------------------------------- +function newobject:GetTopMargin() + + return self.topmargin + +end + +--[[--------------------------------------------------------- + - func: SetName(name) + - desc: sets the object's name +--]]--------------------------------------------------------- +function newobject:SetName(name) + + self.name = name + return self + +end + +--[[--------------------------------------------------------- + - func: GetName() + - desc: gets the object's name +--]]--------------------------------------------------------- +function newobject:GetName() + + return self.name + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/frame.lua b/loveframes/objects/frame.lua new file mode 100644 index 0000000..126cd7e --- /dev/null +++ b/loveframes/objects/frame.lua @@ -0,0 +1,1111 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- frame object +local newobject = loveframes.NewObject("frame", "loveframes_object_frame", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "frame" + self.name = "Frame" + self.width = 300 + self.height = 150 + self.clickx = 0 + self.clicky = 0 + self.dockx = 0 + self.docky = 0 + self.dockzonesize = 10 + self.resizex = 0 + self.resizey = 0 + self.resizexmod = 0 + self.resizeymod = 0 + self.resizewidth = 0 + self.resizeheight = 0 + self.minwidth = 100 + self.minheight = 30 + self.maxwidth = 500 + self.maxheight = 500 + self.internal = false + self.draggable = true + self.screenlocked = false + self.parentlocked = false + self.dragging = false + self.modal = false + self.modalbackground = false + self.showclose = true + self.dockedtop = false + self.dockedbottom = false + self.dockedleft = false + self.dockedright = false + self.topdockobject = false + self.bottomdockobject = false + self.leftdockobject = false + self.rightdockobject = false + self.dockable = false + self.resizing = false + self.canresize = false + self.alwaysontop = false + self.internals = {} + self.children = {} + self.icon = nil + self.OnClose = nil + self.OnDock = nil + self.OnResize = nil + + -- create docking zones + self.dockzones = { + top = {x = 0, y = 0, width = 0, height = 0}, + bottom = {x = 0, y = 0, width = 0, height = 0}, + left = {x = 0, y = 0, width = 0, height = 0}, + right = {x = 0, y = 0, width = 0, height = 0} + } + + -- create the close button for the frame + local close = loveframes.objects["closebutton"]:new() + close.parent = self + close.OnClick = function(x, y, object) + local onclose = object.parent.OnClose + if onclose then + local ret = onclose(object.parent) + + if ret ~= false then + object.parent:Remove() + end + else + object.parent:Remove() + end + end + + table.insert(self.internals, close) + + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the element +--]]--------------------------------------------------------- +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 + + local mx, my = love.mouse.getPosition() + local showclose = self.showclose + local close = self.internals[1] + local dragging = self.dragging + local screenlocked = self.screenlocked + local parentlocked = self.parentlocked + local modal = self.modal + local base = loveframes.base + local basechildren = base.children + local numbasechildren = #basechildren + local draworder = self.draworder + local dockedtop = self.dockedtop + local dockedbottom = self.dockedbottom + local dockedleft = self.dockedleft + local dockedright = self.dockedright + local dockable = self.dockable + local dockzonesize = self.dockzonesize + local children = self.children + local internals = self.internals + local parent = self.parent + local update = self.Update + + self:CheckHover() + + -- update dockzones + self.dockzones.top = {x = self.x, y = self.y - dockzonesize, width = self.width, height = dockzonesize} + self.dockzones.bottom = {x = self.x, y = self.y + self.height, width = self.width, height = dockzonesize} + self.dockzones.left = {x = self.x - dockzonesize, y = self.y, width = dockzonesize, height = self.height} + self.dockzones.right = {x = self.x + self.width, y = self.y, width = dockzonesize, height = self.height} + + -- dragging check + if dragging then + if parent == base then + local width = self.width + local height = self.height + if not dockedtop and not dockedbottom then + self.y = my - self.clicky + end + if not dockedleft and not dockedright then + self.x = mx - self.clickx + end + local basechildren = loveframes.base.children + -- check for frames to dock with + if dockable then + local ondock = self.OnDock + for k, v in ipairs(basechildren) do + if v.type == "frame" then + local topcol = loveframes.RectangleCollisionCheck(self.dockzones.bottom, v.dockzones.top) + local botcol = loveframes.RectangleCollisionCheck(self.dockzones.top, v.dockzones.bottom) + local leftcol = loveframes.RectangleCollisionCheck(self.dockzones.right, v.dockzones.left) + local rightcol = loveframes.RectangleCollisionCheck(self.dockzones.left, v.dockzones.right) + local candockobject = v.dockable + if candockobject then + if topcol and not dockedtop then + self.y = v.y - self.height + self.docky = my + self.dockedtop = true + self.topdockobject = v + -- FIXME: object? + -- if ondock then ondock(object, v) end + elseif botcol and not dockedbottom then + self.y = v.y + v.height + self.docky = my + self.dockedbottom = true + self.bottomdockobject = v + -- if ondock then ondock(object, v) end + elseif leftcol and not dockedleft then + self.x = v.x - self.width + self.dockx = mx + self.dockedleft = true + self.leftdockobject = v + -- if ondock then ondock(object, v) end + elseif rightcol and not dockedright then + self.x = v.x + v.width + self.dockx = mx + self.dockedright = true + self.rightdockobject = v + -- if ondock then ondock(object, v) end + end + end + end + end + end + local dockx = self.dockx + local docky = self.docky + local x = self.x + local y = self.y + -- check to see if the frame should be undocked + if dockedtop then + local topdockobject = self.topdockobject + local tdox = topdockobject.x + local tdowidth = topdockobject.width + if my > (docky + 20) or my < (docky - 20) or (x + width) < tdox or x > (tdox + tdowidth) then + self.dockedtop = false + self.docky = 0 + end + end + if dockedbottom then + local bottomdockobject = self.bottomdockobject + local bdox = bottomdockobject.x + local bdowidth = bottomdockobject.width + if my > (docky + 20) or my < (docky - 20) or (x + width) < bdox or x > (bdox + bdowidth) then + self.dockedbottom = false + self.docky = 0 + end + end + if dockedleft then + local leftdockobject = self.leftdockobject + local ldoy = leftdockobject.y + local ldoheight = leftdockobject.height + if mx > (dockx + 20) or mx < (dockx - 20) or (y + height) < ldoy or y > (ldoy + ldoheight) then + self.dockedleft = false + self.dockx = 0 + end + end + if dockedright then + local rightdockobject = self.rightdockobject + local rdoy = rightdockobject.y + local rdoheight = rightdockobject.height + if mx > (dockx + 20) or mx < (dockx - 20) or (y + height) < rdoy or y > (rdoy + rdoheight) then + self.dockedright = false + self.dockx = 0 + end + end + else + self.staticx = mx - self.clickx + self.staticy = my - self.clicky + end + elseif self.resizing then + local width = self.width + local height = self.height + if self.resize_mode == "top_left" then + local new_width = self.resizewidth + (self.resizex - mx) + local new_height = self.resizeheight + (self.resizey - my) + if new_width >= self.minwidth and new_width <= self.maxwidth then + self.width = new_width + self.x = mx - self.resizexmod + end + if new_height >= self.minheight and new_height <= self.maxheight then + self.height = new_height + self.y = my - self.resizeymod + end + elseif self.resize_mode == "bottom_right" then + local new_width = (mx - self.x) + self.resizexmod + local new_height = (my - self.y) + self.resizeymod + if new_width >= self.minwidth and new_width <= self.maxwidth then + self.width = new_width + end + if new_height >= self.minheight and new_height <= self.maxheight then + self.height = new_height + end + elseif self.resize_mode == "top_right" then + local new_width = (mx - self.x) + self.resizexmod + local new_height = self.resizeheight + (self.resizey - my) + if new_width >= self.minwidth and new_width <= self.maxwidth then + self.width = new_width + end + if new_height >= self.minheight and new_height <= self.maxheight then + self.height = new_height + self.y = my - self.resizeymod + end + elseif self.resize_mode == "bottom_left" then + local new_width = self.resizewidth + (self.resizex - mx) + local new_height = (my - self.y) + self.resizeymod + if new_width >= self.minwidth and new_width <= self.maxwidth then + self.width = new_width + self.x = mx - self.resizexmod + end + if new_height >= self.minheight and new_height <= self.maxheight then + self.height = new_height + end + elseif self.resize_mode == "top" then + local new_height = self.resizeheight + (self.resizey - my) + if new_height >= self.minheight and new_height <= self.maxheight then + self.height = new_height + self.y = my - self.resizeymod + end + elseif self.resize_mode == "bottom" then + local new_height = (my - self.y) + self.resizeymod + if new_height >= self.minheight and new_height <= self.maxheight then + self.height = new_height + end + elseif self.resize_mode == "left" then + local new_width = self.resizewidth + (self.resizex - mx) + if new_width >= self.minwidth and new_width <= self.maxwidth then + self.width = new_width + self.x = mx - self.resizexmod + end + elseif self.resize_mode == "right" then + local new_width = (mx - self.x) + self.resizexmod + if new_width >= self.minwidth and new_width <= self.maxwidth then + self.width = new_width + end + end + if self.width ~= width or self.height ~= height then + local onresize = self.OnResize + if onresize then + onresize(self, self.width, self.height) + end + end + end + + -- if screenlocked then keep within screen + if screenlocked then + local width = self.width + local height = self.height + local screenwidth = love.graphics.getWidth() + local screenheight = love.graphics.getHeight() + local x = self.x + local y = self.y + if x < 0 then + self.x = 0 + end + if x + width > screenwidth then + self.x = screenwidth - width + end + if y < 0 then + self.y = 0 + end + if y + height > screenheight then + self.y = screenheight - height + end + end + + -- keep the frame within its parent's boundaries if parentlocked + if parentlocked then + local width = self.width + local height = self.height + local parentwidth = self.parent.width + local parentheight = self.parent.height + local staticx = self.staticx + local staticy = self.staticy + if staticx < 0 then + self.staticx = 0 + end + if staticx + width > parentwidth then + self.staticx = parentwidth - width + end + if staticy < 0 then + self.staticy = 0 + end + if staticy + height > parentheight then + self.staticy = parentheight - height + end + end + + if parent == base and self.alwaysontop and not self:IsTopChild() then + self:MakeTop() + end + + if modal then + local tip = false + local key = 0 + for k, v in ipairs(basechildren) do + if v.type == "tooltip" and v.show then + tip = v + key = k + end + end + if tip then + self:Remove() + self.modalbackground:Remove() + table.insert(basechildren, key - 2, self.modalbackground) + table.insert(basechildren, key - 1, self) + end + if self.modalbackground.draworder > self.draworder then + self:MakeTop() + end + if self.modalbackground.state ~= self.state then + self.modalbackground:SetState(self.state) + end + end + + if parent ~= base then + self.x = self.parent.x + self.staticx + self.y = self.parent.y + self.staticy + end + + for k, v in ipairs(internals) do + v:update(dt) + end + + for k, v in ipairs(children) do + v:update(dt) + end + + if update then + update(self, dt) + 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 + + local width = self.width + local height = self.height + local internals = self.internals + local children = self.children + local dragging = self.dragging + local parent = self.parent + local base = loveframes.base + + if button == 1 then + -- initiate dragging if not currently dragging + if not dragging and self.hover and self.draggable then + local topcol + if self.canresize then + topcol = loveframes.BoundingBox(x, self.x + 2, y, self.y + 2, 1, self.width - 4, 1, 21) + else + topcol = loveframes.BoundingBox(x, self.x, y, self.y, 1, self.width, 1, 25) + end + if topcol then + if parent == base then + self.clickx = x - self.x + self.clicky = y - self.y + else + self.clickx = x - self.staticx + self.clicky = y - self.staticy + end + self.dragging = true + loveframes.dragobject = self + end + end + if not self.resizing and self.canresize and loveframes.hoverobject == self then + if loveframes.BoundingBox(self.x, x, self.y, y, 5, 1, 5, 1) then + self.resizing = true + self.dragging = false + loveframes.dragobject = false + self.resize_mode = "top_left" + self.resizex = x + self.resizey = y + self.resizewidth = self.width + self.resizeheight = self.height + loveframes.resizeobject = self + if x ~= self.x then + self.resizexmod = x - self.x + end + if y ~= self.y then + self.resizeymod = y - self.y + end + elseif loveframes.BoundingBox(self.x + self.width - 5, x, self.y + self.height - 5, y, 5, 1, 5, 1) then + self.resizing = true + self.resize_mode = "bottom_right" + self.resizex = x + self.resizey = y + self.resizewidth = self.width + self.resizeheight = self.height + loveframes.resizeobject = self + if x ~= self.x + self.width then + self.resizexmod = (self.x + self.width) - x + end + if y ~= self.y + self.height then + self.resizeymod = (self.y + self.height) - y + end + elseif loveframes.BoundingBox(self.x + self.width - 5, x, self.y, y, 5, 1, 5, 1) then + self.resizing = true + self.dragging = false + loveframes.dragobject = false + self.resize_mode = "top_right" + self.resizex = x + self.resizey = y + self.resizewidth = self.width + self.resizeheight = self.height + loveframes.resizeobject = self + if x ~= self.x + self.width then + self.resizexmod = (self.x + self.width) - x + end + if y ~= self.y then + self.resizeymod = y - self.y + end + elseif loveframes.BoundingBox(self.x, x, self.y + self.height - 5, y, 5, 1, 5, 1) then + self.resizing = true + self.dragging = false + loveframes.dragobject = false + self.resize_mode = "bottom_left" + self.resizex = x + self.resizey = y + self.resizewidth = self.width + self.resizeheight = self.height + loveframes.resizeobject = self + if x ~= self.x then + self.resizexmod = x - self.x + end + if y ~= self.y + self.height then + self.resizeymod = (self.y + self.height) - y + end + elseif loveframes.BoundingBox(self.x + 5, x, self.y, y, self.width - 10, 1, 2, 1) then + self.resizing = true + self.dragging = false + loveframes.dragobject = false + self.resize_mode = "top" + self.resizex = x + self.resizey = y + self.resizewidth = self.width + self.resizeheight = self.height + loveframes.resizeobject = self + if y ~= self.y then + self.resizeymod = y - self.y + end + elseif loveframes.BoundingBox(self.x + 5, x, self.y + self.height - 2, y, self.width - 10, 1, 2, 1) then + self.resizing = true + self.dragging = false + loveframes.dragobject = false + self.resize_mode = "bottom" + self.resizex = x + self.resizey = y + self.resizewidth = self.width + self.resizeheight = self.height + loveframes.resizeobject = self + if y ~= self.y then + self.resizeymod = (self.y + self.height) - y + end + elseif loveframes.BoundingBox(self.x, x, self.y + 5, y, 2, 1, self.height - 10, 1) then + self.resizing = true + self.dragging = false + loveframes.dragobject = false + self.resize_mode = "left" + self.resizex = x + self.resizey = y + self.resizewidth = self.width + self.resizeheight = self.height + loveframes.resizeobject = self + if x ~= self.x then + self.resizexmod = x - self.x + end + elseif loveframes.BoundingBox(self.x + self.width - 2, x, self.y + 5, y, 2, 1, self.height - 10, 1) then + self.resizing = true + self.dragging = false + loveframes.dragobject = false + self.resize_mode = "right" + self.resizex = x + self.resizey = y + self.resizewidth = self.width + self.resizeheight = self.height + loveframes.resizeobject = self + if x ~= self.x + self.width then + self.resizexmod = (self.x + self.width) - x + end + end + end + if self.hover and button == 1 then + self:MakeTop() + end + end + + for k, v in ipairs(internals) do + v:mousepressed(x, y, button) + end + + for k, v in ipairs(children) do + v:mousepressed(x, y, button) + 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 children = self.children + local internals = self.internals + + self.dragging = false + loveframes.dragobject = false + + if self.resizing then + self.resizex = 0 + self.resizey = 0 + self.resizexmod = 0 + self.resizeymod = 0 + self.resizewidth = 0 + self.resizeheight = 0 + self.resizing = false + loveframes.resizeobject = false + end + + for k, v in ipairs(internals) do + v:mousereleased(x, y, button) + end + + for k, v in ipairs(children) do + v:mousereleased(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: SetName(name) + - desc: sets the object's name +--]]--------------------------------------------------------- +function newobject:SetName(name) + + self.name = name + return self + +end + +--[[--------------------------------------------------------- + - func: GetName() + - desc: gets the object's name +--]]--------------------------------------------------------- +function newobject:GetName() + + return self.name + +end + +--[[--------------------------------------------------------- + - func: SetDraggable(true/false) + - desc: sets whether the object can be dragged or not +--]]--------------------------------------------------------- +function newobject:SetDraggable(bool) + + self.draggable = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetDraggable() + - desc: gets whether the object can be dragged ot not +--]]--------------------------------------------------------- +function newobject:GetDraggable() + + return self.draggable + +end + + +--[[--------------------------------------------------------- + - func: SetScreenLocked(bool) + - desc: sets whether the object can be moved passed the + boundaries of the window or not +--]]--------------------------------------------------------- +function newobject:SetScreenLocked(bool) + + self.screenlocked = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetScreenLocked() + - desc: gets whether the object can be moved passed the + boundaries of window or not +--]]--------------------------------------------------------- +function newobject:GetScreenLocked() + + return self.screenlocked + +end + +--[[--------------------------------------------------------- + - func: ShowCloseButton(bool) + - desc: sets whether the object's close button should + be drawn +--]]--------------------------------------------------------- +function newobject:ShowCloseButton(bool) + + local close = self.internals[1] + + close.visible = bool + self.showclose = bool + return self + +end + +--[[--------------------------------------------------------- + - func: MakeTop() + - desc: makes the object the top object in the drawing + order +--]]--------------------------------------------------------- +function newobject:MakeTop() + + local key = 0 + local base = loveframes.base + local basechildren = base.children + local numbasechildren = #basechildren + + -- check to see if the object's parent is not the base object + if self.parent ~= base then + local baseparent = self:GetBaseParent() + if baseparent.type == "frame" then + baseparent:MakeTop() + end + return self + end + + -- check to see if the object is the only child of the base object + if numbasechildren == 1 then + return self + end + + -- check to see if the object is already at the top + if basechildren[numbasechildren] == self then + return self + end + + -- make this the top object + for k, v in ipairs(basechildren) do + if v == self then + table.remove(basechildren, k) + table.insert(basechildren, self) + key = k + break + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetModal(bool) + - desc: sets whether or not the object is in a modal + state +--]]--------------------------------------------------------- +function newobject:SetModal(bool) + + local modalobject = loveframes.modalobject + local mbackground = self.modalbackground + local parent = self.parent + local base = loveframes.base + + if parent ~= base then + return + end + + self.modal = bool + + if bool then + if modalobject then + modalobject:SetModal(false) + end + loveframes.modalobject = self + if not mbackground then + self.modalbackground = loveframes.objects["modalbackground"]:new(self) + self.modal = true + end + else + if modalobject == self then + loveframes.modalobject = false + if mbackground then + self.modalbackground:Remove() + self.modalbackground = false + self.modal = false + end + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetModal() + - desc: gets whether or not the object is in a modal + state +--]]--------------------------------------------------------- +function newobject:GetModal() + + return self.modal + +end + +--[[--------------------------------------------------------- + - func: SetVisible(bool) + - desc: set's whether the object is visible or not +--]]--------------------------------------------------------- +function newobject:SetVisible(bool) + + local children = self.children + local internals = self.internals + local closebutton = internals[1] + + self.visible = bool + + for k, v in ipairs(children) do + v:SetVisible(bool) + end + + if self.showclose then + closebutton.visible = bool + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetParentLocked(bool) + - desc: sets whether the object can be moved passed the + boundaries of its parent or not +--]]--------------------------------------------------------- +function newobject:SetParentLocked(bool) + + self.parentlocked = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetParentLocked(bool) + - desc: gets whether the object can be moved passed the + boundaries of its parent or not +--]]--------------------------------------------------------- +function newobject:GetParentLocked() + + return self.parentlocked + +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) + self.icon:setFilter("nearest", "nearest") + else + self.icon = icon + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetIcon() + - desc: gets the object's icon +--]]--------------------------------------------------------- +function newobject:GetIcon() + + local icon = self.icon + + if icon then + return icon + end + + return false + +end + +--[[--------------------------------------------------------- + - func: SetDockable(dockable) + - desc: sets whether or not the object can dock onto + another object of its type or be docked + by another object of its type +--]]--------------------------------------------------------- +function newobject:SetDockable(dockable) + + self.dockable = dockable + return self + +end + +--[[--------------------------------------------------------- + - func: GetDockable() + - desc: gets whether or not the object can dock onto + another object of its type or be docked + by another object of its type +--]]--------------------------------------------------------- +function newobject:GetDockable() + + return self.dockable + +end + +--[[--------------------------------------------------------- + - func: SetDockZoneSize(size) + - desc: sets the size of the object's docking zone +--]]--------------------------------------------------------- +function newobject:SetDockZoneSize(size) + + self.dockzonesize = size + return self + +end + +--[[--------------------------------------------------------- + - func: GetDockZoneSize(size) + - desc: gets the size of the object's docking zone +--]]--------------------------------------------------------- +function newobject:GetDockZoneSize() + + return self.dockzonesize + +end + +--[[--------------------------------------------------------- + - func: SetResizable(bool) + - desc: sets whether or not the object can be resized +--]]--------------------------------------------------------- +function newobject:SetResizable(bool) + + self.canresize = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetResizable() + - desc: gets whether or not the object can be resized +--]]--------------------------------------------------------- +function newobject:GetResizable() + + return self.canresize + +end + +--[[--------------------------------------------------------- + - func: SetMinWidth(width) + - desc: sets the object's minimum width +--]]--------------------------------------------------------- +function newobject:SetMinWidth(width) + + self.minwidth = width + return self + +end + +--[[--------------------------------------------------------- + - func: GetMinWidth() + - desc: gets the object's minimum width +--]]--------------------------------------------------------- +function newobject:GetMinWidth() + + return self.minwidth + +end + +--[[--------------------------------------------------------- + - func: SetMaxWidth(width) + - desc: sets the object's maximum width +--]]--------------------------------------------------------- +function newobject:SetMaxWidth(width) + + self.maxwidth = width + return self + +end + +--[[--------------------------------------------------------- + - func: GetMaxWidth() + - desc: gets the object's maximum width +--]]--------------------------------------------------------- +function newobject:GetMaxWidth() + + return self.maxwidth + +end + +--[[--------------------------------------------------------- + - func: SetMinHeight(height) + - desc: sets the object's minimum height +--]]--------------------------------------------------------- +function newobject:SetMinHeight(height) + + self.minheight = height + return self + +end + +--[[--------------------------------------------------------- + - func: GetMinHeight() + - desc: gets the object's minimum height +--]]--------------------------------------------------------- +function newobject:GetMinHeight() + + return self.minheight + +end + +--[[--------------------------------------------------------- + - func: SetMaxHeight(height) + - desc: sets the object's maximum height +--]]--------------------------------------------------------- +function newobject:SetMaxHeight(height) + + self.maxheight = height + return self + +end + +--[[--------------------------------------------------------- + - func: GetMaxHeight() + - desc: gets the object's maximum height +--]]--------------------------------------------------------- +function newobject:GetMaxHeight() + + return self.maxheight + +end + +--[[--------------------------------------------------------- + - func: SetMinSize(width, height) + - desc: sets the object's minimum size +--]]--------------------------------------------------------- +function newobject:SetMinSize(width, height) + + self.minwidth = width + self.minheight = height + return self + +end + +--[[--------------------------------------------------------- + - func: GetMinSize() + - desc: gets the object's minimum size +--]]--------------------------------------------------------- +function newobject:GetMinSize() + + return self.minwidth, self.maxwidth + +end + +--[[--------------------------------------------------------- + - func: SetMaxSize(width, height) + - desc: sets the object's maximum size +--]]--------------------------------------------------------- +function newobject:SetMaxSize(width, height) + + self.maxwidth = width + self.maxheight = height + return self + +end + +--[[--------------------------------------------------------- + - func: GetMaxSize() + - desc: gets the object's maximum size +--]]--------------------------------------------------------- +function newobject:GetMaxSize() + + return self.maxwidth, self.maxheight + +end + +--[[--------------------------------------------------------- + - func: SetAlwaysOnTop(bool) + - desc: sets whether or not a frame should always be + drawn on top of other objects +--]]--------------------------------------------------------- +function newobject:SetAlwaysOnTop(bool) + + self.alwaysontop = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetAlwaysOnTop() + - desc: gets whether or not a frame should always be + drawn on top of other objects +--]]--------------------------------------------------------- +function newobject:GetAlwaysOnTop() + + return self.alwaysontop + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/grid.lua b/loveframes/objects/grid.lua new file mode 100644 index 0000000..89c0e7a --- /dev/null +++ b/loveframes/objects/grid.lua @@ -0,0 +1,358 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- grid object +local newobject = loveframes.NewObject("grid", "loveframes_object_grid", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "grid" + self.width = 100 + self.height = 100 + self.prevwidth = 100 + self.prevheight = 100 + self.rows = 0 + self.columns = 0 + self.cellwidth = 25 + self.cellheight = 25 + self.cellpadding = 5 + self.itemautosize = false + self.children = {} + self.OnSizeChanged = nil + + self:SetDrawFunc() +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 parent = self.parent + local children = self.children + local base = loveframes.base + + -- 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 + + local cw = self.cellwidth + (self.cellpadding * 2) + local ch = self.cellheight + (self.cellpadding * 2) + local prevwidth = self.prevwidth + local prevheight = self.prevheight + + self.width = (self.columns * self.cellwidth) + (self.columns * (self.cellpadding * 2)) + self.height = (self.rows * self.cellheight) + (self.rows * (self.cellpadding * 2)) + + if self.width ~= prevwidth or self.height ~= prevheight then + local onsizechanged = self.OnSizeChanged + self.prevwidth = self.width + self.prevheight = self.height + if onsizechanged then + onsizechanged(self) + end + end + + for k, v in ipairs(children) do + local x = 0 + ((cw * v.gridcolumn) - cw ) + (cw/2 - v.width/2) + local y = 0 + ((ch * v.gridrow) - ch) + (ch/2 - v.height/2) + v.staticx = x + v.staticy = y + v:update(dt) + end + + local update = self.Update + if update then update(self, dt) 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 + + local children = self.children + local hover = self.hover + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + end + + for k, v in ipairs(children) do + v:mousepressed(x, y, button) + 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 + local children = self.children + + if not visible then + return + end + + for k, v in ipairs(children) do + v:mousereleased(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: AddItem(object, row, column) + - desc: adds and item to the object +--]]--------------------------------------------------------- +function newobject:AddItem(object, row, column) + + local itemautosize = self.itemautosize + local children = self.children + + object:Remove() + + table.insert(children, object) + object.parent = self + object.gridrow = row + object.gridcolumn = column + + if itemautosize then + local cw = self.cellwidth + (self.cellpadding * 2) + local ch = self.cellheight + (self.cellpadding * 2) + object.width = cw - (self.cellpadding * 2) + object.height = ch - (self.cellpadding * 2) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetItem(row, column) + - desc: gets an item from the object at the specified + row and column +--]]--------------------------------------------------------- +function newobject:GetItem(row, column) + + local children = self.children + + for k, v in ipairs(children) do + if v.gridrow == row and v.gridcolumn == column then + return v + end + end + + return false + +end + +--[[--------------------------------------------------------- + - func: SetItemAutoSize(bool) + - desc: sets whether or not the object should auto-size + its items +--]]--------------------------------------------------------- +function newobject:SetItemAutoSize(bool) + + self.itemautosize = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetItemAutoSize() + - desc: gets whether or not the object should auto-size + its items +--]]--------------------------------------------------------- +function newobject:GetItemAutoSize() + + return self.itemautosize + +end + +--[[--------------------------------------------------------- + - func: SetRows(rows) + - desc: sets the number of rows the object should have +--]]--------------------------------------------------------- +function newobject:SetRows(rows) + + self.rows = rows + return self + +end + +--[[--------------------------------------------------------- + - func: SetRows(rows) + - desc: gets the number of rows the object has +--]]--------------------------------------------------------- +function newobject:GetRows() + + return self.rows + +end + +--[[--------------------------------------------------------- + - func: SetColumns(columns) + - desc: sets the number of columns the object should + have +--]]--------------------------------------------------------- +function newobject:SetColumns(columns) + + self.columns = columns + return self + +end + +--[[--------------------------------------------------------- + - func: GetColumns() + - desc: gets the number of columns the object has +--]]--------------------------------------------------------- +function newobject:GetColumns() + + return self.columns + +end + +--[[--------------------------------------------------------- + - func: SetCellWidth(width) + - desc: sets the width of the object's cells +--]]--------------------------------------------------------- +function newobject:SetCellWidth(width) + + self.cellwidth = width + return self + +end + +--[[--------------------------------------------------------- + - func: GetCellWidth() + - desc: gets the width of the object's cells +--]]--------------------------------------------------------- +function newobject:GetCellWidth() + + return self.cellwidth + +end + +--[[--------------------------------------------------------- + - func: SetCellHeight(height) + - desc: sets the height of the object's cells +--]]--------------------------------------------------------- +function newobject:SetCellHeight(height) + + self.cellheight = height + return self + +end + +--[[--------------------------------------------------------- + - func: GetCellHeight() + - desc: gets the height of the object's cells +--]]--------------------------------------------------------- +function newobject:GetCellHeight() + + return self.cellheight + +end + +--[[--------------------------------------------------------- + - func: SetCellSize(width, height) + - desc: sets the size of the object's cells +--]]--------------------------------------------------------- +function newobject:SetCellSize(width, height) + + self.cellwidth = width + self.cellheight = height + return self + +end + +--[[--------------------------------------------------------- + - func: GetCellSize() + - desc: gets the size of the object's cells +--]]--------------------------------------------------------- +function newobject:GetCellSize() + + return self.cellwidth, self.cellheight + +end + +--[[--------------------------------------------------------- + - func: SetCellPadding(padding) + - desc: sets the padding of the object's cells +--]]--------------------------------------------------------- +function newobject:SetCellPadding(padding) + + self.cellpadding = padding + return self + +end + +--[[--------------------------------------------------------- + - func: GetCellPadding + - desc: gets the padding of the object's cells +--]]--------------------------------------------------------- +function newobject:GetCellPadding() + + return self.cellpadding + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/image.lua b/loveframes/objects/image.lua new file mode 100644 index 0000000..e8f4acc --- /dev/null +++ b/loveframes/objects/image.lua @@ -0,0 +1,385 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- image object +local newobject = loveframes.NewObject("image", "loveframes_object_image", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "image" + self.width = 0 + self.height = 0 + self.orientation = 0 + self.scalex = 1 + self.scaley = 1 + self.offsetx = 0 + self.offsety = 0 + self.shearx = 0 + self.sheary = 0 + self.internal = false + self.image = nil + self.imagecolor = {1, 1, 1, 1} + + self:SetDrawFunc() +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 + + local parent = self.parent + local base = loveframes.base + local update = self.Update + + self:CheckHover() + + -- 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: SetImage(image) + - desc: sets the object's image +--]]--------------------------------------------------------- +function newobject:SetImage(image) + + if type(image) == "string" then + self.image = love.graphics.newImage(image) + self.image:setFilter("nearest", "nearest") + else + self.image = image + end + + self.width = self.image:getWidth() + self.height = self.image:getHeight() + + return self + +end + +--[[--------------------------------------------------------- + - func: GetImage() + - desc: gets the object's image +--]]--------------------------------------------------------- +function newobject:GetImage() + + return self.image + +end + +--[[--------------------------------------------------------- + - func: SetColor(r, g, b, a) + - desc: sets the object's color +--]]--------------------------------------------------------- +function newobject:SetColor(r, g, b, a) + + self.imagecolor = {r, g, b, a} + return self + +end + +--[[--------------------------------------------------------- + - func: GetColor() + - desc: gets the object's color +--]]--------------------------------------------------------- +function newobject:GetColor() + + return unpack(self.imagecolor) + +end + +--[[--------------------------------------------------------- + - func: SetOrientation(orientation) + - desc: sets the object's orientation +--]]--------------------------------------------------------- +function newobject:SetOrientation(orientation) + + self.orientation = orientation + return self + +end + +--[[--------------------------------------------------------- + - func: GetOrientation() + - desc: gets the object's orientation +--]]--------------------------------------------------------- +function newobject:GetOrientation() + + return self.orientation + +end + +--[[--------------------------------------------------------- + - func: SetScaleX(scalex) + - desc: sets the object's x scale +--]]--------------------------------------------------------- +function newobject:SetScaleX(scalex) + + self.scalex = scalex + return self + +end + +--[[--------------------------------------------------------- + - func: GetScaleX() + - desc: gets the object's x scale +--]]--------------------------------------------------------- +function newobject:GetScaleX() + + return self.scalex + +end + +--[[--------------------------------------------------------- + - func: SetScaleY(scaley) + - desc: sets the object's y scale +--]]--------------------------------------------------------- +function newobject:SetScaleY(scaley) + + self.scaley = scaley + return self + +end + +--[[--------------------------------------------------------- + - func: GetScaleY() + - desc: gets the object's y scale +--]]--------------------------------------------------------- +function newobject:GetScaleY() + + return self.scaley + +end + +--[[--------------------------------------------------------- + - func: SetScale(scalex, scaley) + - desc: sets the object's x and y scale +--]]--------------------------------------------------------- +function newobject:SetScale(scalex, scaley) + + self.scalex = scalex + self.scaley = scaley + + return self + +end + +--[[--------------------------------------------------------- + - func: GetScale() + - desc: gets the object's x and y scale +--]]--------------------------------------------------------- +function newobject:GetScale() + + return self.scalex, self.scaley + +end + +--[[--------------------------------------------------------- + - func: SetOffsetX(x) + - desc: sets the object's x offset +--]]--------------------------------------------------------- +function newobject:SetOffsetX(x) + + self.offsetx = x + return self + +end + +--[[--------------------------------------------------------- + - func: GetOffsetX() + - desc: gets the object's x offset +--]]--------------------------------------------------------- +function newobject:GetOffsetX() + + return self.offsetx + +end + +--[[--------------------------------------------------------- + - func: SetOffsetY(y) + - desc: sets the object's y offset +--]]--------------------------------------------------------- +function newobject:SetOffsetY(y) + + self.offsety = y + return self + +end + +--[[--------------------------------------------------------- + - func: GetOffsetY() + - desc: gets the object's y offset +--]]--------------------------------------------------------- +function newobject:GetOffsetY() + + return self.offsety + +end + +--[[--------------------------------------------------------- + - func: SetOffset(x, y) + - desc: sets the object's x and y offset +--]]--------------------------------------------------------- +function newobject:SetOffset(x, y) + + self.offsetx = x + self.offsety = y + + return self + +end + +--[[--------------------------------------------------------- + - func: GetOffset() + - desc: gets the object's x and y offset +--]]--------------------------------------------------------- +function newobject:GetOffset() + + return self.offsetx, self.offsety + +end + +--[[--------------------------------------------------------- + - func: SetShearX(shearx) + - desc: sets the object's x shear +--]]--------------------------------------------------------- +function newobject:SetShearX(shearx) + + self.shearx = shearx + return self + +end + +--[[--------------------------------------------------------- + - func: GetShearX() + - desc: gets the object's x shear +--]]--------------------------------------------------------- +function newobject:GetShearX() + + return self.shearx + +end + +--[[--------------------------------------------------------- + - func: SetShearY(sheary) + - desc: sets the object's y shear +--]]--------------------------------------------------------- +function newobject:SetShearY(sheary) + + self.sheary = sheary + return self + +end + +--[[--------------------------------------------------------- + - func: GetShearY() + - desc: gets the object's y shear +--]]--------------------------------------------------------- +function newobject:GetShearY() + + return self.sheary + +end + +--[[--------------------------------------------------------- + - func: SetShear(shearx, sheary) + - desc: sets the object's x and y shear +--]]--------------------------------------------------------- +function newobject:SetShear(shearx, sheary) + + self.shearx = shearx + self.sheary = sheary + + return self + +end + +--[[--------------------------------------------------------- + - func: GetShear() + - desc: gets the object's x and y shear +--]]--------------------------------------------------------- +function newobject:GetShear() + + return self.shearx, self.sheary + +end + +--[[--------------------------------------------------------- + - func: GetImageSize() + - desc: gets the size of the object's image +--]]--------------------------------------------------------- +function newobject:GetImageSize() + + local image = self.image + + if image then + return image:getWidth(), image:getHeight() + end + +end + +--[[--------------------------------------------------------- + - func: GetImageWidth() + - desc: gets the width of the object's image +--]]--------------------------------------------------------- +function newobject:GetImageWidth() + + local image = self.image + + if image then + return image:getWidth() + end + +end + +--[[--------------------------------------------------------- + - func: GetImageWidth() + - desc: gets the height of the object's image +--]]--------------------------------------------------------- +function newobject:GetImageHeight() + + local image = self.image + + if image then + return image:getHeight() + end + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/imagebutton.lua b/loveframes/objects/imagebutton.lua new file mode 100644 index 0000000..786c7a5 --- /dev/null +++ b/loveframes/objects/imagebutton.lua @@ -0,0 +1,343 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- imagebutton object +local newobject = loveframes.NewObject("imagebutton", "loveframes_object_imagebutton", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "imagebutton" + self.text = "Image Button" + self.width = 50 + self.height = 50 + self.internal = false + self.down = false + self.clickable = true + self.enabled = true + self.image = nil + self.imagecolor = {1, 1, 1, 1} + self.OnClick = nil + self.groupIndex = 0 + self.checked = false + + self:SetDrawFunc() +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 downobject = loveframes.downobject + local down = self.down + local parent = self.parent + local base = loveframes.base + local update = self.Update + + if not hover then + self.down = false + else + if downobject == self then + self.down = true + end + end + + if not down and downobject == self then + self.hover = true + 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: 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 + + local hover = self.hover + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + self.down = true + loveframes.downobject = self + 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 down = self.down + local clickable = self.clickable + local enabled = self.enabled + local onclick = self.OnClick + + if hover and down and clickable and button == 1 then + if enabled then + if self.groupIndex ~= 0 then + local baseparent = self.parent + if baseparent then + for k, v in ipairs(baseparent.children) do + if v.groupIndex then + if v.groupIndex == self.groupIndex then + v.checked = false + end + end + end + end + self.checked = true + end + if onclick then + onclick(self, x, y) + end + end + end + + self.down = false + +end + +--[[--------------------------------------------------------- + - func: SetText(text) + - desc: sets the object's text +--]]--------------------------------------------------------- +function newobject:SetText(text) + + self.text = text + return self + +end + +--[[--------------------------------------------------------- + - func: GetText() + - desc: gets the object's text +--]]--------------------------------------------------------- +function newobject:GetText() + + return self.text + +end + +--[[--------------------------------------------------------- + - func: SetClickable(bool) + - desc: sets whether the object can be clicked or not +--]]--------------------------------------------------------- +function newobject:SetClickable(bool) + + self.clickable = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetClickable(bool) + - desc: gets whether the object can be clicked or not +--]]--------------------------------------------------------- +function newobject:GetClickable() + + return self.clickable + +end + +--[[--------------------------------------------------------- + - func: SetClickable(bool) + - desc: sets whether the object is enabled or not +--]]--------------------------------------------------------- +function newobject:SetEnabled(bool) + + self.enabled = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetEnabled() + - desc: gets whether the object is enabled or not +--]]--------------------------------------------------------- +function newobject:GetEnabled() + + return self.enabled + +end + +--[[--------------------------------------------------------- + - func: SetImage(image) + - desc: sets the object's image +--]]--------------------------------------------------------- +function newobject:SetImage(image) + + if type(image) == "string" then + self.image = love.graphics.newImage(image) + self.image:setFilter("nearest", "nearest") + else + self.image = image + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetImage() + - desc: gets whether the object is enabled or not +--]]--------------------------------------------------------- +function newobject:GetImage() + + return self.image + +end + +--[[--------------------------------------------------------- + - func: SizeToImage() + - desc: makes the object the same size as its image +--]]--------------------------------------------------------- +function newobject:SizeToImage() + + local image = self.image + + if image then + self.width = image:getWidth() + self.height = image:getHeight() + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetImageSize() + - desc: gets the size of the object's image +--]]--------------------------------------------------------- +function newobject:GetImageSize() + + local image = self.image + + if image then + return image:getWidth(), image:getHeight() + end + +end + +--[[--------------------------------------------------------- + - func: GetImageWidth() + - desc: gets the width of the object's image +--]]--------------------------------------------------------- +function newobject:GetImageWidth() + + local image = self.image + + if image then + return image:getWidth() + end + +end + +--[[--------------------------------------------------------- + - func: GetImageWidth() + - desc: gets the height of the object's image +--]]--------------------------------------------------------- +function newobject:GetImageHeight() + + local image = self.image + + if image then + return image:getHeight() + end + +end + +--[[--------------------------------------------------------- + - func: SetColor(r, g, b, a) + - desc: sets the object's color +--]]--------------------------------------------------------- +function newobject:SetColor(r, g, b, a) + + self.imagecolor = {r, g, b, a} + return self + +end + +--[[--------------------------------------------------------- + - func: GetColor() + - desc: gets the object's color +--]]--------------------------------------------------------- +function newobject:GetColor() + + return unpack(self.imagecolor) + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/closebutton.lua b/loveframes/objects/internal/closebutton.lua new file mode 100644 index 0000000..ec2ac5f --- /dev/null +++ b/loveframes/objects/internal/closebutton.lua @@ -0,0 +1,159 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- closebutton class +local newobject = loveframes.NewObject("closebutton", "loveframes_object_closebutton", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "closebutton" + self.width = 16 + self.height = 16 + self.internal = true + self.hover = false + self.down = false + self.autoposition = true + self.OnClick = function() end + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the object +--]]--------------------------------------------------------- +function newobject:update(dt) + + 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 down = self.down + local downobject = loveframes.downobject + local parent = self.parent + local base = loveframes.base + local update = self.Update + + if not hover then + self.down = false + else + if loveframes.downobject == self then + self.down = true + end + end + + if not down and downobject == self then + self.hover = true + end + + if self.autoposition then + self.staticx = self.parent.width - self.width - 4 + self.staticy = 4 + end + + -- move to parent if there is a parent + if parent ~= base then + self.x = parent.x + self.staticx + self.y = parent.y + self.staticy + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +function newobject:mousepressed(x, y, button) + + local visible = self.visible + + if not visible then + return + end + + local hover = self.hover + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + self.down = true + loveframes.downobject = self + end + +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + + local visible = self.visible + + if not visible then + return + end + + local hover = self.hover + local onclick = self.OnClick + + if hover and self.down then + if button == 1 then + onclick(x, y, self) + end + end + + self.down = false + +end + +--[[--------------------------------------------------------- + - func: SetAutoPosition(bool) + - desc: sets whether or not the object should be + positioned automatically +--]]--------------------------------------------------------- +function newobject:SetAutoPosition(bool) + + self.autoposition = bool + +end + +--[[--------------------------------------------------------- + - func: GetAutoPosition() + - desc: gets whether or not the object should be + positioned automatically +--]]--------------------------------------------------------- +function newobject:GetAutoPosition() + + return self.autoposition + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/columnlist/columnlistarea.lua b/loveframes/objects/internal/columnlist/columnlistarea.lua new file mode 100644 index 0000000..f4d3458 --- /dev/null +++ b/loveframes/objects/internal/columnlist/columnlistarea.lua @@ -0,0 +1,469 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- columnlistarea class +local newobject = loveframes.NewObject("columnlistarea", "loveframes_object_columnlistarea", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: intializes the element +--]]--------------------------------------------------------- +function newobject:initialize(parent) + + self.type = "columnlistarea" + self.display = "vertical" + self.parent = parent + self.width = 80 + self.height = 25 + self.clickx = 0 + self.clicky = 0 + self.offsety = 0 + self.offsetx = 0 + self.extrawidth = 0 + self.extraheight = 0 + self.rowcolorindex = 1 + self.rowcolorindexmax = 2 + self.buttonscrollamount = parent.buttonscrollamount + self.mousewheelscrollamount = parent.mousewheelscrollamount + self.vbar = false + self.hbar = false + self.dtscrolling = parent.dtscrolling + self.internal = true + self.internals = {} + self.children = {} + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the object +--]]--------------------------------------------------------- +function newobject:update(dt) + + if not self.visible then + if not self.alwaysupdate then + return + end + end + + local cwidth, cheight = self.parent:GetColumnSize() + local parent = self.parent + local update = self.Update + local internals = self.internals + + self:CheckHover() + + -- move to parent if there is a parent + if parent ~= loveframes.base then + self.x = parent.x + self.staticx + self.y = parent.y + self.staticy + end + + for k, v in ipairs(self.children) do + local col = loveframes.BoundingBox(self.x, v.x, self.y, v.y, self.width, v.width, self.height, v.height) + if col then + v:update(dt) + end + v:SetClickBounds(self.x, self.y, self.width, self.height) + v.y = (v.parent.y + v.staticy) - self.offsety + cheight + v.x = (v.parent.x + v.staticx) - self.offsetx + end + + for k, v in ipairs(self.internals) do + v:update(dt) + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: draw() + - desc: draws the object +--]]--------------------------------------------------------- +function newobject:draw() + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + local x = self.x + local y = self.y + local width = self.width + local height = self.height + local swidth = width + local sheight = height + + if self.vbar then + swidth = swidth - self:GetVerticalScrollBody():GetWidth() + end + + if self.hbar then + sheight = sheight - self:GetHorizontalScrollBody():GetHeight() + end + + local stencilfunc = function() love.graphics.rectangle("fill", x, y, swidth, sheight) end + + self:SetDrawOrder() + + local drawfunc = self.Draw or self.drawfunc + if drawfunc then + drawfunc(self) + end + + love.graphics.stencil(stencilfunc) + love.graphics.setStencilTest("greater", 0) + + local children = self.children + if children then + for k, v in ipairs(self.children) do + local col = loveframes.BoundingBox(self.x, v.x, self.y, v.y, width, v.width, height, v.height) + if col then + v:draw() + end + end + end + + love.graphics.setStencilTest() + + drawfunc = self.DrawOver or self.drawoverfunc + if drawfunc then + drawfunc(self) + end + + local internals = self.internals + if internals then + for k, v in ipairs(self.internals) do + v:draw() + end + end +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +function newobject:mousepressed(x, y, button) + + local scrollamount = self.mousewheelscrollamount + + if self.hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + end + + for k, v in ipairs(self.internals) do + v:mousepressed(x, y, button) + end + + for k, v in ipairs(self.children) do + v:mousepressed(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + + local internals = self.internals + local children = self.children + + for k, v in ipairs(internals) do + v:mousereleased(x, y, button) + end + + for k, v in ipairs(children) do + v:mousereleased(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: wheelmoved(x, y) + - desc: called when the player moves a mouse wheel +--]]--------------------------------------------------------- +function newobject:wheelmoved(x, y) + + local scrollamount = self.mousewheelscrollamount + + -- FIXME: button is nil + -- if self.hover and button == 1 then + if self.hover then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + end + + local bar = false + if self.vbar and self.hbar then + bar = self:GetVerticalScrollBody():GetScrollBar() + elseif self.vbar and not self.hbar then + bar = self:GetVerticalScrollBody():GetScrollBar() + elseif not self.vbar and self.hbar then + bar = self:GetHorizontalScrollBody():GetScrollBar() + end + + if self:IsTopList() and bar then + if self.dtscrolling then + local dt = love.timer.getDelta() + bar:Scroll(-y * scrollamount * dt) + else + bar:Scroll(-y * scrollamount) + end + end + +end + +--[[--------------------------------------------------------- + - func: CalculateSize() + - desc: calculates the size of the object's children +--]]--------------------------------------------------------- +function newobject:CalculateSize() + + local height = self.height + local width = self.width + local parent = self.parent + local itemheight = parent.columnheight + + for k, v in ipairs(self.children) do + itemheight = itemheight + v.height + end + + self.itemheight = itemheight + self.itemwidth = parent:GetTotalColumnWidth() + + local hbarheight = 0 + local hbody = self:GetHorizontalScrollBody() + if hbody then + hbarheight = hbody.height + end + + if self.itemheight > (height - hbarheight) then + if hbody then + self.itemheight = self.itemheight + hbarheight + end + self.extraheight = self.itemheight - height + if not self.vbar then + local newbar = loveframes.objects["scrollbody"]:new(self, "vertical") + table.insert(self.internals, newbar) + self.vbar = true + newbar:GetScrollBar().autoscroll = parent.autoscroll + self.itemwidth = self.itemwidth + newbar.width + self.extrawidth = self.itemwidth - width + end + else + if self.vbar then + self:GetVerticalScrollBody():Remove() + self.vbar = false + self.offsety = 0 + end + end + + local vbarwidth = 0 + local vbody = self:GetVerticalScrollBody() + if vbody then + vbarwidth = vbody.width + end + + if self.itemwidth > (width - vbarwidth) then + if vbody then + self.itemwidth = self.itemwidth + vbarwidth + end + self.extrawidth = self.itemwidth - width + if not self.hbar then + local newbar = loveframes.objects["scrollbody"]:new(self, "horizontal") + table.insert(self.internals, newbar) + self.hbar = true + self.itemheight = self.itemheight + newbar.height + self.extraheight = self.itemheight - height + end + else + if self.hbar then + local hbar = self:GetHorizontalScrollBody() + hbar:Remove() + self.itemheight = self.itemheight - hbar.height + self.extraheight = self.itemheight - height + self.hbar = false + self.offsetx = 0 + end + end + +end + +--[[--------------------------------------------------------- + - func: RedoLayout() + - desc: used to redo the layour of the object +--]]--------------------------------------------------------- +function newobject:RedoLayout() + + local starty = 0 + self.rowcolorindex = 1 + + for k, v in ipairs(self.children) do + v:SetWidth(self.parent:GetTotalColumnWidth()) + v.staticx = 0 + v.staticy = starty + if self.vbar then + local vbody = self:GetVerticalScrollBody() + vbody.staticx = self.width - vbody.width + if self.hbar then + vbody.height = self.height - self:GetHorizontalScrollBody().height + else + vbody.height = self.height + end + end + if self.hbar then + local hbody = self:GetHorizontalScrollBody() + hbody.staticy = self.height - hbody.height + if self.vbar then + hbody.width = self.width - self:GetVerticalScrollBody().width + else + hbody.width = self.width + end + end + starty = starty + v.height + v.lastheight = v.height + v.colorindex = self.rowcolorindex + if self.rowcolorindex == self.rowcolorindexmax then + self.rowcolorindex = 1 + else + self.rowcolorindex = self.rowcolorindex + 1 + end + end + +end + +--[[--------------------------------------------------------- + - func: AddRow(data) + - desc: adds a row to the object +--]]--------------------------------------------------------- +function newobject:AddRow(data) + + local colorindex = self.rowcolorindex + + if colorindex == self.rowcolorindexmax then + self.rowcolorindex = 1 + else + self.rowcolorindex = colorindex + 1 + end + + table.insert(self.children, loveframes.objects["columnlistrow"]:new(self, data)) + self:CalculateSize() + self:RedoLayout() + self.parent:PositionColumns() + +end + +--[[--------------------------------------------------------- + - func: GetScrollBar() + - desc: gets the object's scroll bar +--]]--------------------------------------------------------- +function newobject:GetScrollBar() + + if self.bar then + return self.internals[1].internals[1].internals[1] + else + return false + end + +end + +--[[--------------------------------------------------------- + - func: Sort() + - desc: sorts the object's children +--]]--------------------------------------------------------- +function newobject:Sort(column, desc) + + local children = self.children + self.rowcolorindex = 1 + + table.sort(children, function(a, b) + if desc then + return (tostring(a.columndata[column]) or a.columndata[column]) < (tostring(b.columndata[column]) or b.columndata[column]) + else + return (tostring(a.columndata[column]) or a.columndata[column]) > (tostring(b.columndata[column]) or b.columndata[column]) + end + end) + + for k, v in ipairs(children) do + local colorindex = self.rowcolorindex + v.colorindex = colorindex + if colorindex == self.rowcolorindexmax then + self.rowcolorindex = 1 + else + self.rowcolorindex = colorindex + 1 + end + end + + self:CalculateSize() + self:RedoLayout() + +end + +--[[--------------------------------------------------------- + - func: Clear() + - desc: removes all items from the object's list +--]]--------------------------------------------------------- +function newobject:Clear() + + self.children = {} + self:CalculateSize() + self:RedoLayout() + self.parent:PositionColumns() + self.rowcolorindex = 1 + +end + +--[[--------------------------------------------------------- + - func: GetVerticalScrollBody() + - desc: gets the object's vertical scroll body +--]]--------------------------------------------------------- +function newobject:GetVerticalScrollBody() + + for k, v in ipairs(self.internals) do + if v.bartype == "vertical" then + return v + end + end + + return false + +end + +--[[--------------------------------------------------------- + - func: GetHorizontalScrollBody() + - desc: gets the object's horizontal scroll body +--]]--------------------------------------------------------- +function newobject:GetHorizontalScrollBody() + + for k, v in ipairs(self.internals) do + if v.bartype == "horizontal" then + return v + end + end + + return false + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/columnlist/columnlistheader.lua b/loveframes/objects/internal/columnlist/columnlistheader.lua new file mode 100644 index 0000000..d4f5be0 --- /dev/null +++ b/loveframes/objects/internal/columnlist/columnlistheader.lua @@ -0,0 +1,203 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- columnlistheader class +local newobject = loveframes.NewObject("columnlistheader", "loveframes_object_columnlistheader", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: intializes the element +--]]--------------------------------------------------------- +function newobject:initialize(name, parent) + + self.type = "columnlistheader" + self.parent = parent + self.name = name + self.state = parent.state + self.width = parent.defaultcolumnwidth + self.height = parent.columnheight + self.columnid = 0 + self.hover = false + self.down = false + self.clickable = true + self.enabled = true + self.descending = true + self.resizebox = nil + self.internal = true + + table.insert(parent.children, self) + + local key = 0 + + for k, v in ipairs(parent.children) do + if v == self then + key = k + end + end + + self.OnClick = function(object) + local descending = object.descending + local parent = object.parent + local pinternals = parent.internals + local list = pinternals[1] + if descending then + object.descending = false + else + object.descending = true + end + list:Sort(key, object.descending) + end + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the object +--]]--------------------------------------------------------- +function newobject:update(dt) + + if not self.visible then + if not self.alwaysupdate then + return + end + end + + local update = self.Update + local parent = self.parent + local list = parent.internals[1] + local vbody = list:GetVerticalScrollBody() + local width = list.width + if vbody then + width = width - vbody.width + end + + self.clickbounds = {x = list.x, y = list.y, width = width, height = list.height} + self:CheckHover() + + if not self.hover then + self.down = false + else + if loveframes.downobject == self then + self.down = true + end + end + + -- move to parent if there is a parent + if parent ~= loveframes.base then + self.x = (parent.x + self.staticx) - parent.internals[1].offsetx + self.y = parent.y + self.staticy + end + + local resizecolumn = parent.resizecolumn + + if resizecolumn and resizecolumn == self then + local x, y = love.mouse.getPosition() + local start = false + self.width = x - self.x + if self.width < 20 then + self.width = 20 + end + parent.startadjustment = true + parent.internals[1]:CalculateSize() + parent.internals[1]:RedoLayout() + elseif resizecolumn and parent.startadjustment then + local header = parent.children[self.columnid - 1] + self.staticx = header.staticx + header.width + end + + self.resizebox = {x = self.x + (self.width - 2), y = self.y, width = 4, height = self.height} + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +function newobject:mousepressed(x, y, button) + + if not self.parent.resizecolumn and self.parent.canresizecolumns then + local box = self.resizebox + local col = loveframes.BoundingBox(x, box.x, y, box.y, 1, box.width, 1, box.height) + if col then + self.resizing = true + self.parent.resizecolumn = self + end + end + + if self.hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" and button == 1 then + baseparent:MakeTop() + end + self.down = true + loveframes.downobject = self + end + +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + + if not self.visible then + return + end + + local hover = self.hover + local down = self.down + local clickable = self.clickable + local enabled = self.enabled + local onclick = self.OnClick + + if hover and down and clickable and button == 1 then + if enabled then + onclick(self, x, y) + end + end + + local resizecolumn = self.parent.resizecolumn + if resizecolumn and resizecolumn == self then + self.parent.resizecolumn = nil + end + + self.down = false + +end + +--[[--------------------------------------------------------- + - func: SetName(name) + - desc: sets the object's name +--]]--------------------------------------------------------- +function newobject:SetName(name) + + self.name = name + return self + +end + +--[[--------------------------------------------------------- + - func: GetName() + - desc: gets the object's name +--]]--------------------------------------------------------- +function newobject:GetName() + + return self.name + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/columnlist/columnlistrow.lua b/loveframes/objects/internal/columnlist/columnlistrow.lua new file mode 100644 index 0000000..242f840 --- /dev/null +++ b/loveframes/objects/internal/columnlist/columnlistrow.lua @@ -0,0 +1,218 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- columnlistrow class +local newobject = loveframes.NewObject("columnlistrow", "loveframes_object_columnlistrow", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: intializes the element +--]]--------------------------------------------------------- +function newobject:initialize(parent, data) + + self.type = "columnlistrow" + self.parent = parent + self.state = parent.state + self.colorindex = self.parent.rowcolorindex + self.font = loveframes.basicfontsmall + self.width = 80 + self.height = 25 + self.textx = 5 + self.texty = 5 + self.selected = false + self.internal = true + self.columndata = {} + + for k, v in ipairs(data) do + self.columndata[k] = tostring(v) + end + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the object +--]]--------------------------------------------------------- +function newobject:update(dt) + + if not self.visible then + if not self.alwaysupdate then + return + end + end + + local parent = self.parent + local update = self.Update + + self:CheckHover() + + -- move to parent if there is a parent + if parent ~= loveframes.base then + self.x = parent.x + self.staticx + self.y = parent.y + self.staticy + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +function newobject:mousepressed(x, y, button) + + if not self.visible then + return + end + + if self.hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + self:GetParent():GetParent():SelectRow(self, loveframes.IsCtrlDown()) + end + +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + + if not self.visible then + return + end + + if self.hover then + local parent = self:GetParent():GetParent() + if button == 1 then + local onrowclicked = parent.OnRowClicked + if onrowclicked then + onrowclicked(parent, self, self.columndata) + end + elseif button == 2 then + local onrowrightclicked = parent.OnRowRightClicked + if onrowrightclicked then + onrowrightclicked(parent, self, self.columndata) + end + end + end + +end + +--[[--------------------------------------------------------- + - func: SetTextPos(x, y) + - desc: sets the positions of the object's text +--]]--------------------------------------------------------- +function newobject:SetTextPos(x, y) + + self.textx = x + self.texty = y + +end + +--[[--------------------------------------------------------- + - func: GetTextX() + - desc: gets the object's text x position +--]]--------------------------------------------------------- +function newobject:GetTextX() + + return self.textx + +end + +--[[--------------------------------------------------------- + - func: GetTextY() + - desc: gets the object's text y position +--]]--------------------------------------------------------- +function newobject:GetTextY() + + return self.texty + +end + +--[[--------------------------------------------------------- + - func: SetFont(font) + - desc: sets the object's font +--]]--------------------------------------------------------- +function newobject:SetFont(font) + + self.font = font + +end + +--[[--------------------------------------------------------- + - func: GetFont() + - desc: gets the object's font +--]]--------------------------------------------------------- +function newobject:GetFont() + + return self.font + +end + +--[[--------------------------------------------------------- + - func: GetColorIndex() + - desc: gets the object's color index +--]]--------------------------------------------------------- +function newobject:GetColorIndex() + + return self.colorindex + +end + +--[[--------------------------------------------------------- + - func: SetColumnData(data) + - desc: sets the object's column data +--]]--------------------------------------------------------- +function newobject:SetColumnData(data) + + self.columndata = data + +end + +--[[--------------------------------------------------------- + - func: GetColumnData() + - desc: gets the object's column data +--]]--------------------------------------------------------- +function newobject:GetColumnData() + + return self.columndata + +end + +--[[--------------------------------------------------------- + - func: SetSelected(selected) + - desc: sets whether or not the object is selected +--]]--------------------------------------------------------- +function newobject:SetSelected(selected) + + self.selected = true + +end + +--[[--------------------------------------------------------- + - func: GetSelected() + - desc: gets whether or not the object is selected +--]]--------------------------------------------------------- +function newobject:GetSelected() + + return self.selected + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/linenumberspanel.lua b/loveframes/objects/internal/linenumberspanel.lua new file mode 100644 index 0000000..ed4600b --- /dev/null +++ b/loveframes/objects/internal/linenumberspanel.lua @@ -0,0 +1,161 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- linenumberspanel class +local newobject = loveframes.NewObject("linenumberspanel", "loveframes_object_linenumberspanel", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize(parent) + + self.parent = parent + self.type = "linenumberspanel" + self.width = 5 + self.height = 5 + self.offsety = 0 + self.staticx = 0 + self.staticy = 0 + self.internal = true + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the element +--]]--------------------------------------------------------- +function newobject:update(dt) + + local visible = self.visible + local alwaysupdate = self.alwaysupdate + + if not visible then + if not alwaysupdate then + return + end + end + + local parent = self.parent + local base = loveframes.base + local update = self.Update + local height = self.parent.height + local parentinternals = parent.internals + + self.height = height + self.offsety = self.parent.offsety - self.parent.textoffsety + + -- 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 parentinternals[1] ~= self then + self:Remove() + table.insert(parentinternals, 1, self) + return + end + + self:CheckHover() + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: draw() + - desc: draws the object +--]]--------------------------------------------------------- +function newobject:draw() + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + local x = self.x + local y = self.y + local width = self.width + local height = self.height + local stencilfunc = function() love.graphics.rectangle("fill", self.parent.x, self.parent.y, width, height) end + + if self.parent.hbar then + stencilfunc = function() love.graphics.rectangle("fill", self.parent.x, self.parent.y, self.width, self.parent.height - 16) end + end + + self:SetDrawOrder() + + love.graphics.stencil(stencilfunc) + love.graphics.setStencilTest("greater", 0) + + local drawfunc = self.Draw or self.drawfunc + if drawfunc then + drawfunc(self) + end + + love.graphics.setStencilTest() + +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +function newobject:mousepressed(x, y, button) + + local visible = self.visible + + if not visible then + return + end + + local hover = self.hover + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + end + +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + + local visible = self.visible + + if not visible then + return + end + +end + +--[[--------------------------------------------------------- + - func: GetOffsetY() + - desc: gets the object's y offset +--]]--------------------------------------------------------- +function newobject:GetOffsetY() + + return self.offsety + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/menuoption.lua b/loveframes/objects/internal/menuoption.lua new file mode 100644 index 0000000..37e9b1e --- /dev/null +++ b/loveframes/objects/internal/menuoption.lua @@ -0,0 +1,218 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- 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 + self:SetDrawFunc() +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 activated = self.activated + local base = loveframes.base + local update = self.Update + + if option_type == "submenu_activator" then + if hover and not activated then + self.menu:SetVisible(true) + self.menu:MoveToTop() + 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 + elseif activated then + local screen_width = love.graphics.getWidth() + local screen_height = love.graphics.getHeight() + local sx = self.x + local sy = self.y + local width = self.width + local height = self.height + local x1 = sx + width + if x1 + self.menu.width <= screen_width then + self.menu.x = x1 + else + self.menu.x = sx - self.menu.width + end + if sy + self.menu.height <= screen_height then + self.menu.y = sy + else + self.menu.y = (sy + height) - self.menu.height + 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: 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 == 1 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) + self.icon:setFilter("nearest", "nearest") + 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 + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/modalbackground.lua b/loveframes/objects/internal/modalbackground.lua new file mode 100644 index 0000000..b28d825 --- /dev/null +++ b/loveframes/objects/internal/modalbackground.lua @@ -0,0 +1,79 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- modalbackground class +local newobject = loveframes.NewObject("modalbackground", "loveframes_object_modalbackground", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize(object) + + self.type = "modalbackground" + self.width = love.graphics.getWidth() + self.height = love.graphics.getHeight() + self.x = 0 + self.y = 0 + self.internal = true + self.parent = loveframes.base + self.object = object + + table.insert(loveframes.base.children, self) + + if self.object.type ~= "frame" then + self:Remove() + end + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the element +--]]--------------------------------------------------------- +function newobject:update(dt) + + local visible = self.visible + local alwaysupdate = self.alwaysupdate + + if not visible then + if not alwaysupdate then + return + end + end + + local object = self.object + local update = self.Update + local base = loveframes.base + local basechildren = base.children + + self:CheckHover() + + if #basechildren > 1 then + if basechildren[#basechildren - 1] ~= self then + self:Remove() + table.insert(basechildren, self) + end + end + + if not object:IsActive() then + self:Remove() + loveframes.modalobject = false + end + + if update then + update(self, dt) + end + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/multichoice/multichoicelist.lua b/loveframes/objects/internal/multichoice/multichoicelist.lua new file mode 100644 index 0000000..670290d --- /dev/null +++ b/loveframes/objects/internal/multichoice/multichoicelist.lua @@ -0,0 +1,420 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- multichoicelist class +local newobject = loveframes.NewObject("multichoicelist", "loveframes_object_multichoicelist", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize(object) + + self.type = "multichoicelist" + self.parent = loveframes.base + self.list = object + self.x = object.x + self.y = object.y + self.list.height + self.width = self.list.width + self.height = 0 + self.clickx = 0 + self.clicky = 0 + self.padding = self.list.listpadding + self.spacing = self.list.listspacing + self.buttonscrollamount = object.buttonscrollamount + self.mousewheelscrollamount = object.mousewheelscrollamount + self.offsety = 0 + self.offsetx = 0 + self.extrawidth = 0 + self.extraheight = 0 + self.canremove = false + self.dtscrolling = self.list.dtscrolling + self.internal = true + self.vbar = false + self.children = {} + self.internals = {} + + for k, v in ipairs(object.choices) do + local row = loveframes.objects["multichoicerow"]:new() + row:SetText(v) + self:AddItem(row) + end + + table.insert(loveframes.base.internals, self) + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + self:SetDrawFunc() +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 + + local width = love.graphics.getWidth() + local height = love.graphics.getHeight() + local x, y = love.mouse.getPosition() + local selfcol = loveframes.BoundingBox(x, self.x, y, self.y, 1, self.width, 1, self.height) + local parent = self.parent + local base = loveframes.base + local upadte = self.Update + local internals = self.internals + local children = self.children + + -- move to parent if there is a parent + if parent ~= base then + self.x = parent.x + self.staticx + self.y = parent.y + self.staticy + end + + if self.x < 0 then + self.x = 0 + end + + if self.x + self.width > width then + self.x = width - self.width + end + + if self.y < 0 then + self.y = 0 + end + + if self.y + self.height > height then + self.y = height - self.height + end + + for k, v in ipairs(internals) do + v:update(dt) + end + + for k, v in ipairs(children) do + v:update(dt) + v:SetClickBounds(self.x, self.y, self.width, self.height) + v.y = (v.parent.y + v.staticy) - self.offsety + v.x = (v.parent.x + v.staticx) - self.offsetx + end + + if upadte then + upadte(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: draw() + - desc: draws the object +--]]--------------------------------------------------------- +--[[ +function newobject:draw() + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + self:SetDrawOrder() + + local drawfunc = self.Draw or self.drawfunc + if drawfunc then + drawfunc(self) + end + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + v:draw() + end + end + + love.graphics.stencil(stencilfunc) + love.graphics.setStencilTest("greater", 0) + + local children = self.children + if children then + for k, v in ipairs(children) do + local col = loveframes.BoundingBox(self.x, v.x, self.y, v.y, self.width, v.width, self.height, v.height) + if col then + v:draw() + end + end + end + + love.graphics.setStencilTest() + + drawfunc = self.DrawOver or self.drawoverfunc + if drawfunc then + 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 + + local selfcol = loveframes.BoundingBox(x, self.x, y, self.y, 1, self.width, 1, self.height) + local internals = self.internals + local children = self.children + + if not selfcol and self.canremove and button == 1 then + self:Close() + end + + for k, v in ipairs(internals) do + v:mousepressed(x, y, button) + end + + for k, v in ipairs(children) do + v:mousepressed(x, y, button) + 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 + local children = self.children + + self.canremove = true + + for k, v in ipairs(internals) do + v:mousereleased(x, y, button) + end + + for k, v in ipairs(children) do + v:mousereleased(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: wheelmoved(x, y) + - desc: called when the player moves a mouse wheel +--]]--------------------------------------------------------- +function newobject:wheelmoved(x, y) + + local toplist = self:IsTopList() + local internals = self.internals + local scrollamount = self.mousewheelscrollamount + + if self.vbar and toplist then + local bar = internals[1].internals[1].internals[1] + local dtscrolling = self.dtscrolling + if dtscrolling then + local dt = love.timer.getDelta() + bar:Scroll(-y * scrollamount * dt) + else + bar:Scroll(-y * scrollamount) + end + end + +end + +--[[--------------------------------------------------------- + - func: AddItem(object) + - desc: adds an item to the object +--]]--------------------------------------------------------- +function newobject:AddItem(object) + + if object.type ~= "multichoicerow" then + return + end + + object.parent = self + table.insert(self.children, object) + + self:CalculateSize() + self:RedoLayout() + +end + +--[[--------------------------------------------------------- + - func: RemoveItem(object) + - desc: removes an item from the object +--]]--------------------------------------------------------- +function newobject:RemoveItem(object) + + local children = self.children + + for k, v in ipairs(children) do + if v == object then + table.remove(children, k) + end + end + + self:CalculateSize() + self:RedoLayout() + +end + +--[[--------------------------------------------------------- + - func: CalculateSize() + - desc: calculates the size of the object's children +--]]--------------------------------------------------------- +function newobject:CalculateSize() + + self.height = self.padding + + if self.list.listheight then + self.height = self.list.listheight + else + for k, v in ipairs(self.children) do + self.height = self.height + (v.height + self.spacing) + end + end + + if self.height > love.graphics.getHeight() then + self.height = love.graphics.getHeight() + end + + local numitems = #self.children + local height = self.height + local padding = self.padding + local spacing = self.spacing + local itemheight = self.padding + local vbar = self.vbar + local children = self.children + + for k, v in ipairs(children) do + itemheight = itemheight + v.height + spacing + end + + self.itemheight = (itemheight - spacing) + padding + + if self.itemheight > height then + self.extraheight = self.itemheight - height + if not vbar then + local scroll = loveframes.objects["scrollbody"]:new(self, "vertical") + table.insert(self.internals, scroll) + self.vbar = true + end + else + if vbar then + self.internals[1]:Remove() + self.vbar = false + self.offsety = 0 + end + end + +end + +--[[--------------------------------------------------------- + - func: RedoLayout() + - desc: used to redo the layour of the object +--]]--------------------------------------------------------- +function newobject:RedoLayout() + + local children = self.children + local padding = self.padding + local spacing = self.spacing + local starty = padding + local vbar = self.vbar + + if #children > 0 then + for k, v in ipairs(children) do + v.staticx = padding + v.staticy = starty + if vbar then + v.width = (self.width - self.internals[1].width) - padding * 2 + self.internals[1].staticx = self.width - self.internals[1].width + self.internals[1].height = self.height + else + v.width = self.width - padding * 2 + end + starty = starty + v.height + starty = starty + spacing + end + end + +end + +--[[--------------------------------------------------------- + - func: SetPadding(amount) + - desc: sets the object's padding +--]]--------------------------------------------------------- +function newobject:SetPadding(amount) + + self.padding = amount + +end + +--[[--------------------------------------------------------- + - func: SetSpacing(amount) + - desc: sets the object's spacing +--]]--------------------------------------------------------- +function newobject:SetSpacing(amount) + + self.spacing = amount + +end + +--[[--------------------------------------------------------- + - func: Close() + - desc: closes the object +--]]--------------------------------------------------------- +function newobject:Close() + + self:Remove() + self.list.haslist = false + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/multichoice/multichoicerow.lua b/loveframes/objects/internal/multichoice/multichoicerow.lua new file mode 100644 index 0000000..d19404c --- /dev/null +++ b/loveframes/objects/internal/multichoice/multichoicerow.lua @@ -0,0 +1,157 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- multichoicerow class +local newobject = loveframes.NewObject("multichoicerow", "loveframes_object_multichoicerow", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "multichoicerow" + self.text = "" + self.width = 50 + self.height = 25 + self.hover = false + self.internal = true + self.down = false + self.canclick = false + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the object +--]]--------------------------------------------------------- +function newobject:update(dt) + + local visible = self.visible + local alwaysupdate = self.alwaysupdate + + if not visible then + if not alwaysupdate then + return + end + end + + local parent = self.parent + local base = loveframes.base + local update = self.Update + + self:CheckHover() + + if not self.hover then + self.down = false + else + if loveframes.downobject == self then + self.down = true + end + end + + if not self.down and loveframes.downobject == self then + self.hover = true + end + + -- move to parent if there is a parent + if parent ~= base then + self.x = parent.x + self.staticx + self.y = parent.y + self.staticy + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +function newobject:mousepressed(x, y, button) + + local visible = self.visible + + if not visible then + return + end + + local hover = self.hover + + if hover and button == 1 then + self.down = true + loveframes.downobject = self + end + +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + + local visible = self.visible + + if not visible then + return + end + + local text = self.text + + if self.hover and self.down and self.canclick and button == 1 then + self.parent.list:SelectChoice(text) + end + + self.down = false + self.canclick = true + +end + +--[[--------------------------------------------------------- + - func: keypressed(key, isrepeat) + - desc: called when the player presses a key +--]]--------------------------------------------------------- +function newobject:keypressed(key, isrepeat) + + local text = self.text + local selectedobject = loveframes.selectedobject + + if key == "return" and selectedobject == self then + self.parent.list:SelectChoice(text) + 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 + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/scrollable/scrollarea.lua b/loveframes/objects/internal/scrollable/scrollarea.lua new file mode 100644 index 0000000..12f6ea8 --- /dev/null +++ b/loveframes/objects/internal/scrollable/scrollarea.lua @@ -0,0 +1,204 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- scrollarea class +local newobject = loveframes.NewObject("scrollarea", "loveframes_object_scrollarea", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize(parent, bartype) + + self.type = "scroll-area" + self.bartype = bartype + self.parent = parent + self.x = 0 + self.y = 0 + self.scrolldelay = 0 + self.delayamount = 0.05 + self.down = false + self.internal = true + self.internals = {} + + table.insert(self.internals, loveframes.objects["scrollbar"]:new(self, bartype)) + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the object +--]]--------------------------------------------------------- +function newobject:update(dt) + + local visible = self.visible + local alwaysupdate = self.alwaysupdate + + if not visible then + if not alwaysupdate then + return + end + end + + self:CheckHover() + + local base = loveframes.base + local parent = self.parent + local pinternals = parent.internals + local button = pinternals[2] + local bartype = self.bartype + local time = love.timer.getTime() + local x, y = love.mouse.getPosition() + local listo = parent.parent + local down = self.down + local scrolldelay = self.scrolldelay + local delayamount = self.delayamount + local internals = self.internals + local bar = internals[1] + local hover = self.hover + local update = self.Update + + if button then + if bartype == "vertical" then + self.staticx = 0 + self.staticy = button.height - 1 + self.width = parent.width + self.height = parent.height - button.height*2 + 2 + elseif bartype == "horizontal" then + self.staticx = button.width - 1 + self.staticy = 0 + self.width = parent.width - button.width*2 + 2 + self.height = parent.height + end + end + + -- move to parent if there is a parent + if parent ~= base then + self.x = parent.x + self.staticx + self.y = parent.y + self.staticy + end + + if down then + if scrolldelay < time then + self.scrolldelay = time + delayamount + if self.bartype == "vertical" then + if y > bar.y then + bar:Scroll(bar.height) + else + bar:Scroll(-bar.height) + end + elseif self.bartype == "horizontal" then + if x > bar.x then + bar:Scroll(bar.width) + else + bar:Scroll(-bar.width) + end + end + end + if not hover then + self.down = false + end + end + + for k, v in ipairs(internals) do + v:update(dt) + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +function newobject:mousepressed(x, y, button) + + local visible = self.visible + + if not visible then + return + end + + local listo = self.parent.parent + local time = love.timer.getTime() + local internals = self.internals + local bar = internals[1] + local hover = self.hover + local delayamount = self.delayamount + + if hover and button == 1 then + self.down = true + self.scrolldelay = time + delayamount + 0.5 + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + if self.bartype == "vertical" then + if y > self.internals[1].y then + bar:Scroll(bar.height) + else + bar:Scroll(-bar.height) + end + elseif self.bartype == "horizontal" then + if x > bar.x then + bar:Scroll(bar.width) + else + bar:Scroll(-bar.width) + end + end + loveframes.downobject = self + end + + for k, v in ipairs(internals) do + v:mousepressed(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + + local visible = self.visible + + if not visible then + return + end + + local internals = self.internals + + if button == 1 then + self.down = false + end + + for k, v in ipairs(internals) do + v:mousereleased(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: GetBarType() + - desc: gets the object's bar type +--]]--------------------------------------------------------- +function newobject:GetBarType() + + return self.bartype + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/scrollable/scrollbar.lua b/loveframes/objects/internal/scrollable/scrollbar.lua new file mode 100644 index 0000000..846d1ea --- /dev/null +++ b/loveframes/objects/internal/scrollable/scrollbar.lua @@ -0,0 +1,358 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- scrollbar class +local newobject = loveframes.NewObject("scrollbar", "loveframes_object_scrollbar", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize(parent, bartype) + + self.type = "scrollbar" + self.bartype = bartype + self.parent = parent + self.x = 0 + self.y = 0 + self.staticx = 0 + self.staticy = 0 + self.maxx = 0 + self.maxy = 0 + self.clickx = 0 + self.clicky = 0 + self.starty = 0 + self.lastwidth = 0 + self.lastheight = 0 + self.lastx = 0 + self.lasty = 0 + self.internal = true + self.hover = false + self.dragging = false + self.autoscroll = false + self.internal = true + + if self.bartype == "vertical" then + self.width = self.parent.width + self.height = 5 + elseif self.bartype == "horizontal" then + self.width = 5 + self.height = self.parent.height + end + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the object +--]]--------------------------------------------------------- +function newobject:update(dt) + + local visible = self.visible + local alwaysupdate = self.alwaysupdate + + if not visible then + if not alwaysupdate then + return + end + end + + self:CheckHover() + + local x, y = love.mouse.getPosition() + local bartype = self.bartype + local cols = {} + local basecols = {} + local dragging = self.dragging + + if bartype == "vertical" then + self.width = self.parent.width + elseif bartype == "horizontal" then + self.height = self.parent.height + end + + if bartype == "vertical" then + local parent = self.parent + local listo = parent.parent.parent + local height = parent.height * (listo.height/listo.itemheight) + if height < 20 then + self.height = 20 + else + self.height = height + end + self.maxy = parent.y + (parent.height - self.height) + self.x = parent.x + parent.width - self.width + self.y = parent.y + self.staticy + if dragging then + if self.staticy ~= self.lasty then + if listo.OnScroll then + listo.OnScroll(listo) + end + self.lasty = self.staticy + end + self.staticy = self.starty + (y - self.clicky) + end + local space = (self.maxy - parent.y) + local remaining = (0 + self.staticy) + local percent = remaining/space + local extra = listo.extraheight * percent + local autoscroll = self.autoscroll + local lastheight = self.lastheight + listo.offsety = 0 + extra + if self.staticy > space then + self.staticy = space + listo.offsety = listo.extraheight + end + if self.staticy < 0 then + self.staticy = 0 + listo.offsety = 0 + end + if autoscroll then + if listo.itemheight > lastheight then + local type = listo.type + self.lastheight = listo.itemheight + if type == "textinput" then + local indicatory = listo.indicatory + local font = listo.font + local theight = font:getHeight("a") + local y = listo.y + local height = listo.height + local linecount = #listo.lines + local parentheight = self.parent.height + if (indicatory + theight) > (y + height) then + self:Scroll(parentheight/linecount) + end + else + local maxy = self.maxy + self:Scroll(maxy) + end + end + end + elseif bartype == "horizontal" then + local parent = self.parent + local listo = self.parent.parent.parent + local width = self.parent.width * (listo.width/listo.itemwidth) + if width < 20 then + self.width = 20 + else + self.width = width + end + self.maxx = parent.x + (parent.width) - self.width + self.x = parent.x + self.staticx + self.y = parent.y + self.staticy + if dragging then + if self.staticx ~= self.lastx then + if listo.OnScroll then + listo.OnScroll(listo) + end + self.lastx = self.staticx + end + self.staticx = self.startx + (x - self.clickx) + end + local space = (self.maxx - parent.x) + local remaining = (0 + self.staticx) + local percent = remaining/space + local extra = listo.extrawidth * percent + local autoscroll = self.autoscroll + local lastwidth = self.lastwidth + listo.offsetx = 0 + extra + if self.staticx > space then + self.staticx = space + listo.offsetx = listo.extrawidth + end + + if self.staticx < 0 then + self.staticx = 0 + listo.offsetx = 0 + end + if autoscroll then + if listo.itemwidth > lastwidth then + self.lastwidth = listo.itemwidth + self:Scroll(self.maxx) + end + end + end + + local update = self.Update + if update then update(self, dt) end + +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +function newobject:mousepressed(x, y, button) + + local visible = self.visible + local hover = self.hover + + if not visible then + return + end + + if not hover then + return + end + + local baseparent = self:GetBaseParent() + + if baseparent.type == "frame" then + baseparent:MakeTop() + end + + local dragging = self.dragging + + if not dragging then + if button == 1 then + self.starty = self.staticy + self.startx = self.staticx + self.clickx = x + self.clicky = y + self.dragging = true + loveframes.downobject = self + end + end + +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + + local visible = self.visible + + if not visible then + return + end + + if self.dragging then + self.dragging = false + end + +end + +--[[--------------------------------------------------------- + - func: SetMaxX(x) + - desc: sets the object's max x position +--]]--------------------------------------------------------- +function newobject:SetMaxX(x) + + self.maxx = x + +end + +--[[--------------------------------------------------------- + - func: SetMaxY(y) + - desc: sets the object's max y position +--]]--------------------------------------------------------- +function newobject:SetMaxY(y) + + self.maxy = y + +end + +--[[--------------------------------------------------------- + - func: Scroll(amount) + - desc: scrolls the object +--]]--------------------------------------------------------- +function newobject:Scroll(amount) + + local bartype = self.bartype + local listo = self.parent.parent.parent + local onscroll = listo.OnScroll + + if bartype == "vertical" then + local newy = (self.y + amount) + if newy > self.maxy then + self.staticy = self.maxy - self.parent.y + elseif newy < self.parent.y then + self.staticy = 0 + else + self.staticy = self.staticy + amount + end + elseif bartype == "horizontal" then + local newx = (self.x + amount) + if newx > self.maxx then + self.staticx = self.maxx - self.parent.x + elseif newx < self.parent.x then + self.staticx = 0 + else + self.staticx = self.staticx + amount + end + end + + if onscroll then + onscroll(listo) + end + +end + +--[[--------------------------------------------------------- + - func: ScrollTo(position) + - desc: scrolls the object +--]]--------------------------------------------------------- +function newobject:ScrollTo(position) + + local bartype = self.bartype + local listo = self.parent.parent.parent + local onscroll = listo.OnScroll + + if bartype == "vertical" then + local maxRealPos = self.parent.height - self.height + if position > 1 then + self.staticy = maxRealPos + elseif position < 0 then + self.staticy = 0 + else + self.staticy = position * maxRealPos + end + elseif bartype == "horizontal" then + local maxRealPos = self.parent.width - self.width + if position > 1 then + self.staticx = maxRealPos + elseif position < 0 then + self.staticx = 0 + else + self.staticx = position * maxRealPos + end + end + + if onscroll then + onscroll(listo) + end + +end + +--[[--------------------------------------------------------- + - func: IsDragging() + - desc: gets whether the object is being dragged or not +--]]--------------------------------------------------------- +function newobject:IsDragging() + + return self.dragging + +end + +--[[--------------------------------------------------------- + - func: GetBarType() + - desc: gets the object's bartype +--]]--------------------------------------------------------- +function newobject:GetBarType() + + return self.bartype + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/scrollable/scrollbody.lua b/loveframes/objects/internal/scrollable/scrollbody.lua new file mode 100644 index 0000000..6d2b172 --- /dev/null +++ b/loveframes/objects/internal/scrollable/scrollbody.lua @@ -0,0 +1,192 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- scrollbar class +local newobject = loveframes.NewObject("scrollbody", "loveframes_object_scrollbody", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize(parent, bartype) + + self.type = "scrollbody" + self.bartype = bartype + self.parent = parent + self.x = 0 + self.y = 0 + self.internal = true + self.internals = {} + + if self.bartype == "vertical" then + self.width = 16 + self.height = self.parent.height + self.staticx = self.parent.width - self.width + self.staticy = 0 + elseif self.bartype == "horizontal" then + self.width = self.parent.width + self.height = 16 + self.staticx = 0 + self.staticy = self.parent.height - self.height + end + + table.insert(self.internals, loveframes.objects["scrollarea"]:new(self, bartype)) + + local bar = self.internals[1].internals[1] + + if self.bartype == "vertical" then + local upbutton = loveframes.objects["scrollbutton"]:new("up") + upbutton.staticx = 0 + self.width - upbutton.width + upbutton.staticy = 0 + upbutton.parent = self + upbutton.Update = function(object, dt) + upbutton.staticx = 0 + self.width - upbutton.width + upbutton.staticy = 0 + if object.down and object.hover then + local dtscrolling = self.parent.dtscrolling + if dtscrolling then + local dt = love.timer.getDelta() + bar:Scroll(-self.parent.buttonscrollamount * dt) + else + bar:Scroll(-self.parent.buttonscrollamount) + end + end + end + local downbutton = loveframes.objects["scrollbutton"]:new("down") + downbutton.parent = self + downbutton.staticx = 0 + self.width - downbutton.width + downbutton.staticy = 0 + self.height - downbutton.height + downbutton.Update = function(object, dt) + downbutton.staticx = 0 + self.width - downbutton.width + downbutton.staticy = 0 + self.height - downbutton.height + downbutton.x = downbutton.parent.x + downbutton.staticx + downbutton.y = downbutton.parent.y + downbutton.staticy + if object.down and object.hover then + local dtscrolling = self.parent.dtscrolling + if dtscrolling then + local dt = love.timer.getDelta() + bar:Scroll(self.parent.buttonscrollamount * dt) + else + bar:Scroll(self.parent.buttonscrollamount) + end + end + end + table.insert(self.internals, upbutton) + table.insert(self.internals, downbutton) + elseif self.bartype == "horizontal" then + local leftbutton = loveframes.objects["scrollbutton"]:new("left") + leftbutton.parent = self + leftbutton.staticx = 0 + leftbutton.staticy = 0 + leftbutton.Update = function(object, dt) + leftbutton.staticx = 0 + leftbutton.staticy = 0 + if object.down and object.hover then + local dtscrolling = self.parent.dtscrolling + if dtscrolling then + local dt = love.timer.getDelta() + bar:Scroll(-self.parent.buttonscrollamount * dt) + else + bar:Scroll(-self.parent.buttonscrollamount) + end + end + end + local rightbutton = loveframes.objects["scrollbutton"]:new("right") + rightbutton.parent = self + rightbutton.staticx = 0 + self.width - rightbutton.width + rightbutton.staticy = 0 + rightbutton.Update = function(object, dt) + rightbutton.staticx = 0 + self.width - rightbutton.width + rightbutton.staticy = 0 + rightbutton.x = rightbutton.parent.x + rightbutton.staticx + rightbutton.y = rightbutton.parent.y + rightbutton.staticy + if object.down and object.hover then + local dtscrolling = self.parent.dtscrolling + if dtscrolling then + local dt = love.timer.getDelta() + bar:Scroll(self.parent.buttonscrollamount * dt) + else + bar:Scroll(self.parent.buttonscrollamount) + end + end + end + table.insert(self.internals, leftbutton) + table.insert(self.internals, rightbutton) + end + + local parentstate = parent.state + self:SetState(parentstate) + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the object +--]]--------------------------------------------------------- +function newobject:update(dt) + + local visible = self.visible + local alwaysupdate = self.alwaysupdate + + if not visible then + if not alwaysupdate then + return + end + end + + self:CheckHover() + + local parent = self.parent + local base = loveframes.base + local update = self.Update + local internals = self.internals + + -- move to parent if there is a parent + if parent ~= base then + self.x = parent.x + self.staticx + self.y = parent.y + self.staticy + end + + -- resize to parent + if parent ~= base then + if self.bartype == "vertical" then + self.height = self.parent.height + self.staticx = self.parent.width - self.width + if parent.hbar then self.height = self.height - parent:GetHorizontalScrollBody().height end + elseif self.bartype == "horizontal" then + self.width = self.parent.width + self.staticy = self.parent.height - self.height + if parent.vbar then self.width = self.width - parent:GetVerticalScrollBody().width end + end + end + + for k, v in ipairs(internals) do + v:update(dt) + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: GetScrollBar() + - desc: gets the object's scroll bar +--]]--------------------------------------------------------- +function newobject:GetScrollBar() + + return self.internals[1].internals[1] + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/scrollable/scrollbutton.lua b/loveframes/objects/internal/scrollable/scrollbutton.lua new file mode 100644 index 0000000..7cde625 --- /dev/null +++ b/loveframes/objects/internal/scrollable/scrollbutton.lua @@ -0,0 +1,139 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- scrollbutton clas +local newobject = loveframes.NewObject("scrollbutton", "loveframes_object_scrollbutton", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize(scrolltype) + + self.type = "scrollbutton" + self.scrolltype = scrolltype + self.width = 16 + self.height = 16 + self.down = false + self.internal = true + self.OnClick = function() end + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the object +--]]--------------------------------------------------------- +function newobject:update(dt) + + 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 + + if not hover then + self.down = false + else + if loveframes.downobject == self then + self.down = true + end + end + + if not self.down and loveframes.downobject == self then + self.hover = true + end + + -- move to parent if there is a parent + if parent ~= base then + self.x = parent.x + self.staticx + self.y = parent.y + self.staticy + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +function newobject:mousepressed(x, y, button) + + local visible = self.visible + + if not visible then + return + end + + local hover = self.hover + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent.type == "frame" then + baseparent:MakeTop() + end + self.down = true + loveframes.downobject = self + end + +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + + local visible = self.visible + + if not visible then + return + end + + local hover = self.hover + local down = self.down + local onclick = self.OnClick + + if hover and down then + if button == 1 then + onclick(x, y, self) + end + end + + self.down = false + +end + +--[[--------------------------------------------------------- + - func: GetScrollType() + - desc: gets the object's scroll type +--]]--------------------------------------------------------- +function newobject:GetScrollType() + + return self.scrolltype + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/sliderbutton.lua b/loveframes/objects/internal/sliderbutton.lua new file mode 100644 index 0000000..f22b276 --- /dev/null +++ b/loveframes/objects/internal/sliderbutton.lua @@ -0,0 +1,228 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- sliderbutton class +local newobject = loveframes.NewObject("sliderbutton", "loveframes_object_sliderbutton", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize(parent) + + self.type = "sliderbutton" + self.width = 10 + self.height = 20 + self.staticx = 0 + self.staticy = 0 + self.startx = 0 + self.clickx = 0 + self.starty = 0 + self.clicky = 0 + self.intervals = true + self.internal = true + self.down = false + self.dragging = false + self.parent = parent + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the object +--]]--------------------------------------------------------- +function newobject:update(dt) + + local visible = self.visible + local alwaysupdate = self.alwaysupdate + + if not visible then + if not alwaysupdate then + return + end + end + + self:CheckHover() + + local x, y = love.mouse.getPosition() + local intervals = self.intervals + local progress = 0 + local nvalue = 0 + local pvalue = self.parent.value + local hover = self.hover + local down = self.down + local downobject = loveframes.downobject + local parent = self.parent + local slidetype = parent.slidetype + local dragging = self.dragging + local base = loveframes.base + local update = self.Update + + if not hover then + self.down = false + if downobject == self then + self.hover = true + end + else + if downobject == self then + self.down = true + end + end + + if not down and downobject == self then + self.hover = true + end + + -- move to parent if there is a parent + if parent ~= base then + self.x = parent.x + self.staticx + self.y = parent.y + self.staticy + end + + -- start calculations if the button is being dragged + if dragging then + -- calculations for horizontal sliders + if slidetype == "horizontal" then + self.staticx = self.startx + (x - self.clickx) + progress = self.staticx/(self.parent.width - self.width) + nvalue = self.parent.min + (self.parent.max - self.parent.min) * progress + nvalue = loveframes.Round(nvalue, self.parent.decimals) + -- calculations for vertical sliders + elseif slidetype == "vertical" then + self.staticy = self.starty + (y - self.clicky) + local space = self.parent.height - self.height + local remaining = (self.parent.height - self.height) - self.staticy + local percent = remaining/space + nvalue = self.parent.min + (self.parent.max - self.parent.min) * percent + nvalue = loveframes.Round(nvalue, self.parent.decimals) + end + if nvalue > self.parent.max then + nvalue = self.parent.max + end + if nvalue < self.parent.min then + nvalue = self.parent.min + end + self.parent.value = nvalue + if self.parent.value == -0 then + self.parent.value = math.abs(self.parent.value) + end + if nvalue ~= pvalue and nvalue >= self.parent.min and nvalue <= self.parent.max then + if self.parent.OnValueChanged then + self.parent.OnValueChanged(self.parent, self.parent.value) + end + end + loveframes.downobject = self + end + + if slidetype == "horizontal" then + if (self.staticx + self.width) > self.parent.width then + self.staticx = self.parent.width - self.width + end + if self.staticx < 0 then + self.staticx = 0 + end + end + + if slidetype == "vertical" then + if (self.staticy + self.height) > self.parent.height then + self.staticy = self.parent.height - self.height + end + if self.staticy < 0 then + self.staticy = 0 + end + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +function newobject:mousepressed(x, y, button) + + local visible = self.visible + + if not visible then + return + end + + local hover = self.hover + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + self.down = true + self.dragging = true + self.startx = self.staticx + self.clickx = x + self.starty = self.staticy + self.clicky = y + loveframes.downobject = self + end + +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + + local visible = self.visible + + if not visible then + return + end + + local down = self.down + local dragging = self.dragging + + if dragging then + local parent = self.parent + local onrelease = parent.OnRelease + if onrelease then + onrelease(parent) + end + end + + self.down = false + self.dragging = false + +end + +--[[--------------------------------------------------------- + - func: MoveToX(x) + - desc: moves the object to the specified x position +--]]--------------------------------------------------------- +function newobject:MoveToX(x) + + self.staticx = x + +end + +--[[--------------------------------------------------------- + - func: MoveToY(y) + - desc: moves the object to the specified y position +--]]--------------------------------------------------------- +function newobject:MoveToY(y) + + self.staticy = y + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/tabbutton.lua b/loveframes/objects/internal/tabbutton.lua new file mode 100644 index 0000000..5816f90 --- /dev/null +++ b/loveframes/objects/internal/tabbutton.lua @@ -0,0 +1,205 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- tabbutton class +local newobject = loveframes.NewObject("tabbutton", "loveframes_object_tabbutton", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize(parent, text, tabnumber, tip, image, onopened, onclosed) + + self.type = "tabbutton" + self.font = loveframes.smallfont + self.text = text + self.tabnumber = tabnumber + self.parent = parent + self.state = parent.state + self.staticx = 0 + self.staticy = 0 + self.width = 50 + self.height = 25 + self.internal = true + self.down = false + self.image = nil + self.OnOpened = nil + self.OnClosed = nil + + if tip then + self.tooltip = loveframes.objects["tooltip"]:new(self, tip) + self.tooltip:SetFollowCursor(false) + self.tooltip:SetFollowObject(true) + self.tooltip:SetOffsets(0, -(self.tooltip.internals[1]:GetHeight() + 12)) + end + + if image then + self:SetImage(image) + end + + if onopened then + self.OnOpened = onopened + end + + if onclosed then + self.OnClosed = onclosed + end + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the object +--]]--------------------------------------------------------- +function newobject:update(dt) + + local visible = self.visible + local alwaysupdate = self.alwaysupdate + + if not visible then + if not alwaysupdate then + return + end + end + + local parent = self.parent + local base = loveframes.base + local update = self.Update + + self:CheckHover() + self:SetClickBounds(parent.x, parent.y, parent.width, parent.height) + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: mousepressed(x, y, button) + - desc: called when the player presses a mouse button +--]]--------------------------------------------------------- +function newobject:mousepressed(x, y, button) + + local visible = self.visible + + if not visible then + return + end + + local hover = self.hover + local internals = self.internals + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + self.down = true + loveframes.downobject = self + end + +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + + local visible = self.visible + + if not visible then + return + end + + local hover = self.hover + local parent = self.parent + local tabnumber = self.tabnumber + + if hover and button == 1 then + if button == 1 then + local tab = parent.tab + local internals = parent.internals + local onopened = self.OnOpened + local prevtab = internals[tab] + local onclosed = prevtab.OnClosed + parent:SwitchToTab(tabnumber) + if onopened then + onopened(self) + end + if onclosed then + onclosed(prevtab) + end + end + end + + self.down = false + +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: SetImage(image) + - desc: adds an image to the object +--]]--------------------------------------------------------- +function newobject:SetImage(image) + + if type(image) == "string" then + self.image = love.graphics.newImage(image) + self.image:setFilter("nearest", "nearest") + else + self.image = image + end +end + +--[[--------------------------------------------------------- + - func: GetImage() + - desc: gets the object's image +--]]--------------------------------------------------------- +function newobject:GetImage() + + return self.image + +end + +--[[--------------------------------------------------------- + - func: GetTabNumber() + - desc: gets the object's tab number +--]]--------------------------------------------------------- +function newobject:GetTabNumber() + + return self.tabnumber + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/tooltip.lua b/loveframes/objects/internal/tooltip.lua new file mode 100644 index 0000000..8c9095e --- /dev/null +++ b/loveframes/objects/internal/tooltip.lua @@ -0,0 +1,353 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- tooltip class +local newobject = loveframes.NewObject("tooltip", "loveframes_object_tooltip", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize(object, text) + + self.type = "tooltip" + self.parent = loveframes.base + self.object = object or nil + self.width = 0 + self.height = 0 + self.padding = 5 + self.xoffset = 10 + self.yoffset = -10 + self.internal = true + self.followcursor = true + self.followobject = false + self.alwaysupdate = true + self.internals = {} + + -- create the object's text + local textobject = loveframes.Create("text") + textobject:Remove() + textobject.parent = self + textobject:SetText(text or "") + textobject:SetPos(10000, 0) -- textobject interferes with hover detection + table.insert(self.internals, textobject) + + -- apply template properties to the object + loveframes.ApplyTemplatesToObject(self) + table.insert(loveframes.base.internals, self) + + self:SetDrawFunc() +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 + local internals = self.internals + local textobject = internals[1] + + if not visible then + textobject:SetPos(10000, 0) -- textobject interferes with hover detection + if not alwaysupdate then + return + end + end + + local padding = self.padding + local object = self.object + local draworder = self.draworder + local update = self.Update + + self.width = textobject.width + padding * 2 + self.height = textobject.height + padding * 2 + + if object then + if object == loveframes.base then + self:Remove() + return + end + --local ovisible = object.visible + local ohover = object.hover + local ostate = object.state + if ostate ~= state then + self.visible = false + return + end + self.visible = ohover + if ohover then + local top = self:IsTopInternal() + local followcursor = self.followcursor + local followobject = self.followobject + local xoffset = self.xoffset + local yoffset = self.yoffset + if followcursor then + local height = self.height + local mx, my = love.mouse.getPosition() + self.x = mx + xoffset + self.y = my - height + yoffset + elseif followobject then + local ox = object.x + local oy = object.y + self.x = ox + xoffset + self.y = oy + yoffset + end + if not top then + self:MoveToTop() + end + textobject:SetPos(padding, padding) + end + end + + --textobject:SetVisible(self.show) + textobject:SetState(selfstate) + textobject:update(dt) + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: SetFollowCursor(bool) + - desc: sets whether or not the tooltip should follow the + cursor +--]]--------------------------------------------------------- +function newobject:SetFollowCursor(bool) + + self.followcursor = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetFollowCursor() + - desc: gets whether or not the tooltip should follow the + cursor +--]]--------------------------------------------------------- +function newobject:GetFollowCursor() + + return self.followcursor + +end + +--[[--------------------------------------------------------- + - func: SetObject(object) + - desc: sets the tooltip's object +--]]--------------------------------------------------------- +function newobject:SetObject(object) + + self.object = object + self.x = object.x + self.y = object.y + + return self + +end + +--[[--------------------------------------------------------- + - func: GetObject() + - desc: gets the tooltip's object +--]]--------------------------------------------------------- +function newobject:GetObject() + + return self.object + +end + +--[[--------------------------------------------------------- + - func: SetText(text) + - desc: sets the tooltip's text +--]]--------------------------------------------------------- +function newobject:SetText(text) + + local internals = self.internals + local textobject = internals[1] + + textobject:SetText(text) + return self + +end + +--[[--------------------------------------------------------- + - func: GetText() + - desc: gets the tooltip's text +--]]--------------------------------------------------------- +function newobject:GetText() + + local internals = self.internals + local textobject = internals[1] + local text = textobject:GetText() + + return text + +end + +--[[--------------------------------------------------------- + - func: SetTextMaxWidth(text) + - desc: sets the tooltip's text max width +--]]--------------------------------------------------------- +function newobject:SetTextMaxWidth(width) + + local internals = self.internals + local textobject = internals[1] + + textobject:SetMaxWidth(width) + return self + +end + +--[[--------------------------------------------------------- + - func: SetOffsetX(xoffset) + - desc: sets the tooltip's x offset +--]]--------------------------------------------------------- +function newobject:SetOffsetX(xoffset) + + self.xoffset = xoffset + return self + +end + +--[[--------------------------------------------------------- + - func: GetOffsetX() + - desc: gets the tooltip's x offset +--]]--------------------------------------------------------- +function newobject:GetOffsetX() + + return self.xoffset + +end + +--[[--------------------------------------------------------- + - func: SetOffsetY(yoffset) + - desc: sets the tooltip's y offset +--]]--------------------------------------------------------- +function newobject:SetOffsetY(yoffset) + + self.yoffset = yoffset + return self + +end + +--[[--------------------------------------------------------- + - func: GetOffsetY() + - desc: gets the tooltip's y offset +--]]--------------------------------------------------------- +function newobject:GetOffsetY() + + return self.yoffset + +end + +--[[--------------------------------------------------------- + - func: SetOffsets(xoffset, yoffset) + - desc: sets the tooltip's x and y offset +--]]--------------------------------------------------------- +function newobject:SetOffsets(xoffset, yoffset) + + self.xoffset = xoffset + self.yoffset = yoffset + + return self + +end + +--[[--------------------------------------------------------- + - func: GetOffsets() + - desc: gets the tooltip's x and y offset +--]]--------------------------------------------------------- +function newobject:GetOffsets() + + return self.xoffset, self.yoffset + +end + +--[[--------------------------------------------------------- + - func: SetPadding(padding) + - desc: sets the tooltip's padding +--]]--------------------------------------------------------- +function newobject:SetPadding(padding) + + self.padding = padding + return self + +end + +--[[--------------------------------------------------------- + - func: GetPadding() + - desc: gets the tooltip's padding +--]]--------------------------------------------------------- +function newobject:GetPadding() + + return self.padding + +end + +--[[--------------------------------------------------------- + - func: SetFont(font) + - desc: sets the tooltip's font +--]]--------------------------------------------------------- +function newobject:SetFont(font) + + local internals = self.internals + local textobject = internals[1] + + textobject:SetFont(font) + return self + +end + +--[[--------------------------------------------------------- + - func: GetFont() + - desc: gets the tooltip's font +--]]--------------------------------------------------------- +function newobject:GetFont() + + local internals = self.internals + local textobject = internals[1] + + return textobject:GetFont() + +end + +--[[--------------------------------------------------------- + - func: SetFollowObject(bool) + - desc: sets whether or not the tooltip should follow + its assigned object +--]]--------------------------------------------------------- +function newobject:SetFollowObject(bool) + + self.followobject = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetFollowObject() + - desc: gets whether or not the tooltip should follow + its assigned object +--]]--------------------------------------------------------- +function newobject:GetFollowObject() + + return self.followobject + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/treenode.lua b/loveframes/objects/internal/treenode.lua new file mode 100644 index 0000000..5ec4e29 --- /dev/null +++ b/loveframes/objects/internal/treenode.lua @@ -0,0 +1,296 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- button object +local newobject = loveframes.NewObject("treenode", "loveframes_object_treenode", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "treenode" + self.text = "Node" + self.width = 250 + self.height = 16 + self.level = 0 + self.leftpadding = 0 + self.lastclick = 0 + self.open = false + self.internal = true + self.internals = {} + self.icon = nil + self.OnOpen = nil + self.OnClose = nil + + self:SetDrawFunc() +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 parent = self.parent + local base = loveframes.base + local update = self.Update + + local tree = self.tree + self:SetClickBounds(tree.x, tree.y, tree.width, tree.height) + + for k, v in ipairs(self.internals) do + if v.type == "treenode" then + if self.open then + v.x = v.tree.x - v.tree.offsetx + v.y = (v.tree.y + self.tree.itemheight) - v.tree.offsety + if v.width > self.tree.itemwidth then + self.tree.itemwidth = v.width + end + self.tree.itemheight = self.tree.itemheight + v.height + v:update(dt) + end + else + v:update(dt) + end + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: draw() + - desc: draws the object +--]]--------------------------------------------------------- +function newobject:draw() + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + -- set the object's draw order + self:SetDrawOrder() + + local drawfunc = self.Draw or self.drawfunc + if drawfunc then + drawfunc(self) + end + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + if v.type == "treenode" then + if self.open then + v:draw() + end + else + v:draw() + end + end + 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 + + for k, v in ipairs(self.internals) do + v:mousepressed(x, y, button) + end + + if self.hover and button == 1 then + local time = os.time() + if self.lastclick + 0.40 > time then + self.open = not self.open + end + self.lastclick = time + local onselectnode = self.tree.OnSelectNode + self.tree.selectednode = self + if onselectnode then + onselectnode(self.parent, self) + end + 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 + + for k, v in ipairs(self.internals) do + v:mousereleased(x, y, button) + end + +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) + self.icon:setFilter("nearest", "nearest") + else + self.icon = icon + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetIcon() + - desc: gets the object's icon +--]]--------------------------------------------------------- +function newobject:GetIcon() + + return self.icon + +end + +--[[--------------------------------------------------------- + - func: SetText(text) + - desc: sets the object's text +--]]--------------------------------------------------------- +function newobject:SetText(text) + + self.text = text + return self + +end + +--[[--------------------------------------------------------- + - func: GetText() + - desc: gets the object's text +--]]--------------------------------------------------------- +function newobject:GetText() + + return self.text + +end + +--[[--------------------------------------------------------- + - func: AddNode(text) + - desc: adds a new node to the object +--]]--------------------------------------------------------- +function newobject:AddNode(text) + + if not self.internals[1] then + local openbutton = loveframes.objects["treenodebutton"]:new() + openbutton.parent = self + openbutton.staticx = 2 + openbutton.staticy = 2 + table.insert(self.internals, openbutton) + end + + local node = loveframes.objects["treenode"]:new() + node.parent = self + node.tree = self.tree + node.text = text + node.level = self.level + 1 + table.insert(self.internals, node) + return node + +end + +--[[--------------------------------------------------------- + - func: RemoveNode(id) + - desc: removes a node from the object +--]]--------------------------------------------------------- +function newobject:RemoveNode(id) + + id = id + 1 + for k, v in ipairs(self.internals) do + if k == id then + v:Remove() + break + end + end + +end + +--[[--------------------------------------------------------- + - func: SetOpen(bool) + - desc: sets whether or not the object is open +--]]--------------------------------------------------------- +function newobject:SetOpen(bool) + + self.open = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetOpen() + - desc: gets whether or not the object is open +--]]--------------------------------------------------------- +function newobject:GetOpen() + + return self.open + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/internal/treenodebutton.lua b/loveframes/objects/internal/treenodebutton.lua new file mode 100644 index 0000000..4e00033 --- /dev/null +++ b/loveframes/objects/internal/treenodebutton.lua @@ -0,0 +1,108 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- button object +local newobject = loveframes.NewObject("treenodebutton", "loveframes_object_treenodebutton", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "treenodebutton" + self.width = 16 + self.height = 16 + self.internal = true + + self:SetDrawFunc() +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 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 + + if update then + update(self, dt) + 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 + + local hover = self.hover + + if hover and button == 1 then + local bool = not self.parent.open + if bool then + local onopen = self.parent.OnOpen + if onopen then + onopen(self.parent) + end + else + local onclose = self.parent.OnClose + if onclose then + onclose(self.parent) + end + end + self.parent:SetOpen(bool) + print("!") + print(self.parent.level) + end + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/list.lua b/loveframes/objects/list.lua new file mode 100644 index 0000000..dec8997 --- /dev/null +++ b/loveframes/objects/list.lua @@ -0,0 +1,807 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- list object +local newobject = loveframes.NewObject("list", "loveframes_object_list", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "list" + self.display = "vertical" + self.width = 300 + self.height = 150 + self.clickx = 0 + self.clicky = 0 + self.padding = 0 + self.spacing = 0 + self.offsety = 0 + self.offsetx = 0 + self.extrawidth = 0 + self.extraheight = 0 + self.buttonscrollamount = 0.10 + self.mousewheelscrollamount = 10 + self.internal = false + self.hbar = false + self.vbar = false + self.autoscroll = false + self.horizontalstacking = false + self.dtscrolling = false + self.internals = {} + self.children = {} + self.OnScroll = nil + + self:SetDrawFunc() +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 internals = self.internals + local children = self.children + local display = self.display + local parent = self.parent + local horizontalstacking = self.horizontalstacking + 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(internals) do + v:update(dt) + for _, p in pairs(self:GetParents()) do + v.x = v.x - (p.offsetx or 0) + v.y = v.y - (p.offsety or 0) + end + end + + local x = self.x + local y = self.y + local width = self.width + local height = self.height + local offsetx = self.offsetx + local offsety = self.offsety + + for k, v in ipairs(children) do + v:update(dt) + v:SetClickBounds(x, y, width, height) + v.x = (v.parent.x + v.staticx) - offsetx + v.y = (v.parent.y + v.staticy) - offsety + for _, p in pairs(self:GetParents()) do + v.x = v.x - (p.offsetx or 0) + v.y = v.y - (p.offsety or 0) + end + if display == "vertical" then + if v.lastheight ~= v.height then + self:CalculateSize() + self:RedoLayout() + end + end + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: draw() + - desc: draws the object +--]]--------------------------------------------------------- +function newobject:draw() + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + local x = self.x + local y = self.y + local width = self.width + local height = self.height + local stencilfunc = function() + love.graphics.rectangle("fill", x, y, width, height) + end + + self:SetDrawOrder() + + local drawfunc = self.Draw or self.drawfunc + if drawfunc then + drawfunc(self) + end + + love.graphics.stencil(stencilfunc) + love.graphics.setStencilTest("greater", 0) + + local children = self.children + if children then + for k, v in ipairs(children) do + local col = loveframes.BoundingBox(x, v.x, y, v.y, width, v.width, height, v.height) + if col then + v:draw() + end + end + end + + love.graphics.setStencilTest() + + local drawfunc = self.DrawOver or self.drawoverfunc + if drawfunc then + drawfunc(self) + end + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + v:draw() + end + 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 + + local hover = self.hover + local children = self.children + local internals = self.internals + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + end + + for k, v in ipairs(internals) do + v:mousepressed(x, y, button) + end + + for k, v in ipairs(children) do + v:mousepressed(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: wheelmoved(x, y) + - desc: called when the player moves a mouse wheel +--]]--------------------------------------------------------- +function newobject:wheelmoved(x, y) + + local toplist = self:IsTopList() + local vbar = self.vbar + local hbar = self.hbar + local scrollamount = self.mousewheelscrollamount + + if (vbar or hbar) and toplist then + local bar = self:GetScrollBar() + local dtscrolling = self.dtscrolling + if dtscrolling then + local dt = love.timer.getDelta() + bar:Scroll(-y * scrollamount * dt) + else + bar:Scroll(-y * scrollamount) + end + end + +end + +--[[--------------------------------------------------------- + - func: AddItem(object) + - desc: adds an item to the object +--]]--------------------------------------------------------- +function newobject:AddItem(object) + + local objtype = object.type + if objtype == "frame" then + return + end + + local children = self.children + local state = self.state + + -- remove the item object from its current parent and make its new parent the list object + object:Remove() + object.parent = self + object:SetState(state) + + -- insert the item object into the list object's children table + table.insert(children, object) + + -- resize the list and redo its layout + self:CalculateSize() + self:RedoLayout() + + return self + +end + +--[[--------------------------------------------------------- + - func: RemoveItem(object or number) + - desc: removes an item from the object +--]]--------------------------------------------------------- +function newobject:RemoveItem(data) + + local dtype = type(data) + + if dtype == "number" then + local children = self.children + local item = children[data] + if item then + item:Remove() + end + else + data:Remove() + end + + self:CalculateSize() + self:RedoLayout() + + return self + +end + +--[[--------------------------------------------------------- + - func: CalculateSize() + - desc: calculates the size of the object's children +--]]--------------------------------------------------------- +function newobject:CalculateSize() + + local numitems = #self.children + local height = self.height + local width = self.width + local padding = self.padding + local spacing = self.spacing + local itemheight = self.padding + local itemwidth = self.padding + local display = self.display + local vbar = self.vbar + local hbar = self.hbar + local internals = self.internals + local children = self.children + local horizontalstacking = self.horizontalstacking + + if display == "vertical" then + if horizontalstacking then + local curwidth = 0 + local maxwidth = width - padding * 2 + local prevheight = 0 + local scrollbar = self:GetScrollBar() + if scrollbar then + maxwidth = maxwidth - scrollbar.width + end + for k, v in ipairs(children) do + if v.height > prevheight then + prevheight = v.height + end + curwidth = curwidth + v.width + spacing + if children[k + 1] then + if curwidth + children[k + 1].width > maxwidth then + curwidth = padding + itemheight = itemheight + prevheight + spacing + prevheight = 0 + end + else + itemheight = itemheight + prevheight + padding + end + end + self.itemheight = itemheight + else + for k, v in ipairs(children) do + itemheight = itemheight + v.height + spacing + end + self.itemheight = (itemheight - spacing) + padding + end + local itemheight = self.itemheight + if itemheight > height then + self.extraheight = itemheight - height + if not vbar then + local scrollbar = loveframes.objects["scrollbody"]:new(self, display) + table.insert(internals, scrollbar) + self.vbar = true + self:GetScrollBar().autoscroll = self.autoscroll + end + else + if vbar then + local bar = internals[1] + bar:Remove() + self.vbar = false + self.offsety = 0 + end + end + elseif display == "horizontal" then + for k, v in ipairs(children) do + itemwidth = itemwidth + v.width + spacing + end + self.itemwidth = (itemwidth - spacing) + padding + local itemwidth = self.itemwidth + if itemwidth > width then + self.extrawidth = itemwidth - width + if not hbar then + local scrollbar = loveframes.objects["scrollbody"]:new(self, display) + table.insert(internals, scrollbar) + self.hbar = true + self:GetScrollBar().autoscroll = self.autoscroll + end + else + if hbar then + local bar = internals[1] + bar:Remove() + self.hbar = false + self.offsetx = 0 + end + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: RedoLayout() + - desc: used to redo the layout of the object +--]]--------------------------------------------------------- +function newobject:RedoLayout() + + local width = self.width + local height = self.height + local children = self.children + local internals = self.internals + local padding = self.padding + local spacing = self.spacing + local starty = padding + local startx = padding + local vbar = self.vbar + local hbar = self.hbar + local display = self.display + local horizontalstacking = self.horizontalstacking + local scrollbody, scrollbodywidth, scrollbodyheight + + if vbar or hbar then + scrollbody = internals[1] + scrollbodywidth = scrollbody.width + scrollbodyheight = scrollbody.height + end + + if #children > 0 then + if display == "vertical" then + if horizontalstacking then + local curwidth = padding + local curheight = padding + local maxwidth = self.width - padding * 2 + local prevheight = 0 + local scrollbar = self:GetScrollBar() + if scrollbar then + maxwidth = maxwidth - scrollbar.width + end + for k, v in ipairs(children) do + local itemheight = v.height + v.lastheight = itemheight + v.staticx = curwidth + v.staticy = curheight + if v.height > prevheight then + prevheight = v.height + end + if children[k + 1] then + curwidth = curwidth + v.width + spacing + if curwidth + (children[k + 1].width) > maxwidth then + curwidth = padding + curheight = curheight + prevheight + spacing + prevheight = 0 + end + end + end + else + for k, v in ipairs(children) do + local itemwidth = v.width + local itemheight = v.height + local retainsize = v.retainsize + v.staticx = padding + v.staticy = starty + v.lastheight = itemheight + if vbar then + if itemwidth + padding > (width - scrollbodywidth) then + v:SetWidth((width - scrollbodywidth) - (padding * 2)) + end + if not retainsize then + v:SetWidth((width - scrollbodywidth) - (padding * 2)) + end + scrollbody.staticx = width - scrollbodywidth + scrollbody.height = height + else + if not retainsize then + v:SetWidth(width - (padding * 2)) + end + end + starty = starty + itemheight + starty = starty + spacing + end + end + elseif display == "horizontal" then + for k, v in ipairs(children) do + local itemwidth = v.width + local itemheight = v.height + local retainsize = v.retainsize + v.staticx = startx + v.staticy = padding + if hbar then + if itemheight + padding > (height - scrollbodyheight) then + v:SetHeight((height - scrollbodyheight) - (padding * 2)) + end + if not retainsize then + v:SetHeight((height - scrollbodyheight) - (padding * 2)) + end + scrollbody.staticy = height - scrollbodyheight + scrollbody.width = width + else + if not retainsize then + v:SetHeight(height - (padding * 2)) + end + end + startx = startx + itemwidth + startx = startx + spacing + end + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetDisplayType(type) + - desc: sets the object's display type +--]]--------------------------------------------------------- +function newobject:SetDisplayType(type) + + local children = self.children + local numchildren = #children + + self.display = type + self.vbar = false + self.hbar = false + self.offsetx = 0 + self.offsety = 0 + self.internals = {} + + if numchildren > 0 then + self:CalculateSize() + self:RedoLayout() + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetDisplayType() + - desc: gets the object's display type +--]]--------------------------------------------------------- +function newobject:GetDisplayType() + + return self.display + +end + +--[[--------------------------------------------------------- + - func: SetPadding(amount) + - desc: sets the object's padding +--]]--------------------------------------------------------- +function newobject:SetPadding(amount) + + local children = self.children + local numchildren = #children + + self.padding = amount + + if numchildren > 0 then + self:CalculateSize() + self:RedoLayout() + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetSpacing(amount) + - desc: sets the object's spacing +--]]--------------------------------------------------------- +function newobject:SetSpacing(amount) + + local children = self.children + local numchildren = #children + + self.spacing = amount + + if numchildren > 0 then + self:CalculateSize() + self:RedoLayout() + end + + return self + +end + +--[[--------------------------------------------------------- + - func: Clear() + - desc: removes all of the object's children +--]]--------------------------------------------------------- +function newobject:Clear() + + self.children = {} + self:CalculateSize() + self:RedoLayout() + + return self + +end + +--[[--------------------------------------------------------- + - func: SetWidth(width, relative) + - desc: sets the object's width +--]]--------------------------------------------------------- +function newobject:SetWidth(width, relative) + + if relative then + self.width = self.parent.width * width + else + self.width = width + end + + self:CalculateSize() + self:RedoLayout() + + return self + +end + +--[[--------------------------------------------------------- + - func: SetHeight(height, relative) + - desc: sets the object's height +--]]--------------------------------------------------------- +function newobject:SetHeight(height, relative) + + if relative then + self.height = self.parent.height * height + else + self.height = height + end + + self:CalculateSize() + self:RedoLayout() + + return self + +end + +--[[--------------------------------------------------------- + - func: SetSize(width, height, r1, r2) + - desc: sets the object's size +--]]--------------------------------------------------------- +function newobject:SetSize(width, height, r1, r2) + + if r1 then + self.width = self.parent.width * width + else + self.width = width + end + + if r2 then + self.height = self.parent.height * height + else + self.height = height + end + + self:CalculateSize() + self:RedoLayout() + + return self + +end + +--[[--------------------------------------------------------- + - func: GetScrollBar() + - desc: gets the object's scroll bar +--]]--------------------------------------------------------- +function newobject:GetScrollBar() + + local vbar = self.vbar + local hbar = self.hbar + local internals = self.internals + + if vbar or hbar then + local scrollbody = internals[1] + local scrollarea = scrollbody.internals[1] + local scrollbar = scrollarea.internals[1] + return scrollbar + else + return false + end + +end + +--[[--------------------------------------------------------- + - func: SetAutoScroll(bool) + - desc: sets whether or not the list's scrollbar should + auto scroll to the bottom when a new object is + added to the list +--]]--------------------------------------------------------- +function newobject:SetAutoScroll(bool) + + local scrollbar = self:GetScrollBar() + + self.autoscroll = bool + + if scrollbar then + scrollbar.autoscroll = bool + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetAutoScroll() + - desc: gets whether or not the list's scrollbar should + auto scroll to the bottom when a new object is + added to the list +--]]--------------------------------------------------------- +function newobject:GetAutoScroll() + + return self.autoscroll + +end + +--[[--------------------------------------------------------- + - func: SetButtonScrollAmount(speed) + - desc: sets the scroll amount of the object's scrollbar + buttons +--]]--------------------------------------------------------- +function newobject:SetButtonScrollAmount(amount) + + self.buttonscrollamount = amount + return self + +end + +--[[--------------------------------------------------------- + - func: GetButtonScrollAmount() + - desc: gets the scroll amount of the object's scrollbar + buttons +--]]--------------------------------------------------------- +function newobject:GetButtonScrollAmount() + + return self.buttonscrollamount + +end + +--[[--------------------------------------------------------- + - func: SetMouseWheelScrollAmount(amount) + - desc: sets the scroll amount of the mouse wheel +--]]--------------------------------------------------------- +function newobject:SetMouseWheelScrollAmount(amount) + + self.mousewheelscrollamount = amount + return self + +end + +--[[--------------------------------------------------------- + - func: GetMouseWheelScrollAmount() + - desc: gets the scroll amount of the mouse wheel +--]]--------------------------------------------------------- +function newobject:GetButtonScrollAmount() + + return self.mousewheelscrollamount + +end + +--[[--------------------------------------------------------- + - func: EnableHorizontalStacking(bool) + - desc: enables or disables horizontal stacking +--]]--------------------------------------------------------- +function newobject:EnableHorizontalStacking(bool) + + local children = self.children + local numchildren = #children + + self.horizontalstacking = bool + + if numchildren > 0 then + self:CalculateSize() + self:RedoLayout() + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetHorizontalStacking() + - desc: gets whether or not the object allows horizontal + stacking +--]]--------------------------------------------------------- +function newobject:GetHorizontalStacking() + + return self.horizontalstacking + +end + +--[[--------------------------------------------------------- + - func: SetDTScrolling(bool) + - desc: sets whether or not the object should use delta + time when scrolling +--]]--------------------------------------------------------- +function newobject:SetDTScrolling(bool) + + self.dtscrolling = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetDTScrolling() + - desc: gets whether or not the object should use delta + time when scrolling +--]]--------------------------------------------------------- +function newobject:GetDTScrolling() + + return self.dtscrolling + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/menu.lua b/loveframes/objects/menu.lua new file mode 100644 index 0000000..bbc47b2 --- /dev/null +++ b/loveframes/objects/menu.lua @@ -0,0 +1,287 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- 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 = {} + + self:SetDrawFunc() +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 + + local screen_width = love.graphics.getWidth() + local screen_height = love.graphics.getHeight() + local sx = self.x + local sy = self.y + local width = self.width + local height = self.height + local x1 = sx + width + if sx + width > screen_width then + self.x = screen_width - width + end + if sy + self.height > screen_height then + self.y = screen_height - self.height + end + + if update then + update(self, dt) + 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) + return self + +end + +--[[--------------------------------------------------------- + - func: RemoveOption(id) + - desc: removes an option +--]]--------------------------------------------------------- +function newobject:RemoveOption(id) + + for k, v in ipairs(self.internals) do + if k == id then + table.remove(self.internals, k) + return + end + end + + return self + +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) + return self + +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) + return self + +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 + + return self + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/multichoice.lua b/loveframes/objects/multichoice.lua new file mode 100644 index 0000000..4323fc2 --- /dev/null +++ b/loveframes/objects/multichoice.lua @@ -0,0 +1,418 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- multichoice object +local newobject = loveframes.NewObject("multichoice", "loveframes_object_multichoice", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "multichoice" + self.choice = "" + self.text = "Select an option" + self.width = 200 + self.height = 25 + self.listpadding = 0 + self.listspacing = 0 + self.buttonscrollamount = 200 + self.mousewheelscrollamount = 1500 + self.sortfunc = function(a, b) return a < b end + self.haslist = false + self.dtscrolling = true + self.enabled = true + self.internal = false + self.choices = {} + self.listheight = nil + + self:SetDrawFunc() +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 + + local parent = self.parent + local base = loveframes.base + local update = self.Update + + self:CheckHover() + + -- 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: 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 + + local hover = self.hover + local haslist = self.haslist + local enabled = self.enabled + + if hover and not haslist and enabled and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + self.haslist = true + self.list = loveframes.objects["multichoicelist"]:new(self) + self.list:SetState(self.state) + loveframes.downobject = self + 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 + +end + +--[[--------------------------------------------------------- + - func: AddChoice(choice) + - desc: adds a choice to the current list of choices +--]]--------------------------------------------------------- +function newobject:AddChoice(choice) + + local choices = self.choices + table.insert(choices, choice) + + return self + +end + +--[[--------------------------------------------------------- + - func: RemoveChoice(choice) + - desc: removes the specified choice from the object's + list of choices +--]]--------------------------------------------------------- +function newobject:RemoveChoice(choice) + + local choices = self.choices + + for k, v in ipairs(choices) do + if v == choice then + table.remove(choices, k) + break + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetChoice(choice) + - desc: sets the current choice +--]]--------------------------------------------------------- +function newobject:SetChoice(choice) + + self.choice = choice + return self + +end + +--[[--------------------------------------------------------- + - func: SelectChoice(choice) + - desc: selects a choice +--]]--------------------------------------------------------- +function newobject:SelectChoice(choice) + + local onchoiceselected = self.OnChoiceSelected + + self.choice = choice + + if self.list then + self.list:Close() + end + + if onchoiceselected then + onchoiceselected(self, choice) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetListHeight(height) + - desc: sets the height of the list of choices +--]]--------------------------------------------------------- +function newobject:SetListHeight(height) + + self.listheight = height + return self + +end + +--[[--------------------------------------------------------- + - func: SetPadding(padding) + - desc: sets the padding of the list of choices +--]]--------------------------------------------------------- +function newobject:SetPadding(padding) + + self.listpadding = padding + return self + +end + +--[[--------------------------------------------------------- + - func: SetSpacing(spacing) + - desc: sets the spacing of the list of choices +--]]--------------------------------------------------------- +function newobject:SetSpacing(spacing) + + self.listspacing = spacing + return self + +end + +--[[--------------------------------------------------------- + - func: GetValue() + - desc: gets the value (choice) of the object +--]]--------------------------------------------------------- +function newobject:GetValue() + + return self.choice + +end + +--[[--------------------------------------------------------- + - func: GetChoice() + - desc: gets the current choice (same as get value) +--]]--------------------------------------------------------- +function newobject:GetChoice() + + return self.choice + +end + +--[[--------------------------------------------------------- + - func: SetText(text) + - desc: sets the object's text +--]]--------------------------------------------------------- +function newobject:SetText(text) + + self.text = text + return self + +end + +--[[--------------------------------------------------------- + - func: GetText() + - desc: gets the object's text +--]]--------------------------------------------------------- +function newobject:GetText() + + return self.text + +end + +--[[--------------------------------------------------------- + - func: SetButtonScrollAmount(speed) + - desc: sets the scroll amount of the object's scrollbar + buttons +--]]--------------------------------------------------------- +function newobject:SetButtonScrollAmount(amount) + + self.buttonscrollamount = amount + return self + +end + +--[[--------------------------------------------------------- + - func: GetButtonScrollAmount() + - desc: gets the scroll amount of the object's scrollbar + buttons +--]]--------------------------------------------------------- +function newobject:GetButtonScrollAmount() + + return self.buttonscrollamount + +end + +--[[--------------------------------------------------------- + - func: SetMouseWheelScrollAmount(amount) + - desc: sets the scroll amount of the mouse wheel +--]]--------------------------------------------------------- +function newobject:SetMouseWheelScrollAmount(amount) + + self.mousewheelscrollamount = amount + return self + +end + +--[[--------------------------------------------------------- + - func: GetMouseWheelScrollAmount() + - desc: gets the scroll amount of the mouse wheel +--]]--------------------------------------------------------- +function newobject:GetButtonScrollAmount() + + return self.mousewheelscrollamount + +end + +--[[--------------------------------------------------------- + - func: SetDTScrolling(bool) + - desc: sets whether or not the object should use delta + time when scrolling +--]]--------------------------------------------------------- +function newobject:SetDTScrolling(bool) + + self.dtscrolling = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetDTScrolling() + - desc: gets whether or not the object should use delta + time when scrolling +--]]--------------------------------------------------------- +function newobject:GetDTScrolling() + + return self.dtscrolling + +end + +--[[--------------------------------------------------------- + - func: Sort(func) + - desc: sorts the object's choices +--]]--------------------------------------------------------- +function newobject:Sort(func) + + local default = self.sortfunc + + if func then + table.sort(self.choices, func) + else + table.sort(self.choices, default) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetSortFunction(func) + - desc: sets the object's default sort function +--]]--------------------------------------------------------- +function newobject:SetSortFunction(func) + + self.sortfunc = func + return self + +end + +--[[--------------------------------------------------------- + - func: GetSortFunction(func) + - desc: gets the object's default sort function +--]]--------------------------------------------------------- +function newobject:GetSortFunction() + + return self.sortfunc + +end + +--[[--------------------------------------------------------- + - func: Clear() + - desc: removes all choices from the object's list + of choices +--]]--------------------------------------------------------- +function newobject:Clear() + + self.choices = {} + self.choice = "" + self.text = "Select an option" + + return self + +end + +--[[--------------------------------------------------------- + - func: SetClickable(bool) + - desc: sets whether or not the object is enabled +--]]--------------------------------------------------------- +function newobject:SetEnabled(bool) + + self.enabled = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetEnabled() + - desc: gets whether or not the object is enabled +--]]--------------------------------------------------------- +function newobject:GetEnabled() + + return self.enabled + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/numberbox.lua b/loveframes/objects/numberbox.lua new file mode 100644 index 0000000..d857155 --- /dev/null +++ b/loveframes/objects/numberbox.lua @@ -0,0 +1,485 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- numberbox object +local newobject = loveframes.NewObject("numberbox", "loveframes_object_numberbox", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "numberbox" + self.width = 80 + self.height = 20 + self.value = 0 + self.increaseamount = 1 + self.decreaseamount = 1 + self.min = -100 + self.max = 100 + self.delay = 0 + self.decimals = 0 + self.internal = false + self.canmodify = false + self.lastbuttonclicked = false + self.internals = {} + self.OnValueChanged = nil + + local input = loveframes.objects["textinput"]:new() + input.parent = self + input:SetSize(50, 20) + input:SetUsable({"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", ".", "-"}) + input:SetTabReplacement("") + input:SetText(self.value) + input.OnTextChanged = function(object) + local value = self.value + local newvalue = tonumber(object.lines[1]) + if not newvalue then + self.value = value + input:SetText(value) + return + end + self.value = newvalue + if self.value > self.max then + self.value = self.max + object:SetText(self.value) + end + if self.value < self.min then + self.value = self.min + object:SetText(self.value) + end + if value ~= self.value then + if self.OnValueChanged then + self.OnValueChanged(self, self.value) + end + end + end + input.Update = function(object) + object:SetSize(object.parent.width - 20, object.parent.height) + end + + local increasebutton = loveframes.objects["button"]:new() + increasebutton.parent = self + increasebutton:SetWidth(21) + increasebutton:SetText("+") + increasebutton.OnClick = function() + local canmodify = self.canmodify + if not canmodify then + self:ModifyValue("add") + else + self.canmodify = false + end + end + increasebutton.Update = function(object) + local time = 0 + time = love.timer.getTime() + local delay = self.delay + local down = object.down + local canmodify = self.canmodify + local lastbuttonclicked = self.lastbuttonclicked + object:SetPos(object.parent.width - 21, 0) + object:SetHeight(object.parent.height/2 + 1) + if down and not canmodify then + self:ModifyValue("add") + self.canmodify = true + self.delay = time + 0.80 + self.lastbuttonclicked = object + elseif down and canmodify and delay < time then + self:ModifyValue("add") + self.delay = time + 0.02 + elseif not down and canmodify and lastbuttonclicked == object then + self.canmodify = false + self.delay = time + 0.80 + end + end + + local decreasesbutton = loveframes.objects["button"]:new() + decreasesbutton.parent = self + decreasesbutton:SetWidth(21) + decreasesbutton:SetText("-") + decreasesbutton.OnClick = function() + local canmodify = self.canmodify + if not canmodify then + self:ModifyValue("subtract") + else + self.canmodify = false + end + end + decreasesbutton.Update = function(object) + local time = 0 + time = love.timer.getTime() + local delay = self.delay + local down = object.down + local canmodify = self.canmodify + local lastbuttonclicked = self.lastbuttonclicked + object:SetPos(object.parent.width - 21, object.parent.height/2) + object:SetHeight(object.parent.height/2) + if down and not canmodify then + self:ModifyValue("subtract") + self.canmodify = true + self.delay = time + 0.80 + self.lastbuttonclicked = object + elseif down and canmodify and delay < time then + self:ModifyValue("subtract") + self.delay = time + 0.02 + elseif not down and canmodify and lastbuttonclicked == object then + self.canmodify = false + self.delay = time + 0.80 + end + end + + table.insert(self.internals, input) + table.insert(self.internals, increasebutton) + table.insert(self.internals, decreasesbutton) + + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the element +--]]--------------------------------------------------------- +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 + + local internals = self.internals + local parent = self.parent + local base = loveframes.base + local update = self.Update + + -- move to parent if there is a parent + if parent ~= base and parent.type ~= "list" then + self.x = self.parent.x + self.staticx + self.y = self.parent.y + self.staticy + end + + self:CheckHover() + + for k, v in ipairs(internals) do + v:update(dt) + end + + if update then + update(self, dt) + 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 + + local internals = self.internals + local hover = self.hover + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + end + + for k, v in ipairs(internals) do + v:mousepressed(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: SetValue(value) + - desc: sets the object's value +--]]--------------------------------------------------------- +function newobject:SetValue(value) + + local min = self.min + local curvalue = self.value + local value = tonumber(value) or min + local internals = self.internals + local input = internals[1] + local onvaluechanged = self.OnValueChanged + + self.value = value + input:SetText(value) + + if value ~= curvalue and onvaluechanged then + onvaluechanged(self, value) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetValue() + - desc: gets the object's value +--]]--------------------------------------------------------- +function newobject:GetValue() + + return self.value + +end + +--[[--------------------------------------------------------- + - func: SetIncreaseAmount(amount) + - desc: sets the object's increase amount +--]]--------------------------------------------------------- +function newobject:SetIncreaseAmount(amount) + + self.increaseamount = amount + return self + +end + +--[[--------------------------------------------------------- + - func: GetIncreaseAmount() + - desc: gets the object's increase amount +--]]--------------------------------------------------------- +function newobject:GetIncreaseAmount() + + return self.increaseamount + +end + +--[[--------------------------------------------------------- + - func: SetDecreaseAmount(amount) + - desc: sets the object's decrease amount +--]]--------------------------------------------------------- +function newobject:SetDecreaseAmount(amount) + + self.decreaseamount = amount + return self + +end + +--[[--------------------------------------------------------- + - func: GetDecreaseAmount() + - desc: gets the object's decrease amount +--]]--------------------------------------------------------- +function newobject:GetDecreaseAmount() + + return self.decreaseamount + +end + +--[[--------------------------------------------------------- + - func: SetMax(max) + - desc: sets the object's maximum value +--]]--------------------------------------------------------- +function newobject:SetMax(max) + + local internals = self.internals + local input = internals[1] + local onvaluechanged = self.OnValueChanged + + self.max = max + + if self.value > max then + self.value = max + input:SetValue(max) + if onvaluechanged then + onvaluechanged(self, max) + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetMax() + - desc: gets the object's maximum value +--]]--------------------------------------------------------- +function newobject:GetMax() + + return self.max + +end + +--[[--------------------------------------------------------- + - func: SetMin(min) + - desc: sets the object's minimum value +--]]--------------------------------------------------------- +function newobject:SetMin(min) + + local internals = self.internals + local input = internals[1] + local onvaluechanged = self.OnValueChanged + + self.min = min + + if self.value < min then + self.value = min + input:SetValue(min) + if onvaluechanged then + onvaluechanged(self, min) + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetMin() + - desc: gets the object's minimum value +--]]--------------------------------------------------------- +function newobject:GetMin() + + return self.min + +end + +--[[--------------------------------------------------------- + - func: SetMinMax() + - desc: sets the object's minimum and maximum values +--]]--------------------------------------------------------- +function newobject:SetMinMax(min, max) + + local internals = self.internals + local input = internals[1] + local onvaluechanged = self.OnValueChanged + + self.min = min + self.max = max + + if self.value > max then + self.value = max + input:SetValue(max) + if onvaluechanged then + onvaluechanged(self, max) + end + end + + if self.value < min then + self.value = min + input:SetValue(min) + if onvaluechanged then + onvaluechanged(self, min) + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetMinMax() + - desc: gets the object's minimum and maximum values +--]]--------------------------------------------------------- +function newobject:GetMinMax() + + return self.min, self.max + +end + +--[[--------------------------------------------------------- + - func: ModifyValue(type) + - desc: modifies the object's value +--]]--------------------------------------------------------- +function newobject:ModifyValue(type) + + local value = self.value + local internals = self.internals + local input = internals[1] + local decimals = self.decimals + local onvaluechanged = self.OnValueChanged + + if not value then + return + end + + if type == "add" then + local increaseamount = self.increaseamount + local max = self.max + self.value = value + increaseamount + if self.value > max then + self.value = max + end + self.value = loveframes.Round(self.value, decimals) + input:SetText(self.value) + if value ~= self.value then + if onvaluechanged then + onvaluechanged(self, self.value) + end + end + elseif type == "subtract" then + local decreaseamount = self.decreaseamount + local min = self.min + self.value = value - decreaseamount + if self.value < min then + self.value = min + end + self.value = loveframes.Round(self.value, decimals) + input:SetText(self.value) + if value ~= self.value then + if onvaluechanged then + onvaluechanged(self, self.value) + end + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetDecimals(decimals) + - desc: sets how many decimals the object's value + can have +--]]--------------------------------------------------------- +function newobject:SetDecimals(decimals) + + self.decimals = decimals + return self + +end + +--[[--------------------------------------------------------- + - func: GetDecimals() + - desc: gets how many decimals the object's value + can have +--]]--------------------------------------------------------- +function newobject:GetDecimals() + + return self.decimals + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/panel.lua b/loveframes/objects/panel.lua new file mode 100644 index 0000000..bb822e3 --- /dev/null +++ b/loveframes/objects/panel.lua @@ -0,0 +1,134 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- panel object +local newobject = loveframes.NewObject("panel", "loveframes_object_panel", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "panel" + self.width = 200 + self.height = 50 + self.internal = false + self.children = {} + + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the element +--]]--------------------------------------------------------- +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 + + local children = self.children + local parent = self.parent + local base = loveframes.base + local update = self.Update + + -- move to parent if there is a parent + if parent ~= base and parent.type ~= "list" then + self.x = self.parent.x + self.staticx + self.y = self.parent.y + self.staticy + end + + self:CheckHover() + + for k, v in ipairs(children) do + v:update(dt) + end + + if update then + update(self, dt) + 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 + + local children = self.children + local hover = self.hover + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + end + + for k, v in ipairs(children) do + v:mousepressed(x, y, button) + 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 + local children = self.children + + if not visible then + return + end + + for k, v in ipairs(children) do + v:mousereleased(x, y, button) + end + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/progressbar.lua b/loveframes/objects/progressbar.lua new file mode 100644 index 0000000..99c25dd --- /dev/null +++ b/loveframes/objects/progressbar.lua @@ -0,0 +1,318 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- progressbar object +local newobject = loveframes.NewObject("progressbar", "loveframes_object_progressbar", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "progressbar" + self.text = "" + self.width = 100 + self.height = 25 + self.min = 0 + self.max = 10 + self.value = 0 + self.barwidth = 0 + self.lerprate = 1000 + self.lerpvalue = 0 + self.lerpto = 0 + self.lerpfrom = 0 + self.completed = false + self.lerp = false + self.internal = false + self.OnComplete = nil + + self:SetDrawFunc() +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 + + local lerp = self.lerp + local lerprate = self.lerprate + local lerpvalue = self.lerpvalue + local lerpto = self.lerpto + local lerpfrom = self.lerpfrom + local value = self.value + local completed = self.completed + local parent = self.parent + local base = loveframes.base + local update = self.Update + local oncomplete = self.OnComplete + + self:CheckHover() + + -- caclulate barwidth + if lerp then + if lerpfrom < lerpto then + if lerpvalue < lerpto then + self.lerpvalue = lerpvalue + lerprate*dt + elseif lerpvalue > lerpto then + self.lerpvalue = lerpto + end + elseif lerpfrom > lerpto then + if lerpvalue > lerpto then + self.lerpvalue = lerpvalue - lerprate*dt + elseif lerpvalue < lerpto then + self.lerpvalue = lerpto + end + elseif lerpfrom == lerpto then + self.lerpvalue = lerpto + end + self.barwidth = self.lerpvalue/self.max * self.width + -- min check + if self.lerpvalue < self.min then + self.lerpvalue = self.min + end + -- max check + if self.lerpvalue > self.max then + self.lerpvalue = self.max + end + else + self.barwidth = value/self.max * self.width + -- min max check + if value < self.min then + self.value = self.min + elseif value > self.max then + self.value = self.max + 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 + + -- completion check + if not completed then + if self.value >= self.max then + self.completed = true + if oncomplete then + oncomplete(self) + end + end + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: SetMax(max) + - desc: sets the object's maximum value +--]]--------------------------------------------------------- +function newobject:SetMax(max) + + self.max = max + return self + +end + +--[[--------------------------------------------------------- + - func: GetMax() + - desc: gets the object's maximum value +--]]--------------------------------------------------------- +function newobject:GetMax() + + return self.max + +end + +--[[--------------------------------------------------------- + - func: SetMin(min) + - desc: sets the object's minimum value +--]]--------------------------------------------------------- +function newobject:SetMin(min) + + self.min = min + return self + +end + +--[[--------------------------------------------------------- + - func: GetMin() + - desc: gets the object's minimum value +--]]--------------------------------------------------------- +function newobject:GetMin() + + return self.min + +end + +--[[--------------------------------------------------------- + - func: SetMinMax() + - desc: sets the object's minimum and maximum values +--]]--------------------------------------------------------- +function newobject:SetMinMax(min, max) + + self.min = min + self.max = max + + return self + +end + +--[[--------------------------------------------------------- + - func: GetMinMax() + - desc: gets the object's minimum and maximum values +--]]--------------------------------------------------------- +function newobject:GetMinMax() + + return self.min, self.max + +end + +--[[--------------------------------------------------------- + - func: SetValue(value) + - desc: sets the object's value +--]]--------------------------------------------------------- +function newobject:SetValue(value) + + local lerp = self.lerp + + if lerp then + self.lerpvalue = self.lerpvalue + self.lerpto = value + self.lerpfrom = self.lerpvalue + self.value = value + else + self.value = value + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetValue() + - desc: gets the object's value +--]]--------------------------------------------------------- +function newobject:GetValue() + + return self.value + +end + +--[[--------------------------------------------------------- + - func: SetLerp(bool) + - desc: sets whether or not the object should lerp + when changing between values +--]]--------------------------------------------------------- +function newobject:SetLerp(bool) + + self.lerp = bool + self.lerpto = self:GetValue() + self.lerpvalue = self:GetValue() + + return self + +end + +--[[--------------------------------------------------------- + - func: GetLerp() + - desc: gets whether or not the object should lerp + when changing between values +--]]--------------------------------------------------------- +function newobject:GetLerp() + + return self.lerp + +end + +--[[--------------------------------------------------------- + - func: SetLerpRate(rate) + - desc: sets the object's lerp rate +--]]--------------------------------------------------------- +function newobject:SetLerpRate(rate) + + self.lerprate = rate + return self + +end + +--[[--------------------------------------------------------- + - func: GetLerpRate() + - desc: gets the object's lerp rate +--]]--------------------------------------------------------- +function newobject:GetLerpRate() + + return self.lerprate + +end + +--[[--------------------------------------------------------- + - func: GetCompleted() + - desc: gets whether or not the object has reached its + maximum value +--]]--------------------------------------------------------- +function newobject:GetCompleted() + + return self.completed + +end + +--[[--------------------------------------------------------- + - func: GetBarWidth() + - desc: gets the object's bar width +--]]--------------------------------------------------------- +function newobject:GetBarWidth() + + return self.barwidth + +end + +--[[--------------------------------------------------------- + - func: SetText(text) + - desc: sets the object's text +--]]--------------------------------------------------------- +function newobject:SetText(text) + + self.text = text + return self + +end + +--[[--------------------------------------------------------- + - func: GetText() + - desc: gets the object's text +--]]--------------------------------------------------------- +function newobject:GetText() + + return self.text + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/radiobutton.lua b/loveframes/objects/radiobutton.lua new file mode 100644 index 0000000..3f362d5 --- /dev/null +++ b/loveframes/objects/radiobutton.lua @@ -0,0 +1,429 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- radiobutton object +local newobject = loveframes.NewObject("radiobutton", "loveframes_object_radiobutton", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "radiobutton" + self.width = 0 + self.height = 0 + self.boxwidth = 20 + self.boxheight = 20 + self.font = loveframes.basicfont + self.checked = false + self.lastvalue = false + self.internal = false + self.down = true + self.enabled = true + self.internals = {} + self.OnChanged = function () end + self.group = {} + + self:SetDrawFunc() +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 internals = self.internals + local boxwidth = self.boxwidth + local boxheight = self.boxheight + local parent = self.parent + local base = loveframes.base + local update = self.Update + + if not hover then + self.down = false + else + if loveframes.downobject == self then + self.down = true + end + end + + if not self.down and loveframes.downobject == self then + self.hover = true + end + + -- move to parent if there is a parent + if parent ~= base and parent.type ~= "list" then + self.x = self.parent.x + self.staticx + self.y = self.parent.y + self.staticy + end + + if internals[1] then + self.width = boxwidth + 5 + internals[1].width + if internals[1].height == boxheight then + self.height = boxheight + else + if internals[1].height > boxheight then + self.height = internals[1].height + else + self.height = boxheight + end + end + else + self.width = boxwidth + self.height = boxheight + end + + for k, v in ipairs(internals) do + v:update(dt) + end + + if update then + update(self, dt) + 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 + + local hover = self.hover + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + self.down = true + loveframes.downobject = self + end + +end + +--[[--------------------------------------------------------- + - func: mousereleased(x, y, button) + - desc: called when the player releases a mouse button +--]]--------------------------------------------------------- +function newobject:mousereleased(x, y, button) + + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + if self.hover and self.down and self.enabled and button == 1 then + if not self.checked then + -- a radio button can only be unchecked by checking another radio button + self:SetChecked(true) + end + end + +end + +--[[--------------------------------------------------------- + - func: SetText(text) + - desc: sets the object's text +--]]--------------------------------------------------------- +function newobject:SetText(text) + + local boxwidth = self.boxwidth + local boxheight = self.boxheight + + if text ~= "" then + self.internals = {} + local textobject = loveframes.Create("text") + local skin = loveframes.GetActiveSkin() + if not skin then + skin = loveframes.config["DEFAULTSKIN"] + end + local directives = skin.directives + if directives then + local default_color = directives.radiobutton_text_default_color + local default_shadowcolor = directives.radiobutton_text_default_shadowcolor + local default_font = directives.radiobutton_text_default_font + if default_color then + textobject.defaultcolor = default_color + end + if default_shadowcolor then + textobject.shadowcolor = default_shadowcolor + end + if default_font then + self.font = default_font + end + end + textobject:Remove() + textobject.parent = self + textobject.state = self.state + textobject.collide = false + textobject:SetFont(self.font) + textobject:SetText(text) + textobject.Update = function(object, dt) + if object.height > boxheight then + object:SetPos(boxwidth + 5, 0) + else + object:SetPos(boxwidth + 5, boxheight/2 - object.height/2) + end + end + table.insert(self.internals, textobject) + else + self.width = boxwidth + self.height = boxheight + self.internals = {} + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetText() + - desc: gets the object's text +--]]--------------------------------------------------------- +function newobject:GetText() + + local internals = self.internals + local text = internals[1] + + if text then + return text.text + else + return false + end + +end + +--[[--------------------------------------------------------- + - func: SetSize(width, height, r1, r2) + - desc: sets the object's size +--]]--------------------------------------------------------- +function newobject:SetSize(width, height, r1, r2) + + if r1 then + self.boxwidth = self.parent.width * width + else + self.boxwidth = width + end + + if r2 then + self.boxheight = self.parent.height * height + else + self.boxheight = height + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetWidth(width, relative) + - desc: sets the object's width +--]]--------------------------------------------------------- +function newobject:SetWidth(width, relative) + + if relative then + self.boxwidth = self.parent.width * width + else + self.boxwidth = width + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetHeight(height, relative) + - desc: sets the object's height +--]]--------------------------------------------------------- +function newobject:SetHeight(height, relative) + + if relative then + self.boxheight = self.parent.height * height + else + self.boxheight = height + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetChecked(bool) + - desc: sets whether the object is checked or not +--]]--------------------------------------------------------- +function newobject:SetChecked(checked) + + if self.checked ~= checked then + self.checked = checked + self:OnChanged(checked) + end + + if checked then + for _, button in pairs(self.group) do + if button ~= self and button.checked then + button:SetChecked(false) + end + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetChecked() + - desc: gets whether the object is checked or not +--]]--------------------------------------------------------- +function newobject:GetChecked() + + return self.checked + +end + +--[[--------------------------------------------------------- + - func: SetGroup() + - desc: set the object's group. only one radio button in a + group is checked at a time. +--]]--------------------------------------------------------- +function newobject:SetGroup(group) + + self.group = group + self.group[self] = self + +end + +--[[--------------------------------------------------------- + - func: GetGroup() + - desc: gets the object's group +--]]--------------------------------------------------------- +function newobject:GetGroup(group) + + return self.group + +end + +--[[--------------------------------------------------------- + - func: SetFont(font) + - desc: sets the font of the object's text +--]]--------------------------------------------------------- +function newobject:SetFont(font) + + local internals = self.internals + local text = internals[1] + + self.font = font + + if text then + text:SetFont(font) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: newobject:GetFont() + - desc: gets the font of the object's text +--]]--------------------------------------------------------- +function newobject:GetFont() + + return self.font + +end + +--[[--------------------------------------------------------- + - func: newobject:GetBoxHeight() + - desc: gets the object's box size +--]]--------------------------------------------------------- +function newobject:GetBoxSize() + + return self.boxwidth, self.boxheight + +end + +--[[--------------------------------------------------------- + - func: newobject:GetBoxWidth() + - desc: gets the object's box width +--]]--------------------------------------------------------- +function newobject:GetBoxWidth() + + return self.boxwidth + +end + +--[[--------------------------------------------------------- + - func: newobject:GetBoxHeight() + - desc: gets the object's box height +--]]--------------------------------------------------------- +function newobject:GetBoxHeight() + + return self.boxheight + +end + +--[[--------------------------------------------------------- + - func: SetClickable(bool) + - desc: sets whether or not the object is enabled +--]]--------------------------------------------------------- +function newobject:SetEnabled(bool) + + self.enabled = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetEnabled() + - desc: gets whether or not the object is enabled +--]]--------------------------------------------------------- +function newobject:GetEnabled() + + return self.enabled + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/slider.lua b/loveframes/objects/slider.lua new file mode 100644 index 0000000..75b157f --- /dev/null +++ b/loveframes/objects/slider.lua @@ -0,0 +1,514 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- slider object +local newobject = loveframes.NewObject("slider", "loveframes_object_slider", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "slider" + self.text = "Slider" + self.slidetype = "horizontal" + self.width = 5 + self.height = 5 + self.max = 10 + self.min = 0 + self.value = 0 + self.decimals = 5 + self.scrollincrease = 1 + self.scrolldecrease = 1 + self.scrollable = true + self.enabled = true + self.internal = false + self.internals = {} + self.OnValueChanged = nil + self.OnRelease = nil + + -- create the slider button + local sliderbutton = loveframes.objects["sliderbutton"]:new(self) + sliderbutton.state = self.state + table.insert(self.internals, sliderbutton) + + -- set initial value to minimum + self:SetValue(self.min) + + self:SetDrawFunc() +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 + + local internals = self.internals + local sliderbutton = internals[1] + local parent = self.parent + local base = loveframes.base + local update = self.Update + + self:CheckHover() + + -- move to parent if there is a parent + if parent ~= base and parent.type ~= "list" then + self.x = self.parent.x + self.staticx + self.y = self.parent.y + self.staticy + end + + if sliderbutton then + local slidetype = self.slidetype + local buttonwidth = sliderbutton.width + local buttonheight = sliderbutton.height + if slidetype == "horizontal" then + self.height = buttonheight + elseif slidetype == "vertical" then + self.width = buttonwidth + end + end + + -- update internals + for k, v in ipairs(self.internals) do + v:update(dt) + end + + if update then + update(self, dt) + 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 + + local enabled = self.enabled + + if not enabled then + return + end + + local internals = self.internals + local hover = self.hover + local slidetype = self.slidetype + local scrollable = self.scrollable + + if hover and button == 1 then + if slidetype == "horizontal" then + local xpos = x - self.x + local button = internals[1] + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + button:MoveToX(xpos) + button.down = true + button.dragging = true + button.startx = button.staticx + button.clickx = x + elseif slidetype == "vertical" then + local ypos = y - self.y + local button = internals[1] + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + button:MoveToY(ypos) + button.down = true + button.dragging = true + button.starty = button.staticy + button.clicky = y + end + elseif hover and scrollable and button == "wu" then + local value = self.value + local increase = self.scrollincrease + local newvalue = value + increase + self:SetValue(newvalue) + elseif hover and scrollable and button == "wd" then + local value = self.value + local decrease = self.scrolldecrease + local newvalue = value - decrease + self:SetValue(newvalue) + end + + for k, v in ipairs(internals) do + v:mousepressed(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: SetValue(value) + - desc: sets the object's value +--]]--------------------------------------------------------- +function newobject:SetValue(value) + + if value > self.max then + return + end + + if value < self.min then + return + end + + local decimals = self.decimals + local newval = loveframes.Round(value, decimals) + local internals = self.internals + local onvaluechanged = self.OnValueChanged + + -- set the new value + self.value = newval + + -- slider button object + local sliderbutton = internals[1] + local slidetype = self.slidetype + local width = self.width + local height = self.height + local min = self.min + local max = self.max + + -- move the slider button to the new position + if slidetype == "horizontal" then + local xpos = width * ((newval - min) / (max - min)) + sliderbutton:MoveToX(xpos) + elseif slidetype == "vertical" then + local ypos = height - height * ((newval - min) / (max - min)) + sliderbutton:MoveToY(ypos) + end + + -- call OnValueChanged + if onvaluechanged then + onvaluechanged(self, newval) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetValue() + - desc: gets the object's value +--]]--------------------------------------------------------- +function newobject:GetValue() + + return self.value + +end + +--[[--------------------------------------------------------- + - func: SetMax(max) + - desc: sets the object's maximum value +--]]--------------------------------------------------------- +function newobject:SetMax(max) + + self.max = max + + if self.value > self.max then + self.value = self.max + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetMax() + - desc: gets the object's maximum value +--]]--------------------------------------------------------- +function newobject:GetMax() + + return self.max + +end + +--[[--------------------------------------------------------- + - func: SetMin(min) + - desc: sets the object's minimum value +--]]--------------------------------------------------------- +function newobject:SetMin(min) + + self.min = min + + if self.value < self.min then + self.value = self.min + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetMin() + - desc: gets the object's minimum value +--]]--------------------------------------------------------- +function newobject:GetMin() + + return self.min + +end + +--[[--------------------------------------------------------- + - func: SetMinMax() + - desc: sets the object's minimum and maximum values +--]]--------------------------------------------------------- +function newobject:SetMinMax(min, max) + + self.min = min + self.max = max + + if self.value > self.max then + self.value = self.max + end + + if self.value < self.min then + self.value = self.min + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetMinMax() + - desc: gets the object's minimum and maximum values +--]]--------------------------------------------------------- +function newobject:GetMinMax() + + return self.min, self.max + +end + +--[[--------------------------------------------------------- + - func: SetText(name) + - desc: sets the objects's text +--]]--------------------------------------------------------- +function newobject:SetText(text) + + self.text = text + return self + +end + +--[[--------------------------------------------------------- + - func: GetText() + - desc: gets the objects's text +--]]--------------------------------------------------------- +function newobject:GetText() + + return self.text + +end + +--[[--------------------------------------------------------- + - func: SetDecimals(decimals) + - desc: sets how many decimals the object's value + can have +--]]--------------------------------------------------------- +function newobject:SetDecimals(decimals) + + self.decimals = decimals + return self + +end + +--[[--------------------------------------------------------- + - func: GetDecimals() + - desc: gets how many decimals the object's value + can have +--]]--------------------------------------------------------- +function newobject:GetDecimals() + + return self.decimals + +end + +--[[--------------------------------------------------------- + - func: SetButtonSize(width, height) + - desc: sets the objects's button size +--]]--------------------------------------------------------- +function newobject:SetButtonSize(width, height) + + local internals = self.internals + local sliderbutton = internals[1] + + if sliderbutton then + sliderbutton.width = width + sliderbutton.height = height + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetButtonSize() + - desc: gets the objects's button size +--]]--------------------------------------------------------- +function newobject:GetButtonSize() + + local internals = self.internals + local sliderbutton = internals[1] + + if sliderbutton then + return sliderbutton.width, sliderbutton.height + end + +end + +--[[--------------------------------------------------------- + - func: SetSlideType(slidetype) + - desc: sets the objects's slide type +--]]--------------------------------------------------------- +function newobject:SetSlideType(slidetype) + + self.slidetype = slidetype + + if slidetype == "vertical" then + self:SetValue(self.min) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetSlideType() + - desc: gets the objects's slide type +--]]--------------------------------------------------------- +function newobject:GetSlideType() + + return self.slidetype + +end + +--[[--------------------------------------------------------- + - func: SetScrollable(bool) + - desc: sets whether or not the object can be scrolled + via the mouse wheel +--]]--------------------------------------------------------- +function newobject:SetScrollable(bool) + + self.scrollable = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetScrollable() + - desc: gets whether or not the object can be scrolled + via the mouse wheel +--]]--------------------------------------------------------- +function newobject:GetScrollable() + + return self.scrollable + +end + +--[[--------------------------------------------------------- + - func: SetScrollIncrease(increase) + - desc: sets the amount to increase the object's value + by when scrolling with the mouse wheel +--]]--------------------------------------------------------- +function newobject:SetScrollIncrease(increase) + + self.scrollincrease = increase + return self + +end + +--[[--------------------------------------------------------- + - func: GetScrollIncrease() + - desc: gets the amount to increase the object's value + by when scrolling with the mouse wheel +--]]--------------------------------------------------------- +function newobject:GetScrollIncrease() + + return self.scrollincrease + +end + +--[[--------------------------------------------------------- + - func: SetScrollDecrease(decrease) + - desc: sets the amount to decrease the object's value + by when scrolling with the mouse wheel +--]]--------------------------------------------------------- +function newobject:SetScrollDecrease(decrease) + + self.scrolldecrease = decrease + return self + +end + +--[[--------------------------------------------------------- + - func: GetScrollDecrease() + - desc: gets the amount to decrease the object's value + by when scrolling with the mouse wheel +--]]--------------------------------------------------------- +function newobject:GetScrollDecrease() + + return self.scrolldecrease + +end + +--[[--------------------------------------------------------- + - func: SetEnabled(bool) + - desc: sets whether or not the object is enabled +--]]--------------------------------------------------------- +function newobject:SetEnabled(bool) + + self.enabled = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetEnabled() + - desc: gets whether or not the object is enabled +--]]--------------------------------------------------------- +function newobject:GetEnabled() + + return self.enabled + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/tabs.lua b/loveframes/objects/tabs.lua new file mode 100644 index 0000000..fff0b72 --- /dev/null +++ b/loveframes/objects/tabs.lua @@ -0,0 +1,765 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- tabs object +local newobject = loveframes.NewObject("tabs", "loveframes_object_tabs", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "tabs" + self.width = 100 + self.height = 50 + self.clickx = 0 + self.clicky = 0 + self.offsetx = 0 + self.tab = 1 + self.tabnumber = 1 + self.padding = 5 + self.tabheight = 25 + self.previoustabheight = 25 + self.buttonscrollamount = 200 + self.mousewheelscrollamount = 1500 + self.buttonareax = 0 + self.buttonareawidth = self.width + self.autosize = true + self.autobuttonareawidth = true + self.dtscrolling = true + self.internal = false + self.tooltipfont = loveframes.basicfontsmall + self.internals = {} + self.children = {} + + self:AddScrollButtons() + self:SetDrawFunc() +end + +--[[--------------------------------------------------------- + - func: update(deltatime) + - desc: updates the element +--]]--------------------------------------------------------- +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 + + local x, y = love.mouse.getPosition() + local tabheight = self.tabheight + local padding = self.padding + local autosize = self.autosize + local autobuttonareawidth = self.autobuttonareawidth + local padding = self.padding + local children = self.children + local numchildren = #children + local internals = self.internals + local tab = self.tab + 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 + + self:CheckHover() + + if numchildren > 0 and tab == 0 then + self.tab = 1 + end + + if autobuttonareawidth then + local width = self.width + self.buttonareawidth = width + end + + local pos = 0 + + for k, v in ipairs(internals) do + v:update(dt) + if v.type == "tabbutton" then + v.x = (v.parent.x + v.staticx) + pos + self.offsetx + self.buttonareax + v.y = (v.parent.y + v.staticy) + pos = pos + v.width - 1 + end + end + + if #self.children > 0 then + self.children[self.tab]:update(dt) + self.children[self.tab]:SetPos(padding, tabheight + padding) + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: draw() + - desc: draws the object +--]]--------------------------------------------------------- +function newobject:draw() + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + local x = self.x + local y = self.y + local width = self.width + local height = self.height + local tabheight = self:GetHeightOfButtons() + local stencilfunc = function() love.graphics.rectangle("fill", x + self.buttonareax, y, self.buttonareawidth, height) end + + self:SetDrawOrder() + + local drawfunc = self.Draw or self.drawfunc + if drawfunc then + drawfunc(self) + end + + love.graphics.stencil(stencilfunc) + love.graphics.setStencilTest("greater", 0) + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + local col = loveframes.BoundingBox(x + self.buttonareax, v.x, self.y, v.y, self.buttonareawidth, v.width, tabheight, v.height) + if col or v.type == "scrollbutton" then + v:draw() + end + end + end + + love.graphics.setStencilTest() + + local children = self.children + if #children > 0 then + children[self.tab]:draw() + end + + drawfunc = self.DrawOver or self.drawoverfunc + if drawfunc then + 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 + + local children = self.children + local internals = self.internals + local numchildren = #children + local numinternals = #internals + local tab = self.tab + local hover = self.hover + + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + end + + for k, v in ipairs(internals) do + v:mousepressed(x, y, button) + end + + if numchildren > 0 then + children[tab]:mousepressed(x, y, button) + 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 + local children = self.children + local numchildren = #children + local tab = self.tab + local internals = self.internals + + if not visible then + return + end + + for k, v in ipairs(internals) do + v:mousereleased(x, y, button) + end + + if numchildren > 0 then + children[tab]:mousereleased(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: wheelmoved(x, y) + - desc: called when the player moves a mouse wheel +--]]--------------------------------------------------------- +function newobject:wheelmoved(x, y) + + local internals = self.internals + local numinternals = #internals + + if y < 0 then + local buttonheight = self:GetHeightOfButtons() + local col = loveframes.BoundingBox(self.x, x, self.y, y, self.width, 1, buttonheight, 1) + local visible = internals[numinternals - 1]:GetVisible() + if col and visible then + local scrollamount = -y * self.mousewheelscrollamount + local dtscrolling = self.dtscrolling + if dtscrolling then + local dt = love.timer.getDelta() + self.offsetx = self.offsetx + scrollamount * dt + else + self.offsetx = self.offsetx + scrollamount + end + if self.offsetx > 0 then + self.offsetx = 0 + end + end + elseif y > 0 then + local buttonheight = self:GetHeightOfButtons() + local col = loveframes.BoundingBox(self.x, x, self.y, y, self.width, 1, buttonheight, 1) + local visible = internals[numinternals]:GetVisible() + if col and visible then + local bwidth = self:GetWidthOfButtons() + local scrollamount = y * self.mousewheelscrollamount + local dtscrolling = self.dtscrolling + if dtscrolling then + local dt = love.timer.getDelta() + self.offsetx = self.offsetx - scrollamount * dt + else + self.offsetx = self.offsetx - scrollamount + end + if ((self.offsetx + bwidth) + self.width) < self.width then + self.offsetx = -(bwidth + 10) + end + end + end + +end + +--[[--------------------------------------------------------- + - func: AddTab(name, object, tip, image) + - desc: adds a new tab to the tab panel +--]]--------------------------------------------------------- +function newobject:AddTab(name, object, tip, image, onopened, onclosed) + + local padding = self.padding + local autosize = self.autosize + local retainsize = self.retainsize + local tabnumber = self.tabnumber + local tabheight = self.tabheight + local internals = self.internals + local state = self.state + + object:Remove() + object.parent = self + object:SetState(state) + object.staticx = 0 + object.staticy = 0 + + if tabnumber ~= 1 then + object.visible = false + end + + local tab = loveframes.objects["tabbutton"]:new(self, name, tabnumber, tip, image, onopened, onclosed) + + table.insert(self.children, object) + table.insert(self.internals, #self.internals - 1, tab) + self.tabnumber = tabnumber + 1 + + if autosize and not retainsize then + object:SetSize(self.width - padding * 2, (self.height - tabheight) - padding * 2) + end + + return tab + +end + +--[[--------------------------------------------------------- + - func: AddScrollButtons() + - desc: creates scroll buttons fot the tab panel + - note: for internal use only +--]]--------------------------------------------------------- +function newobject:AddScrollButtons() + + local internals = self.internals + local state = self.state + + for k, v in ipairs(internals) do + if v.type == "scrollbutton" then + table.remove(internals, k) + end + end + + local leftbutton = loveframes.objects["scrollbutton"]:new("left") + leftbutton.parent = self + leftbutton:SetPos(0, 0) + leftbutton:SetSize(15, 25) + leftbutton:SetAlwaysUpdate(true) + leftbutton.Update = function(object, dt) + object.staticx = 0 + object.staticy = 0 + if self.offsetx ~= 0 then + object.visible = true + else + object.visible = false + object.down = false + object.hover = false + end + if object.down then + if self.offsetx > 0 then + self.offsetx = 0 + elseif self.offsetx ~= 0 then + local scrollamount = self.buttonscrollamount + local dtscrolling = self.dtscrolling + if dtscrolling then + local dt = love.timer.getDelta() + self.offsetx = self.offsetx + scrollamount * dt + else + self.offsetx = self.offsetx + scrollamount + end + end + end + end + + local rightbutton = loveframes.objects["scrollbutton"]:new("right") + rightbutton.parent = self + rightbutton:SetPos(self.width - 15, 0) + rightbutton:SetSize(15, 25) + rightbutton:SetAlwaysUpdate(true) + rightbutton.Update = function(object, dt) + object.staticx = self.width - object.width + object.staticy = 0 + local bwidth = self:GetWidthOfButtons() + if (self.offsetx + bwidth) - (self.buttonareax * 2 - 1) > self.width then + object.visible = true + else + object.visible = false + object.down = false + object.hover = false + end + if object.down then + if ((self.x + self.offsetx) + bwidth) ~= (self.x + self.width) then + local scrollamount = self.buttonscrollamount + local dtscrolling = self.dtscrolling + if dtscrolling then + local dt = love.timer.getDelta() + self.offsetx = self.offsetx - scrollamount * dt + else + self.offsetx = self.offsetx - scrollamount + end + end + end + end + + leftbutton.state = state + rightbutton.state = state + + table.insert(internals, leftbutton) + table.insert(internals, rightbutton) + +end + +--[[--------------------------------------------------------- + - func: GetWidthOfButtons() + - desc: gets the total width of all of the tab buttons +--]]--------------------------------------------------------- +function newobject:GetWidthOfButtons() + + local width = 0 + local internals = self.internals + + for k, v in ipairs(internals) do + if v.type == "tabbutton" then + width = width + v.width + end + end + + return width + +end + +--[[--------------------------------------------------------- + - func: GetHeightOfButtons() + - desc: gets the height of one tab button +--]]--------------------------------------------------------- +function newobject:GetHeightOfButtons() + + return self.tabheight + +end + +--[[--------------------------------------------------------- + - func: SwitchToTab(tabnumber) + - desc: makes the specified tab the active tab +--]]--------------------------------------------------------- +function newobject:SwitchToTab(tabnumber) + + local children = self.children + + for k, v in ipairs(children) do + v.visible = false + end + + self.tab = tabnumber + self.children[tabnumber].visible = true + + return self + +end + +--[[--------------------------------------------------------- + - func: SetScrollButtonSize(width, height) + - desc: sets the size of the scroll buttons +--]]--------------------------------------------------------- +function newobject:SetScrollButtonSize(width, height) + + local internals = self.internals + + for k, v in ipairs(internals) do + if v.type == "scrollbutton" then + v:SetSize(width, height) + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetPadding(paddint) + - desc: sets the padding for the tab panel +--]]--------------------------------------------------------- +function newobject:SetPadding(padding) + + self.padding = padding + return self + +end + +--[[--------------------------------------------------------- + - func: SetPadding(paddint) + - desc: gets the padding of the tab panel +--]]--------------------------------------------------------- +function newobject:GetPadding() + + return self.padding + +end + +--[[--------------------------------------------------------- + - func: SetTabHeight(height) + - desc: sets the height of the tab buttons +--]]--------------------------------------------------------- +function newobject:SetTabHeight(height) + + local autosize = self.autosize + local padding = self.padding + local previoustabheight = self.previoustabheight + local children = self.children + local internals = self.internals + + self.tabheight = height + + local tabheight = self.tabheight + + if tabheight ~= previoustabheight then + for k, v in ipairs(children) do + local retainsize = v.retainsize + if autosize and not retainsize then + v:SetSize(self.width - padding*2, (self.height - tabheight) - padding*2) + end + end + self.previoustabheight = tabheight + end + + for k, v in ipairs(internals) do + if v.type == "tabbutton" then + v:SetHeight(self.tabheight) + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetToolTipFont(font) + - desc: sets the height of the tab buttons +--]]--------------------------------------------------------- +function newobject:SetToolTipFont(font) + + local internals = self.internals + + for k, v in ipairs(internals) do + if v.type == "tabbutton" and v.tooltip then + v.tooltip:SetFont(font) + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetTabNumber() + - desc: gets the object's tab number +--]]--------------------------------------------------------- +function newobject:GetTabNumber() + + return self.tab + +end + +--[[--------------------------------------------------------- + - func: RemoveTab(id) + - desc: removes a tab from the object +--]]--------------------------------------------------------- +function newobject:RemoveTab(id) + + local children = self.children + local internals = self.internals + local tab = children[id] + + if tab then + tab:Remove() + end + + for k, v in ipairs(internals) do + if v.type == "tabbutton" then + if v.tabnumber == id then + v:Remove() + end + end + end + + local tabnumber = 1 + + for k, v in ipairs(internals) do + if v.type == "tabbutton" then + v.tabnumber = tabnumber + tabnumber = tabnumber + 1 + end + end + + self.tabnumber = tabnumber + return self + +end + +--[[--------------------------------------------------------- + - func: SetButtonScrollAmount(speed) + - desc: sets the scroll amount of the object's scrollbar + buttons +--]]--------------------------------------------------------- +function newobject:SetButtonScrollAmount(amount) + + self.buttonscrollamount = amount + return self + +end + +--[[--------------------------------------------------------- + - func: GetButtonScrollAmount() + - desc: gets the scroll amount of the object's scrollbar + buttons +--]]--------------------------------------------------------- +function newobject:GetButtonScrollAmount() + + return self.buttonscrollamount + +end + +--[[--------------------------------------------------------- + - func: SetMouseWheelScrollAmount(amount) + - desc: sets the scroll amount of the mouse wheel +--]]--------------------------------------------------------- +function newobject:SetMouseWheelScrollAmount(amount) + + self.mousewheelscrollamount = amount + return self + +end + +--[[--------------------------------------------------------- + - func: GetMouseWheelScrollAmount() + - desc: gets the scroll amount of the mouse wheel +--]]--------------------------------------------------------- +function newobject:GetButtonScrollAmount() + + return self.mousewheelscrollamount + +end + +--[[--------------------------------------------------------- + - func: SetDTScrolling(bool) + - desc: sets whether or not the object should use delta + time when scrolling +--]]--------------------------------------------------------- +function newobject:SetDTScrolling(bool) + + self.dtscrolling = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetDTScrolling() + - desc: gets whether or not the object should use delta + time when scrolling +--]]--------------------------------------------------------- +function newobject:GetDTScrolling() + + return self.dtscrolling + +end + +--[[--------------------------------------------------------- + - func: SetTabObject(id, object) + - desc: sets the object of a tab +--]]--------------------------------------------------------- +function newobject:SetTabObject(id, object) + + local children = self.children + local internals = self.internals + local tab = children[id] + local state = self.state + + if tab then + tab:Remove() + object:Remove() + object.parent = self + object:SetState(state) + object.staticx = 0 + object.staticy = 0 + children[id] = object + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetButtonAreaX(x) + - desc: sets the x position of the object's button area +--]]--------------------------------------------------------- +function newobject:SetButtonAreaX(x) + + self.buttonareax = x + return self + +end + +--[[--------------------------------------------------------- + - func: GetButtonAreaX() + - desc: gets the x position of the object's button area +--]]--------------------------------------------------------- +function newobject:GetButtonAreaX() + + return self.buttonareax + +end + +--[[--------------------------------------------------------- + - func: SetButtonAreaWidth(width) + - desc: sets the width of the object's button area +--]]--------------------------------------------------------- +function newobject:SetButtonAreaWidth(width) + + self.buttonareawidth = width + return self + +end + +--[[--------------------------------------------------------- + - func: GetButtonAreaWidth() + - desc: gets the width of the object's button area +--]]--------------------------------------------------------- +function newobject:GetButtonAreaWidth() + + return self.buttonareawidth + +end + +--[[--------------------------------------------------------- + - func: SetAutoButtonAreaWidth(bool) + - desc: sets whether or not the width of the object's + button area should be adjusted automatically +--]]--------------------------------------------------------- +function newobject:SetAutoButtonAreaWidth(bool) + + self.autobuttonareawidth = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetAutoButtonAreaWidth() + - desc: gets whether or not the width of the object's + button area should be adjusted automatically +--]]--------------------------------------------------------- +function newobject:GetAutoButtonAreaWidth() + + return self.autobuttonareawidth + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/text.lua b/loveframes/objects/text.lua new file mode 100644 index 0000000..3855b19 --- /dev/null +++ b/loveframes/objects/text.lua @@ -0,0 +1,802 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +--[[------------------------------------------------ + -- note: the text wrapping of this object is + experimental and not final +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- text object +local newobject = loveframes.NewObject("text", "loveframes_object_text", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "text" + self.text = "" + self.font = loveframes.basicfont + self.width = 5 + self.height = 5 + self.maxw = 0 + self.shadowxoffset = 1 + self.shadowyoffset = 1 + self.lines = 0 + self.formattedtext = {} + self.original = {} + self.defaultcolor = {0, 0, 0, 1} + self.shadowcolor = {0, 0, 0, 1} + self.linkcolor = {0, .4, 1, 1} + self.linkhovercolor = {0, 0, 1, 1} + self.ignorenewlines = false + self.shadow = false + self.linkcol = false + self.internal = false + self.linksenabled = false + self.detectlinks = false + self.OnClickLink = nil + + local skin = loveframes.GetActiveSkin() + if not skin then + skin = loveframes.config["DEFAULTSKIN"] + end + + local directives = skin.directives + if directives then + local text_default_color = directives.text_default_color + local text_default_shadowcolor = directives.text_default_shadowcolor + local text_default_font = directives.text_default_font + if text_default_color then + self.defaultcolor = text_default_color + end + if text_default_shadowcolor then + self.shadowcolor = text_default_shadowcolor + end + if text_default_font then + self.font = text_default_font + end + end + self:SetDrawFunc() +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 + + local parent = self.parent + local base = loveframes.base + local update = self.Update + + self:CheckHover() + + local hover = self.hover + local linksenabled = self.linksenabled + local linkcol = false + + if hover and linksenabled and not loveframes.resizeobject then + local formattedtext = self.formattedtext + local x = self.x + local y = self.y + for k, v in ipairs(formattedtext) do + local link = v.link + if link then + local mx, my = love.mouse.getPosition() + local font = v.font + local linkx = v.x + local linky = v.y + local text = v.text + local twidth = font:getWidth(text) + local theight = font:getHeight() + local col = loveframes.BoundingBox(x + linkx, mx, y + linky, my, twidth, 1, theight, 1) + v.hover = false + if col then + v.hover = true + linkcol = true + end + end + end + self.linkcol = linkcol + 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: 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 + + local hover = self.hover + if hover and button == 1 then + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + local linksenabled = self.linksenabled + if linksenabled then + local formattedtext = self.formattedtext + local objx = self.x + local objy = self.y + for k, v in ipairs(formattedtext) do + local link = v.link + if link then + local linkx = v.x + local linky = v.y + local font = v.font + local text = v.text + local twidth = font:getWidth(text) + local theight = font:getHeight() + local col = loveframes.BoundingBox(objx + linkx, x, objy + linky, y, twidth, 1, theight, 1) + if col then + local onclicklink = self.OnClickLink + if onclicklink then + onclicklink(self, text) + end + end + end + end + end + end + +end + +--[[--------------------------------------------------------- + - func: SetText(text) + - desc: sets the object's text +--]]--------------------------------------------------------- +function newobject:SetText(t) + + local dtype = type(t) + local maxw = self.maxw + local font = self.font + local defaultcolor = self.defaultcolor + local inserts = {} + local prevcolor = defaultcolor + local prevlinkcolor = self.linkcolor + local prevlinkhovercolor = self.linkhovercolor + local prevfont = font + local link = false + local tdata + + self.text = "" + self.formattedtext = {} + + if dtype == "string" then + tdata = {t} + self.original = {t} + elseif dtype == "number" then + tdata = {tostring(t)} + self.original = {tostring(t)} + elseif dtype == "table" then + tdata = t + self.original = t + else + return + end + + for k, v in ipairs(tdata) do + dtype = type(v) + if dtype == "table" then + if v.color then + prevcolor = v.color + end + if v.linkcolor then + prevlinkcolor = v.linkcolor + end + if v.linkhovercolor then + prevlinkhovercolor = v.linkhovercolor + end + if v.font then + prevfont = v.font + end + if v.link then + link = true + else + link = false + end + elseif dtype == "number" then + table.insert(self.formattedtext, { + font = prevfont, + color = prevcolor, + linkcolor = prevlinkcolor, + linkhovercolor = prevlinkhovercolor, + link = link, + text = tostring(v) + }) + elseif dtype == "string" then + if self.ignorenewlines then + v = loveframes.utf8.gsub(v, "\n", " ") + end + v = loveframes.utf8.gsub(v, string.char(9), " ") + v = loveframes.utf8.gsub(v, "\n", " \n ") + local parts = loveframes.SplitString(v, " ") + for i, j in ipairs(parts) do + table.insert(self.formattedtext, { + font = prevfont, + color = prevcolor, + linkcolor = prevlinkcolor, + linkhovercolor = prevlinkhovercolor, + link = link, + text = j + }) + end + end + end + + if maxw > 0 then + for k, v in ipairs(self.formattedtext) do + local data = v.text + local width = v.font:getWidth(data) + local curw = 0 + local new = "" + local key = k + if width > maxw then + table.remove(self.formattedtext, k) + for n=1, loveframes.utf8.len(data) do + local item = loveframes.utf8.sub(data, n, n) + local itemw = v.font:getWidth(item) + if n ~= loveframes.utf8.len(data) then + if (curw + itemw) > maxw then + table.insert(inserts, { + key = key, + font = v.font, + color = v.color, + linkcolor = prevlinkcolor, + linkhovercolor = v.linkhovercolor, + link = v.link, + text = new + }) + new = item + curw = 0 + itemw + key = key + 1 + else + new = new .. item + curw = curw + itemw + end + else + new = new .. item + table.insert(inserts, { + key = key, + font = v.font, + color = v.color, + linkcolor = prevlinkcolor, + linkhovercolor = v.linkhovercolor, + link = v.link, + text = new + }) + end + end + end + end + end + + for k, v in ipairs(inserts) do + table.insert(self.formattedtext, v.key, { + font = v.font, + color = v.color, + linkcolor = prevlinkcolor, + linkhovercolor = v.linkhovercolor, + link = v.link, + text = v.text + }) + end + + local textdata = self.formattedtext + local maxw = self.maxw + local font = self.font + local twidth = 0 + local drawx = 0 + local drawy = 0 + local lines = 1 + local textwidth = 0 + local lastwidth = 0 + local totalwidth = 0 + local x = self.x + local y = self.y + local prevtextwidth = 0 + local prevtextheight = 0 + local prevlargestheight = 0 + local largestwidth = 0 + local largestheight = 0 + local initialwidth = 0 + local detectlinks = self.detectlinks + + for k, v in ipairs(textdata) do + local text = v.text + local color = v.color + if detectlinks then + if loveframes.utf8.len(text) > 7 and (loveframes.utf8.sub(text, 1, 7) == "http://" or loveframes.utf8.sub(text, 1, 8) == "https://") then + v.link = true + end + end + if type(text) == "string" then + self.text = self.text .. text + local width = v.font:getWidth(text) + local height = v.font:getHeight("a") + if height > largestheight then + largestheight = height + prevlargestheight = height + end + totalwidth = totalwidth + width + if maxw > 0 then + if k ~= 1 then + if string.byte(text) == 10 then + twidth = 0 + drawx = 0 + width = 0 + drawy = drawy + largestheight + largestheight = 0 + text = "" + lines = lines + 1 + elseif (twidth + width) > maxw then + twidth = 0 + width + drawx = 0 + drawy = drawy + largestheight + largestheight = 0 + lines = lines + 1 + else + twidth = twidth + width + drawx = drawx + prevtextwidth + end + else + twidth = twidth + width + end + prevtextwidth = width + prevtextheight = height + v.x = drawx + v.y = drawy + else + if string.byte(text) == 10 then + twidth = 0 + drawx = 0 + width = 0 + drawy = drawy + largestheight + largestheight = 0 + text = "" + lines = lines + 1 + if lastwidth < textwidth then + lastwidth = textwidth + end + if largestwidth < textwidth then + largestwidth = textwidth + end + textwidth = 0 + else + drawx = drawx + prevtextwidth + textwidth = textwidth + width + end + prevtextwidth = width + prevtextheight = height + v.x = drawx + v.y = drawy + end + end + end + + self.lines = lines + + if lastwidth == 0 then + textwidth = totalwidth + end + + if textwidth < largestwidth then + textwidth = largestwidth + end + + if maxw > 0 then + self.width = maxw + else + self.width = textwidth + end + + self.height = drawy + prevlargestheight + return self + +end + +--[[--------------------------------------------------------- + - func: GetText() + - desc: gets the object's text +--]]--------------------------------------------------------- +function newobject:GetText() + + return self.text + +end + +--[[--------------------------------------------------------- + - func: GetFormattedText() + - desc: gets the object's formatted text +--]]--------------------------------------------------------- +function newobject:GetFormattedText() + + return self.formattedtext + +end + +--[[--------------------------------------------------------- + - func: DrawText() + - desc: draws the object's text +--]]--------------------------------------------------------- +function newobject:DrawText() + + local textdata = self.formattedtext + local x = self.x + local y = self.y + local shadow = self.shadow + local shadowxoffset = self.shadowxoffset + local shadowyoffset = self.shadowyoffset + local shadowcolor = self.shadowcolor + local inlist, list = self:IsInList() + local printfunc = function(text, x, y) + love.graphics.print(text, math.floor(x + 0.5), math.floor(y + 0.5)) + end + + for k, v in ipairs(textdata) do + local textx = v.x + local texty = v.y + local text = v.text + local color = v.color + local font = v.font + local link = v.link + local theight = font:getHeight("a") + if inlist then + local listy = list.y + local listhieght = list.height + if (y + texty) <= (listy + listhieght) and y + ((texty + theight)) >= listy then + love.graphics.setFont(font) + if shadow then + love.graphics.setColor(unpack(shadowcolor)) + printfunc(text, x + textx + shadowxoffset, y + texty + shadowyoffset) + end + if link then + local linkcolor = v.linkcolor + local linkhovercolor = v.linkhovercolor + local hover = v.hover + if hover then + love.graphics.setColor(linkhovercolor) + else + love.graphics.setColor(linkcolor) + end + else + love.graphics.setColor(unpack(color)) + end + printfunc(text, x + textx, y + texty) + end + else + love.graphics.setFont(font) + if shadow then + love.graphics.setColor(unpack(shadowcolor)) + printfunc(text, x + textx + shadowxoffset, y + texty + shadowyoffset) + end + if link then + local linkcolor = v.linkcolor + local linkhovercolor = v.linkhovercolor + local hover = v.hover + if hover then + love.graphics.setColor(linkhovercolor) + else + love.graphics.setColor(linkcolor) + end + else + love.graphics.setColor(unpack(color)) + end + printfunc(text, x + textx, y + texty) + end + end + + return self +end + +--[[--------------------------------------------------------- + - func: SetMaxWidth(width) + - desc: sets the object's maximum width +--]]--------------------------------------------------------- +function newobject:SetMaxWidth(width) + + local original = self.original + + self.maxw = width + self:SetText(original) + + return self + +end + +--[[--------------------------------------------------------- + - func: GetMaxWidth() + - desc: gets the object's maximum width +--]]--------------------------------------------------------- +function newobject:GetMaxWidth() + + return self.maxw + +end + +--[[--------------------------------------------------------- + - func: SetWidth(width, relative) + - desc: sets the object's width +--]]--------------------------------------------------------- +function newobject:SetWidth(width, relative) + + if relative then + self:SetMaxWidth(self.parent.width * width) + else + self:SetMaxWidth(width) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetHeight() + - desc: sets the object's height +--]]--------------------------------------------------------- +function newobject:SetHeight(height) + + return + +end + +--[[--------------------------------------------------------- + - func: SetSize(width, height, relative) + - desc: sets the object's size +--]]--------------------------------------------------------- +function newobject:SetSize(width, height, relative) + + if relative then + self:SetMaxWidth(self.parent.width * width) + else + self:SetMaxWidth(width) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetFont(font) + - desc: sets the object's font + - note: font argument must be a font object +--]]--------------------------------------------------------- +function newobject:SetFont(font) + + local original = self.original + + self.font = font + + if original then + self:SetText(original) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetFont() + - desc: gets the object's font +--]]--------------------------------------------------------- +function newobject:GetFont() + + return self.font + +end + +--[[--------------------------------------------------------- + - func: GetLines() + - desc: gets the number of lines the object's text uses +--]]--------------------------------------------------------- +function newobject:GetLines() + + return self.lines + +end + +--[[--------------------------------------------------------- + - func: SetIgnoreNewlines(bool) + - desc: sets whether the object should ignore \n or not +--]]--------------------------------------------------------- +function newobject:SetIgnoreNewlines(bool) + + self.ignorenewlines = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetIgnoreNewlines() + - desc: gets whether the object should ignore \n or not +--]]--------------------------------------------------------- +function newobject:GetIgnoreNewlines() + + return self.ignorenewlines + +end + +--[[--------------------------------------------------------- + - func: SetShadow(bool) + - desc: sets whether or not the object should draw a + shadow behind its text +--]]--------------------------------------------------------- +function newobject:SetShadow(bool) + + self.shadow = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetShadow() + - desc: gets whether or not the object should draw a + shadow behind its text +--]]--------------------------------------------------------- +function newobject:GetShadow() + + return self.shadow + +end + +--[[--------------------------------------------------------- + - func: SetShadowOffsets(offsetx, offsety) + - desc: sets the object's x and y shadow offsets +--]]--------------------------------------------------------- +function newobject:SetShadowOffsets(offsetx, offsety) + + self.shadowxoffset = offsetx + self.shadowyoffset = offsety + + return self + +end + +--[[--------------------------------------------------------- + - func: GetShadowOffsets() + - desc: gets the object's x and y shadow offsets +--]]--------------------------------------------------------- +function newobject:GetShadowOffsets() + + return self.shadowxoffset, self.shadowyoffset + +end + +--[[--------------------------------------------------------- + - func: SetShadowColor(r, g, b, a) + - desc: sets the object's shadow color +--]]--------------------------------------------------------- +function newobject:SetShadowColor(r, g, b, a) + + self.shadowcolor = {r, g, b, a} + return self + +end + +--[[--------------------------------------------------------- + - func: GetShadowColor() + - desc: gets the object's shadow color +--]]--------------------------------------------------------- +function newobject:GetShadowColor() + + return self.shadowcolor + +end + +--[[--------------------------------------------------------- + - func: SetDefaultColor(r, g, b, a) + - desc: sets the object's default text color +--]]--------------------------------------------------------- +function newobject:SetDefaultColor(r, g, b, a) + + self.defaultcolor = {r, g, b, a} + return self + +end + +--[[--------------------------------------------------------- + - func: GetDefaultColor() + - desc: gets whether or not the object should draw a + shadow behind its text +--]]--------------------------------------------------------- +function newobject:GetDefaultColor() + + return self.defaultcolor + +end + +--[[--------------------------------------------------------- + - func: SetLinksEnabled(enabled) + - desc: sets whether or not the object should process + urls into clickable links +--]]--------------------------------------------------------- +function newobject:SetLinksEnabled(enabled) + + self.linksenabled = enabled + return self + +end + +--[[--------------------------------------------------------- + - func: GetLinksEnabled() + - desc: gets whether or not the object should process + urls into clickable links +--]]--------------------------------------------------------- +function newobject:GetLinksEnabled() + + return self.linksenabled + +end + +--[[--------------------------------------------------------- + - func: SetDetectLinks(detect) + - desc: sets whether or not the object should detect + links when processing new text +--]]--------------------------------------------------------- +function newobject:SetDetectLinks(detect) + + self.detectlinks = detect + return self + +end + +--[[--------------------------------------------------------- + - func: GetDetectLinks() + - desc: gets whether or not the object should detect + links when processing new text +--]]--------------------------------------------------------- +function newobject:GetDetectLinks() + + return self.detectlinks + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/textinput.lua b/loveframes/objects/textinput.lua new file mode 100644 index 0000000..d6694ca --- /dev/null +++ b/loveframes/objects/textinput.lua @@ -0,0 +1,2136 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +local utf8 = require("utf8") + +return function(loveframes) +---------- module start ---------- + +-- textinput object +local newobject = loveframes.NewObject("textinput", "loveframes_object_textinput", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "textinput" + self.keydown = "none" + self.tabreplacement = " " + self.maskchar = "*" + self.font = loveframes.basicfont + self.width = 200 + self.height = 25 + self.delay = 0 + self.repeatdelay = 0.80 + self.repeatrate = 0.02 + self.offsetx = 0 + self.offsety = 0 + self.indincatortime = 0 + self.indicatornum = 0 + self.indicatorx = 0 + self.indicatory = 0 + self.textx = 0 + self.texty = 0 + self.textoffsetx = 5 + self.textoffsety = 5 + self.unicode = 0 + self.limit = 0 + self.line = 1 + self.itemwidth = 0 + self.itemheight = 0 + self.extrawidth = 0 + self.extraheight = 0 + self.rightpadding = 0 + self.bottompadding = 0 + self.lastclicktime = 0 + self.maxx = 0 + self.buttonscrollamount = 0.10 + self.mousewheelscrollamount = 5 + self.usable = {} + self.unusable = {} + self.lines = {""} + self.placeholder = "" + self.internals = {} + self.showindicator = true + self.focus = false + self.multiline = false + self.vbar = false + self.hbar = false + self.alltextselected = false + self.linenumbers = true + self.linenumberspanel = false + self.editable = true + self.internal = false + self.autoscroll = false + self.masked = false + self.trackindicator = true + self.OnEnter = nil + self.OnTextChanged = nil + self.OnFocusGained = nil + self.OnFocusLost = nil + self.OnCopy = nil + self.OnPaste = nil + + self:SetDrawFunc() +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 + + -- check to see if the object is being hovered over + self:CheckHover() + + local time = love.timer.getTime() + local keydown = self.keydown + local parent = self.parent + local base = loveframes.base + local update = self.Update + local font = self.font + local theight = font:getHeight() + local delay = self.delay + local lines = self.lines + local numlines = #lines + local multiline = self.multiline + local width = self.width + local height = self.height + local vbar = self.vbar + local hbar = self.hbar + local inputobject = loveframes.inputobject + local internals = self.internals + local repeatrate = self.repeatrate + local hover = self.hover + + -- move to parent if there is a parent + if parent ~= base then + local parentx = parent.x + local parenty = parent.y + local staticx = self.staticx + local staticy = self.staticy + self.x = parentx + staticx + self.y = parenty + staticy + end + + if inputobject ~= self then + self.focus = false + self.alltextselected = false + end + + self:PositionText() + self:UpdateIndicator() + + -- calculations for multiline mode + if multiline then + local twidth = 0 + local panel = self:GetLineNumbersPanel() + local textoffsetx = self.textoffsetx + local textoffsety = self.textoffsety + local linenumbers = self.linenumbers + local masked = self.masked + local maskchar = self.maskchar + -- get the longest line of text + for k, v in ipairs(lines) do + local linewidth = 0 + if masked then + linewidth = font:getWidth(loveframes.utf8.gsub(v, ".", maskchar)) + else + linewidth = font:getWidth(v) + end + if linewidth > twidth then + twidth = linewidth + end + end + -- item width calculation + if vbar then + self.itemwidth = twidth + 16 + textoffsetx * 2 + else + self.itemwidth = twidth + (textoffsetx * 2) + end + if panel then + local panelwidth = panel.width + self.itemwidth = self.itemwidth + panelwidth + textoffsetx + 5 + end + -- item height calculation + if hbar then + self.itemheight = theight * numlines + 16 + textoffsety * 2 + else + self.itemheight = theight * numlines + end + -- extra width and height calculations + self.extrawidth = self.itemwidth - width + self.extraheight = self.itemheight - height + local itemwidth = self.itemwidth + local itemheight = self.itemheight + if itemheight > height then + if not vbar then + local scrollbody = loveframes.objects["scrollbody"]:new(self, "vertical") + scrollbody.internals[1].internals[1].autoscroll = self.autoscroll + table.insert(self.internals, scrollbody) + self.vbar = true + if hbar then + local vbody = self:GetVerticalScrollBody() + local vbodyheight = vbody:GetHeight() - 15 + local hbody = self:GetHorizontalScrollBody() + local hbodywidth = hbody:GetWidth() - 15 + vbody:SetHeight(vbodyheight) + hbody:SetWidth(hbodywidth) + end + end + else + if vbar then + self:GetVerticalScrollBody():Remove() + self.vbar = false + self.offsety = 0 + if self.hbar then + local hbody = self:GetHorizontalScrollBody() + local hbodywidth = hbody:GetWidth() - 15 + hbody:SetWidth(hbodywidth) + end + end + end + + if itemwidth > width then + if not hbar then + local scrollbody = loveframes.objects["scrollbody"]:new(self, "horizontal") + scrollbody.internals[1].internals[1].autoscroll = self.autoscroll + table.insert(self.internals, scrollbody) + self.hbar = true + if self.vbar then + local vbody = self:GetVerticalScrollBody() + local hbody = self:GetHorizontalScrollBody() + vbody:SetHeight(vbody:GetHeight() - 15) + hbody:SetWidth(hbody:GetWidth() - 15) + end + end + else + if hbar then + self:GetHorizontalScrollBody():Remove() + self.hbar = false + self.offsetx = 0 + if vbar then + local vbody = self:GetVerticalScrollBody() + if vbody then + vbody:SetHeight(vbody:GetHeight() + 15) + end + end + end + end + if linenumbers then + if not self.linenumberspanel then + local linenumberspanel = loveframes.objects["linenumberspanel"]:new(self) + table.insert(internals, linenumberspanel) + self.linenumberspanel = true + end + else + if self.linenumberspanel then + table.remove(internals, 1) + self.linenumberspanel = false + end + end + end + + for k, v in ipairs(internals) do + v:update(dt) + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: draw() + - desc: draws the object +--]]--------------------------------------------------------- +function newobject:draw() + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + local x = self.x + local y = self.y + local width = self.width + local height = self.height + local stencilfunc = function() love.graphics.rectangle("fill", x, y, width, height) end + local vbar = self.vbar + local hbar = self.hbar + + -- set the object's draw order + self:SetDrawOrder() + + if vbar and hbar then + stencilfunc = function() love.graphics.rectangle("fill", x, y, width - 16, height - 16) end + end + + love.graphics.stencil(stencilfunc) + love.graphics.setStencilTest("greater", 0) + + local drawfunc = self.Draw or self.drawfunc + if drawfunc then + drawfunc(self) + end + + love.graphics.setStencilTest() + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + v:draw() + end + end + + drawfunc = self.DrawOver or self.drawoverfunc + if drawfunc then + 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 + + local hover = self.hover + local internals = self.internals + local alt = love.keyboard.isDown("lalt", "ralt") + local vbar = self.vbar + local hbar = self.hbar + local scrollamount = self.mousewheelscrollamount + local focus = self.focus + local alltextselected = self.alltextselected + local onfocusgained = self.OnFocusGained + local onfocuslost = self.OnFocusLost + local time = love.timer.getTime() + local inputobject = loveframes.inputobject + + if hover then + if button == 1 then + if inputobject ~= self then + loveframes.inputobject = self + end + if not alltextselected then + local lastclicktime = self.lastclicktime + if (time > lastclicktime) and time < (lastclicktime + 0.25) then + if not self.multiline then + if self.lines[1] ~= "" then + self.alltextselected = true + end + else + self.alltextselected = true + end + end + else + self.alltextselected = false + end + self.focus = true + self.lastclicktime = time + self:GetTextCollisions(x, y) + if onfocusgained and not focus then + onfocusgained(self) + end + local baseparent = self:GetBaseParent() + if baseparent and baseparent.type == "frame" then + baseparent:MakeTop() + end + elseif button == "wu" then + if not alt then + if focus then + self.line = math.max(self.line - scrollamount, 1) + elseif vbar then + local vbar = self:GetVerticalScrollBody().internals[1].internals[1] + vbar:Scroll(-scrollamount) + end + else + if focus then + self:MoveIndicator(-scrollamount) + elseif hbar then + local hbar = self:GetHorizontalScrollBody().internals[1].internals[1] + hbar:Scroll(-scrollamount) + end + end + elseif button == "wd" then + if not alt then + if focus then + self.line = math.min(self.line + scrollamount, #self.lines) + elseif vbar then + local vbar = self:GetVerticalScrollBody().internals[1].internals[1] + vbar:Scroll(scrollamount) + end + else + if focus then + self:MoveIndicator(scrollamount) + elseif hbar then + local hbar = self:GetHorizontalScrollBody().internals[1].internals[1] + hbar:Scroll(scrollamount) + end + end + end + else + if inputobject == self then + loveframes.inputobject = false + if onfocuslost then + onfocuslost(self) + end + end + end + + for k, v in ipairs(internals) do + v:mousepressed(x, y, button) + 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: keypressed(key, isrepeat) + - desc: called when the player presses a key +--]]--------------------------------------------------------- +function newobject:keypressed(key, isrepeat) + + 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 time = love.timer.getTime() + local focus = self.focus + local repeatdelay = self.repeatdelay + local alltextselected = self.alltextselected + local editable = self.editable + + self.delay = time + repeatdelay + self.keydown = key + + if (loveframes.IsCtrlDown()) and focus then + if key == "a" then + if not self.multiline then + if self.lines[1] ~= "" then + self.alltextselected = true + end + else + self.alltextselected = true + end + elseif key == "c" and alltextselected then + local text = self:GetText() + local oncopy = self.OnCopy + love.system.setClipboardText(text) + if oncopy then + oncopy(self, text) + end + elseif key == "x" and alltextselected and editable then + local text = self:GetText() + local oncut = self.OnCut + love.system.setClipboardText(text) + if oncut then + oncut(self, text) + else + self:SetText("") + end + elseif key == "v" and editable then + self:Paste() + else + self:RunKey(key, false) + end + else + self:RunKey(key, false) + end + +end + +--[[--------------------------------------------------------- + - func: keyreleased(key) + - desc: called when the player releases a key +--]]--------------------------------------------------------- +function newobject:keyreleased(key) + + local state = loveframes.state + local selfstate = self.state + + if state ~= selfstate then + return + end + + local visible = self.visible + if not visible then + return + end + + self.keydown = "none" + +end + +--[[--------------------------------------------------------- + - func: textinput(text) + - desc: called when the inputs text +--]]--------------------------------------------------------- +function newobject:textinput(text) + + if loveframes.utf8.find(text, "kp.") then + text = loveframes.utf8.gsub(text, "kp", "") + end + + self:RunKey(text, true) + +end + +--[[--------------------------------------------------------- + - func: RunKey(key, istext) + - desc: runs a key event on the object +--]]--------------------------------------------------------- +function newobject:RunKey(key, istext) + + local visible = self.visible + local focus = self.focus + + if not visible then + return + end + + if not focus then + return + end + + local x = self.x + local offsetx = self.offsetx + local lines = self.lines + local line = self.line + local numlines = #lines + local curline = lines[line] + local text = curline + local ckey = "" + local font = self.font + local swidth = self.width + local textoffsetx = self.textoffsetx + local indicatornum = self.indicatornum + local multiline = self.multiline + local alltextselected = self.alltextselected + local editable = self.editable + local initialtext = self:GetText() + local ontextchanged = self.OnTextChanged + local onenter = self.OnEnter + + if not istext then + if key == "left" then + indicatornum = self.indicatornum + if not multiline then + self:MoveIndicator(-1) + local indicatorx = self.indicatorx + if indicatorx <= x and indicatornum ~= 0 then + local width = font:getWidth(loveframes.utf8.sub(text, indicatornum, indicatornum + 1)) + self.offsetx = offsetx - width + elseif indicatornum == 0 and offsetx ~= 0 then + self.offsetx = 0 + end + else + if indicatornum == 0 then + if line > 1 then + self.line = line - 1 + local numchars = utf8.len(lines[self.line]) + self:MoveIndicator(numchars) + end + else + self:MoveIndicator(-1) + end + end + if alltextselected then + self.line = 1 + self.indicatornum = 0 + self.alltextselected = false + end + return + elseif key == "right" then + indicatornum = self.indicatornum + if not multiline then + self:MoveIndicator(1) + local indicatorx = self.indicatorx + if indicatorx >= (x + swidth) and indicatornum ~= utf8.len(text) then + local width = font:getWidth(loveframes.utf8.sub(text, indicatornum, indicatornum)) + self.offsetx = offsetx + width + elseif indicatornum == utf8.len(text) and offsetx ~= ((font:getWidth(text)) - swidth + 10) and font:getWidth(text) + textoffsetx > swidth then + self.offsetx = ((font:getWidth(text)) - swidth + 10) + end + else + if indicatornum == utf8.len(text) then + if line < numlines then + self.line = line + 1 + self:MoveIndicator(0, true) + end + else + self:MoveIndicator(1) + end + end + if alltextselected then + self.line = #lines + self.indicatornum = utf8.len(lines[#lines]) + self.alltextselected = false + end + return + elseif key == "up" then + if multiline then + if line > 1 then + self.line = line - 1 + if indicatornum > utf8.len(lines[self.line]) then + self.indicatornum = utf8.len(lines[self.line]) + end + end + end + return + elseif key == "down" then + if multiline then + if line < #lines then + self.line = line + 1 + if indicatornum > utf8.len(lines[self.line]) then + self.indicatornum = utf8.len(lines[self.line]) + end + end + end + return + end + + if not editable then + return + end + + -- key input checking system + if key == "backspace" then + ckey = key + if alltextselected then + self:Clear() + self.alltextselected = false + indicatornum = self.indicatornum + else + if text ~= "" and indicatornum ~= 0 then + text = self:RemoveFromText(indicatornum) + self:MoveIndicator(-1) + lines[line] = text + end + if multiline then + if line > 1 and indicatornum == 0 then + local newindicatornum = 0 + local oldtext = lines[line] + table.remove(lines, line) + self.line = line - 1 + if utf8.len(oldtext) > 0 then + newindicatornum = utf8.len(lines[self.line]) + lines[self.line] = lines[self.line] .. oldtext + self:MoveIndicator(newindicatornum) + else + self:MoveIndicator(utf8.len(lines[self.line])) + end + end + end + local masked = self.masked + local cwidth = 0 + if masked then + local maskchar = self.maskchar + cwidth = font:getWidth(loveframes.utf8.gsub(text, ".", maskchar)) + else + cwidth = font:getWidth(text) + end + if self.offsetx > 0 then + self.offsetx = self.offsetx - cwidth + elseif self.offsetx < 0 then + self.offsetx = 0 + end + end + elseif key == "delete" then + if not editable then + return + end + ckey = key + if alltextselected then + self:Clear() + self.alltextselected = false + indicatornum = self.indicatornum + else + if text ~= "" and indicatornum < utf8.len(text) then + text = self:RemoveFromText(indicatornum + 1) + lines[line] = text + elseif indicatornum == utf8.len(text) and line < #lines then + local oldtext = lines[line + 1] + if utf8.len(oldtext) > 0 then + -- FIXME: newindicatornum here??? + -- newindicatornum = utf8.len(lines[self.line]) + lines[self.line] = lines[self.line] .. oldtext + end + table.remove(lines, line + 1) + end + end + elseif key == "return" or key == "kpenter" then + ckey = key + -- call onenter if it exists + if onenter then + onenter(self, text) + end + -- newline calculations for multiline mode + if multiline then + if alltextselected then + self.alltextselected = false + self:Clear() + indicatornum = self.indicatornum + line = self.line + end + local newtext = "" + if indicatornum == 0 then + newtext = self.lines[line] + self.lines[line] = "" + elseif indicatornum > 0 and indicatornum < utf8.len(self.lines[line]) then + newtext = loveframes.utf8.sub(self.lines[line], indicatornum + 1, utf8.len(self.lines[line])) + self.lines[line] = loveframes.utf8.sub(self.lines[line], 1, indicatornum) + end + if line ~= #lines then + table.insert(self.lines, line + 1, newtext) + self.line = line + 1 + else + table.insert(self.lines, newtext) + self.line = line + 1 + end + self.indicatornum = 0 + local hbody = self:GetHorizontalScrollBody() + if hbody then + hbody:GetScrollBar():Scroll(-hbody:GetWidth()) + end + end + elseif key == "tab" then + if alltextselected then + return + end + ckey = key + self.lines[self.line] = self:AddIntoText(self.tabreplacement, self.indicatornum) + self:MoveIndicator(utf8.len(self.tabreplacement)) + end + else + if not editable then + return + end + -- do not continue if the text limit has been reached or exceeded + if utf8.len(text) >= self.limit and self.limit ~= 0 and not alltextselected then + return + end + -- check for unusable characters + if #self.usable > 0 then + local found = false + for k, v in ipairs(self.usable) do + if v == key then + found = true + end + end + if not found then + return + end + end + -- check for usable characters + if #self.unusable > 0 then + local found = false + for k, v in ipairs(self.unusable) do + if v == key then + found = true + end + end + if found then + return + end + end + if alltextselected then + self.alltextselected = false + self:Clear() + indicatornum = self.indicatornum + text = "" + lines = self.lines + line = self.line + end + if indicatornum ~= 0 and indicatornum ~= utf8.len(text) then + text = self:AddIntoText(key, indicatornum) + lines[line] = text + self:MoveIndicator(1) + elseif indicatornum == utf8.len(text) then + text = text .. key + lines[line] = text + self:MoveIndicator(1) + elseif indicatornum == 0 then + text = self:AddIntoText(key, indicatornum) + lines[line] = text + self:MoveIndicator(1) + end + lines = self.lines + line = self.line + curline = lines[line] + text = curline + if not multiline then + local masked = self.masked + local twidth = 0 + local cwidth = 0 + if masked then + local maskchar = self.maskchar + twidth = font:getWidth(loveframes.utf8.gsub(text, ".", maskchar)) + cwidth = font:getWidth(loveframes.utf8.gsub(key, ".", maskchar)) + else + twidth = font:getWidth(text) + cwidth = font:getWidth(key) + end + -- swidth - 1 is for the "-" character + if (twidth + textoffsetx) >= (swidth - 1) then + self.offsetx = self.offsetx + cwidth + end + end + end + + local curtext = self:GetText() + if ontextchanged and initialtext ~= curtext then + ontextchanged(self, key) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: MoveIndicator(num, exact) + - desc: moves the object's indicator +--]]--------------------------------------------------------- +function newobject:MoveIndicator(num, exact) + + local lines = self.lines + local line = self.line + local curline = lines[line] + local text = curline + local indicatornum = self.indicatornum + + if not exact then + self.indicatornum = indicatornum + num + else + self.indicatornum = num + end + + if self.indicatornum > utf8.len(text) then + self.indicatornum = utf8.len(text) + elseif self.indicatornum < 0 then + self.indicatornum = 0 + end + + self.showindicator = true + self:UpdateIndicator() + + return self + +end + +--[[--------------------------------------------------------- + - func: UpdateIndicator() + - desc: updates the object's text insertion position + indicator +--]]--------------------------------------------------------- +function newobject:UpdateIndicator() + + local time = love.timer.getTime() + local indincatortime = self.indincatortime + local indicatornum = self.indicatornum + local lines = self.lines + local line = self.line + local curline = lines[line] + local text = curline + local font = self.font + local theight = font:getHeight() + local offsetx = self.offsetx + local multiline = self.multiline + local showindicator = self.showindicator + local alltextselected = self.alltextselected + local textx = self.textx + local texty = self.texty + local masked = self.masked + + if indincatortime < time then + if showindicator then + self.showindicator = false + else + self.showindicator = true + end + self.indincatortime = time + 0.50 + end + + if alltextselected then + self.showindicator = false + else + if love.keyboard.isDown("up", "down", "left", "right") then + self.showindicator = true + end + end + + local width = 0 + if masked then + width = font:getWidth(string.rep(self.maskchar,indicatornum)) + else + if indicatornum == 0 then + width = 0 + elseif indicatornum >= utf8.len(text) then + width = font:getWidth(text) + else + width = font:getWidth(loveframes.utf8.sub(text, 1, indicatornum)) + end + end + + if multiline then + self.indicatorx = textx + width + self.indicatory = texty + theight * line - theight + else + self.indicatorx = textx + width + self.indicatory = texty + end + + -- indicator should be visible, so correcting scrolls + if self.focus and self.trackindicator then + local indicatorRelativeX = width + self.textoffsetx - self.offsetx + local leftlimit, rightlimit = 1, self:GetWidth() - 1 + if self.linenumberspanel then + rightlimit = rightlimit - self:GetLineNumbersPanel().width + end + if self.vbar then + rightlimit = rightlimit - self:GetVerticalScrollBody().width + end + if not (indicatorRelativeX > leftlimit and indicatorRelativeX < rightlimit) then + local hbody = self:GetHorizontalScrollBody() + if hbody then + local twidth = 0 + for k, v in ipairs(lines) do + local linewidth = 0 + if self.masked then + linewidth = font:getWidth(loveframes.utf8.gsub(v, ".", self.maskchar)) + else + linewidth = font:getWidth(v) + end + if linewidth > twidth then + twidth = linewidth + end + end + local correction = self:GetWidth() / 8 + if indicatorRelativeX < leftlimit then + correction = correction * -1 + end + hbody:GetScrollBar():ScrollTo((width + correction) / twidth) + end + end + local indicatorRelativeY = (line - 1) * theight + self.textoffsety - self.offsety + local uplimit, downlimit = theight, self:GetHeight() - theight + if self.hbar then + downlimit = downlimit - self:GetHorizontalScrollBody().height + end + if not (indicatorRelativeY > uplimit and indicatorRelativeY < downlimit) then + local vbody = self:GetVerticalScrollBody() + if vbody then + local correction = self:GetHeight() / 8 / theight + if indicatorRelativeY < uplimit then + correction = correction * -1 + end + vbody:GetScrollBar():ScrollTo((line - 1 + correction)/#lines) + end + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: AddIntoText(t, p) + - desc: adds text into the object's text at a given + position +--]]--------------------------------------------------------- +function newobject:AddIntoText(t, p) + + local lines = self.lines + local line = self.line + local curline = lines[line] + local text = curline + local part1 = loveframes.utf8.sub(text, 1, p) + local part2 = loveframes.utf8.sub(text, p + 1) + local new = part1 .. t .. part2 + + return new + +end + +--[[--------------------------------------------------------- + - func: RemoveFromText(p) + - desc: removes text from the object's text a given + position +--]]--------------------------------------------------------- +function newobject:RemoveFromText(p) + + local lines = self.lines + local line = self.line + local curline = lines[line] + local text = curline + local part1 = loveframes.utf8.sub(text, 1, p - 1) + local part2 = loveframes.utf8.sub(text, p + 1) + local new = part1 .. part2 + return new + +end + +--[[--------------------------------------------------------- + - func: GetTextCollisions(x, y) + - desc: gets text collisions with the mouse +--]]--------------------------------------------------------- +function newobject:GetTextCollisions(x, y) + + local font = self.font + local lines = self.lines + local numlines = #lines + local line = self.line + local curline = lines[line] + local text = curline + local xpos = 0 + local line = 0 + local vbar = self.vbar + local hbar = self.hbar + local multiline = self.multiline + local selfx = self.x + local selfy = self.y + local selfwidth = self.width + local masked = self.masked + + if multiline then + local theight = font:getHeight() + local liney = 0 + local selfcol + if vbar and not hbar then + selfcol = loveframes.BoundingBox(selfx, x, selfy, y, selfwidth - 16, 1, self.height, 1) + elseif hbar and not vbar then + selfcol = loveframes.BoundingBox(selfx, x, selfy, y, selfwidth, 1, self.height - 16, 1) + elseif not vbar and not hbar then + selfcol = loveframes.BoundingBox(selfx, x, selfy, y, selfwidth, 1, self.height, 1) + elseif vbar and hbar then + selfcol = loveframes.BoundingBox(selfx, x, selfy, y, selfwidth - 16, 1, self.height - 16, 1) + end + if selfcol then + local offsety = self.offsety + local textoffsety = self.textoffsety + for i=1, numlines do + local linecol = loveframes.BoundingBox(selfx, x, (selfy - offsety) + textoffsety + (theight * i) - theight, y, self.width, 1, theight, 1) + if linecol then + liney = (selfy - offsety) + textoffsety + (theight * i) - theight + self.line = i + end + end + local line = self.line + local curline = lines[line] + for i=1, utf8.len(curline) do + local char = loveframes.utf8.sub(text, i, i) + local width = 0 + if masked then + local maskchar = self.maskchar + width = font:getWidth(maskchar) + else + width = font:getWidth(char) + end + local height = font:getHeight() + local tx = self.textx + xpos + local ty = self.texty + local col = loveframes.BoundingBox(tx, x, liney, y, width, 1, height, 1) + + xpos = xpos + width + + if col then + self:MoveIndicator(i - 1, true) + break + else + self.indicatornum = utf8.len(curline) + end + + if x < tx then + self:MoveIndicator(0, true) + end + + if x > (tx + width) then + self:MoveIndicator(utf8.len(curline), true) + end + end + + if utf8.len(curline) == 0 then + self.indicatornum = 0 + end + end + else + local i = 0 + for p, c in utf8.codes(text) do + i = i + 1 + local char = utf8.char(c) + local width = 0 + if masked then + local maskchar = self.maskchar + width = font:getWidth(maskchar) + else + width = font:getWidth(char) + end + local height = font:getHeight() + local tx = self.textx + xpos + local ty = self.texty + local col = loveframes.BoundingBox(tx, x, ty, y, width, 1, height, 1) + xpos = xpos + width + if col then + self:MoveIndicator(i - 1, true) + break + end + if x < tx then + self:MoveIndicator(0, true) + end + if x > (tx + width) then + self:MoveIndicator(utf8.len(text), true) + end + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: PositionText() + - desc: positions the object's text +--]]--------------------------------------------------------- +function newobject:PositionText() + + local multiline = self.multiline + local x = self.x + local y = self.y + local offsetx = self.offsetx + local offsety = self.offsety + local textoffsetx = self.textoffsetx + local textoffsety = self.textoffsety + local linenumberspanel = self.linenumberspanel + + if multiline then + if linenumberspanel then + local panel = self:GetLineNumbersPanel() + self.textx = ((x + panel.width) - offsetx) + textoffsetx + self.texty = (y - offsety) + textoffsety + else + self.textx = (x - offsetx) + textoffsetx + self.texty = (y - offsety) + textoffsety + end + else + self.textx = (x - offsetx) + textoffsetx + self.texty = (y - offsety) + textoffsety + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetTextOffsetX(num) + - desc: sets the object's text x offset +--]]--------------------------------------------------------- +function newobject:SetTextOffsetX(num) + + self.textoffsetx = num + return self + +end + +--[[--------------------------------------------------------- + - func: SetTextOffsetY(num) + - desc: sets the object's text y offset +--]]--------------------------------------------------------- +function newobject:SetTextOffsetY(num) + + self.textoffsety = num + return self + +end + +--[[--------------------------------------------------------- + - func: SetFont(font) + - desc: sets the object's font +--]]--------------------------------------------------------- +function newobject:SetFont(font) + + self.font = font + return self + +end + +--[[--------------------------------------------------------- + - func: GetFont() + - desc: gets the object's font +--]]--------------------------------------------------------- +function newobject:GetFont() + + return self.font + +end + +--[[--------------------------------------------------------- + - func: SetFocus(focus) + - desc: sets the object's focus +--]]--------------------------------------------------------- +function newobject:SetFocus(focus) + + local inputobject = loveframes.inputobject + local onfocusgained = self.OnFocusGained + local onfocuslost = self.OnFocusLost + + self.focus = focus + + if focus then + loveframes.inputobject = self + if onfocusgained then + onfocusgained(self) + end + else + if inputobject == self then + loveframes.inputobject = false + end + if onfocuslost then + onfocuslost(self) + end + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetFocus() + - desc: gets the object's focus +--]]--------------------------------------------------------- +function newobject:GetFocus() + + return self.focus + +end + +--[[--------------------------------------------------------- + - func: GetIndicatorVisibility() + - desc: gets the object's indicator visibility +--]]--------------------------------------------------------- +function newobject:GetIndicatorVisibility() + + return self.showindicator + +end + +--[[--------------------------------------------------------- + - func: SetLimit(limit) + - desc: sets the object's text limit +--]]--------------------------------------------------------- +function newobject:SetLimit(limit) + + self.limit = limit + return self + +end + +--[[--------------------------------------------------------- + - func: SetUsable(usable) + - desc: sets what characters can be used for the + object's text +--]]--------------------------------------------------------- +function newobject:SetUsable(usable) + + self.usable = usable + return self + +end + +--[[--------------------------------------------------------- + - func: GetUsable() + - desc: gets what characters can be used for the + object's text +--]]--------------------------------------------------------- +function newobject:GetUsable() + + return self.usable + +end + +--[[--------------------------------------------------------- + - func: SetUnusable(unusable) + - desc: sets what characters can not be used for the + object's text +--]]--------------------------------------------------------- +function newobject:SetUnusable(unusable) + + self.unusable = unusable + return self + +end + +--[[--------------------------------------------------------- + - func: GetUnusable() + - desc: gets what characters can not be used for the + object's text +--]]--------------------------------------------------------- +function newobject:GetUnusable() + + return self.unusable + +end + +--[[--------------------------------------------------------- + - func: Clear() + - desc: clears the object's text +--]]--------------------------------------------------------- +function newobject:Clear() + + self.lines = {""} + self.line = 1 + self.offsetx = 0 + self.offsety = 0 + self.indicatornum = 0 + + return self + +end + +--[[--------------------------------------------------------- + - func: SetText(text) + - desc: sets the object's text +--]]--------------------------------------------------------- +function newobject:SetText(text) + + local tabreplacement = self.tabreplacement + local multiline = self.multiline + + text = tostring(text) + text = loveframes.utf8.gsub(text, string.char(9), tabreplacement) + text = loveframes.utf8.gsub(text, string.char(13), "") + + if multiline then + text = loveframes.utf8.gsub(text, string.char(92) .. string.char(110), string.char(10)) + local t = loveframes.SplitString(text, string.char(10)) + if #t > 0 then + self.lines = t + else + self.lines = {""} + end + self.line = #self.lines + self.indicatornum = utf8.len(self.lines[#self.lines]) + else + text = loveframes.utf8.gsub(text, string.char(92) .. string.char(110), "") + text = loveframes.utf8.gsub(text, string.char(10), "") + self.lines = {text} + self.line = 1 + self.indicatornum = utf8.len(text) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetText() + - desc: gets the object's text +--]]--------------------------------------------------------- +function newobject:GetText() + + local multiline = self.multiline + local lines = self.lines + local text = "" + + if multiline then + for k, v in ipairs(lines) do + text = text .. v + if k ~= #lines then + text = text .. "\n" + end + end + else + text = lines[1] + end + + return text + +end + +--[[--------------------------------------------------------- + - func: SetMultiline(bool) + - desc: enables or disables allowing multiple lines for + text entry +--]]--------------------------------------------------------- +function newobject:SetMultiline(bool) + + local text = "" + local lines = self.lines + + self.multiline = bool + + if bool then + self:Clear() + else + for k, v in ipairs(lines) do + text = text .. v + end + self:SetText(text) + self.internals = {} + self.vbar = false + self.hbar = false + self.linenumberspanel = false + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetMultiLine() + - desc: gets whether or not the object is using multiple + lines +--]]--------------------------------------------------------- +function newobject:GetMultiLine() + + return self.multiline + +end + +--[[--------------------------------------------------------- + - func: GetVerticalScrollBody() + - desc: gets the object's vertical scroll body +--]]--------------------------------------------------------- +function newobject:GetVerticalScrollBody() + + local vbar = self.vbar + local internals = self.internals + local item = false + + if vbar then + for k, v in ipairs(internals) do + if v.type == "scrollbody" and v.bartype == "vertical" then + item = v + end + end + end + + return item + +end + +--[[--------------------------------------------------------- + - func: GetHorizontalScrollBody() + - desc: gets the object's horizontal scroll body +--]]--------------------------------------------------------- +function newobject:GetHorizontalScrollBody() + + local hbar = self.hbar + local internals = self.internals + local item = false + + if hbar then + for k, v in ipairs(internals) do + if v.type == "scrollbody" and v.bartype == "horizontal" then + item = v + end + end + end + + return item + +end + +--[[--------------------------------------------------------- + - func: HasVerticalScrollBar() + - desc: gets whether or not the object has a vertical + scroll bar +--]]--------------------------------------------------------- +function newobject:HasVerticalScrollBar() + + return self.vbar + +end + +--[[--------------------------------------------------------- + - func: HasHorizontalScrollBar() + - desc: gets whether or not the object has a horizontal + scroll bar +--]]--------------------------------------------------------- +function newobject:HasHorizontalScrollBar() + + return self.hbar + +end + +--[[--------------------------------------------------------- + - func: GetLineNumbersPanel() + - desc: gets the object's line numbers panel +--]]--------------------------------------------------------- +function newobject:GetLineNumbersPanel() + + local panel = self.linenumberspanel + local internals = self.internals + local item = false + + if panel then + for k, v in ipairs(internals) do + if v.type == "linenumberspanel" then + item = v + end + end + end + + return item + +end + +--[[--------------------------------------------------------- + - func: ShowLineNumbers(bool) + - desc: sets whether or not to show line numbers when + using multiple lines +--]]--------------------------------------------------------- +function newobject:ShowLineNumbers(bool) + + local multiline = self.multiline + + if multiline then + self.linenumbers = bool + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetTextX() + - desc: gets the object's text x +--]]--------------------------------------------------------- +function newobject:GetTextX() + + return self.textx + +end + +--[[--------------------------------------------------------- + - func: GetTextY() + - desc: gets the object's text y +--]]--------------------------------------------------------- +function newobject:GetTextY() + + return self.texty + +end + +--[[--------------------------------------------------------- + - func: IsAllTextSelected() + - desc: gets whether or not all of the object's text is + selected +--]]--------------------------------------------------------- +function newobject:IsAllTextSelected() + + return self.alltextselected + +end + +--[[--------------------------------------------------------- + - func: GetLines() + - desc: gets the object's lines +--]]--------------------------------------------------------- +function newobject:GetLines() + + return self.lines + +end + +--[[--------------------------------------------------------- + - func: GetOffsetX() + - desc: gets the object's x offset +--]]--------------------------------------------------------- +function newobject:GetOffsetX() + + return self.offsetx + +end + +--[[--------------------------------------------------------- + - func: GetOffsetY() + - desc: gets the object's y offset +--]]--------------------------------------------------------- +function newobject:GetOffsetY() + + return self.offsety + +end + +--[[--------------------------------------------------------- + - func: GetIndicatorX() + - desc: gets the object's indicator's xpos +--]]--------------------------------------------------------- +function newobject:GetIndicatorX() + + return self.indicatorx + +end + +--[[--------------------------------------------------------- + - func: GetIndicatorY() + - desc: gets the object's indicator's ypos +--]]--------------------------------------------------------- +function newobject:GetIndicatorY() + + return self.indicatory + +end + +--[[--------------------------------------------------------- + - func: GetLineNumbersEnabled() + - desc: gets whether line numbers are enabled on the + object or not +--]]--------------------------------------------------------- +function newobject:GetLineNumbersEnabled() + + return self.linenumbers + +end + +--[[--------------------------------------------------------- + - func: GetItemWidth() + - desc: gets the object's item width +--]]--------------------------------------------------------- +function newobject:GetItemWidth() + + return self.itemwidth + +end + +--[[--------------------------------------------------------- + - func: GetItemHeight() + - desc: gets the object's item height +--]]--------------------------------------------------------- +function newobject:GetItemHeight() + + return self.itemheight + +end + +--[[--------------------------------------------------------- + - func: SetTabReplacement(tabreplacement) + - desc: sets a string to replace tabs with +--]]--------------------------------------------------------- +function newobject:SetTabReplacement(tabreplacement) + + self.tabreplacement = tabreplacement + return self + +end + +--[[--------------------------------------------------------- + - func: GetTabReplacement() + - desc: gets the object's tab replacement +--]]--------------------------------------------------------- +function newobject:GetTabReplacement() + + return self.tabreplacement + +end + +--[[--------------------------------------------------------- + - func: SetEditable(bool) + - desc: sets whether or not the user can edit the + object's text +--]]--------------------------------------------------------- +function newobject:SetEditable(bool) + + self.editable = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetEditable + - desc: gets whether or not the user can edit the + object's text +--]]--------------------------------------------------------- +function newobject:GetEditable() + + return self.editable + +end + +--[[--------------------------------------------------------- + - func: SetButtonScrollAmount(speed) + - desc: sets the scroll amount of the object's scrollbar + buttons +--]]--------------------------------------------------------- +function newobject:SetButtonScrollAmount(amount) + + self.buttonscrollamount = amount + return self + +end + +--[[--------------------------------------------------------- + - func: GetButtonScrollAmount() + - desc: gets the scroll amount of the object's scrollbar + buttons +--]]--------------------------------------------------------- +function newobject:GetButtonScrollAmount() + + return self.buttonscrollamount + +end + +--[[--------------------------------------------------------- + - func: SetMouseWheelScrollAmount(amount) + - desc: sets the scroll amount of the mouse wheel +--]]--------------------------------------------------------- +function newobject:SetMouseWheelScrollAmount(amount) + + self.mousewheelscrollamount = amount + return self + +end + +--[[--------------------------------------------------------- + - func: GetMouseWheelScrollAmount() + - desc: gets the scroll amount of the mouse wheel +--]]--------------------------------------------------------- +function newobject:GetButtonScrollAmount() + + return self.mousewheelscrollamount + +end + +--[[--------------------------------------------------------- + - func: SetAutoScroll(bool) + - desc: sets whether or not the object should autoscroll + when in multiline mode +--]]--------------------------------------------------------- +function newobject:SetAutoScroll(bool) + + local internals = self.internals + + self.autoscroll = bool + + if internals[2] then + internals[2].internals[1].internals[1].autoscroll = bool + end + + return self + +end + +--[[--------------------------------------------------------- + - func: GetAutoScroll() + - desc: gets whether or not the object should autoscroll + when in multiline mode +--]]--------------------------------------------------------- +function newobject:GetAutoScroll() + + return self.autoscroll + +end + +--[[--------------------------------------------------------- + - func: SetRepeatDelay(delay) + - desc: sets the object's repeat delay +--]]--------------------------------------------------------- +function newobject:SetRepeatDelay(delay) + + self.repeatdelay = delay + return self + +end + +--[[--------------------------------------------------------- + - func: GetRepeatDelay() + - desc: gets the object's repeat delay +--]]--------------------------------------------------------- +function newobject:GetRepeatDelay() + + return self.repeatdelay + +end + +--[[--------------------------------------------------------- + - func: SetRepeatRate(rate) + - desc: sets the object's repeat rate +--]]--------------------------------------------------------- +function newobject:SetRepeatRate(rate) + + self.repeatrate = rate + return self + +end + +--[[--------------------------------------------------------- + - func: GetRepeatRate() + - desc: gets the object's repeat rate +--]]--------------------------------------------------------- +function newobject:GetRepeatRate() + + return self.repeatrate + +end + +--[[--------------------------------------------------------- + - func: SetValue(value) + - desc: sets the object's value (alias of SetText) +--]]--------------------------------------------------------- +function newobject:SetValue(value) + + self:SetText(value) + return self + +end + +--[[--------------------------------------------------------- + - func: GetValue() + - desc: gets the object's value (alias of GetText) +--]]--------------------------------------------------------- +function newobject:GetValue() + + return self:GetText() + +end + +--[[--------------------------------------------------------- + - func: SetVisible(bool) + - desc: sets the object's visibility +--]]--------------------------------------------------------- +function newobject:SetVisible(bool) + + self.visible = bool + + if not bool then + self.keydown = "none" + end + + return self + +end + +--[[--------------------------------------------------------- + - func: Copy() + - desc: copies the object's text to the user's clipboard +--]]--------------------------------------------------------- +function newobject:Copy() + + local text = self:GetText() + love.system.setClipboardText(text) + + return self + +end + +--[[--------------------------------------------------------- + - func: Paste() + - desc: pastes the current contents of the clipboard + into the object's text +--]]--------------------------------------------------------- +function newobject:Paste() + + local text = love.system.getClipboardText() + local usable = self.usable + local unusable = self.unusable + local limit = self.limit + local alltextselected = self.alltextselected + local onpaste = self.OnPaste + local ontextchanged = self.OnTextChanged + + if limit > 0 then + local curtext = self:GetText() + local curlength = utf8.len(curtext) + if curlength == limit then + return + else + local inputlimit = limit - curlength + if utf8.len(text) > inputlimit then + text = loveframes.utf8.sub(text, 1, inputlimit) + end + end + end + local charcheck = function(a) + if #usable > 0 then + if not loveframes.TableHasValue(usable, a) then + return "" + end + elseif #unusable > 0 then + if loveframes.TableHasValue(unusable, a) then + return "" + end + end + end + if #usable > 0 or #unusable > 0 then + text = loveframes.utf8.gsub(text, ".", charcheck) + end + if alltextselected then + self:SetText(text) + self.alltextselected = false + if ontextchanged then + ontextchanged(self, text) + end + else + local tabreplacement = self.tabreplacement + local indicatornum = self.indicatornum + local lines = self.lines + local multiline = self.multiline + if multiline then + local parts = loveframes.SplitString(text, string.char(10)) + local numparts = #parts + local oldlinedata = {} + local line = self.line + local first = loveframes.utf8.sub(lines[line], 0, indicatornum) + local last = loveframes.utf8.sub(lines[line], indicatornum + 1) + if numparts > 1 then + for i=1, numparts do + local part = loveframes.utf8.gsub(parts[i], string.char(13), "") + part = loveframes.utf8.gsub(part, string.char(9), " ") + if i ~= 1 then + table.insert(oldlinedata, lines[line]) + lines[line] = part + if i == numparts then + self.indicatornum = utf8.len(part) + lines[line] = lines[line] .. last + self.line = line + end + else + lines[line] = first .. part + end + line = line + 1 + end + for i=1, #oldlinedata do + lines[line] = oldlinedata[i] + line = line + 1 + end + if ontextchanged then + ontextchanged(self, text) + end + elseif numparts == 1 then + text = loveframes.utf8.gsub(text, string.char(10), " ") + text = loveframes.utf8.gsub(text, string.char(13), " ") + text = loveframes.utf8.gsub(text, string.char(9), tabreplacement) + local length = utf8.len(text) + local new = first .. text .. last + lines[line] = new + self.indicatornum = indicatornum + length + if ontextchanged then + ontextchanged(self, text) + end + end + else + text = loveframes.utf8.gsub(text, string.char(10), " ") + text = loveframes.utf8.gsub(text, string.char(13), " ") + text = loveframes.utf8.gsub(text, string.char(9), tabreplacement) + local length = utf8.len(text) + local linetext = lines[1] + local part1 = loveframes.utf8.sub(linetext, 1, indicatornum) + local part2 = loveframes.utf8.sub(linetext, indicatornum + 1) + local new = part1 .. text .. part2 + lines[1] = new + self.indicatornum = indicatornum + length + if ontextchanged then + ontextchanged(self, text) + end + end + end + if onpaste then + onpaste(self, text) + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SelectAll() + - desc: selects all of the object's text +--]]--------------------------------------------------------- +function newobject:SelectAll() + + if not self.multiline then + if self.lines[1] ~= "" then + self.alltextselected = true + end + else + self.alltextselected = true + end + + return self + +end + +--[[--------------------------------------------------------- + - func: DeselectAll() + - desc: deselects all of the object's text +--]]--------------------------------------------------------- +function newobject:DeselectAll() + + self.alltextselected = false + return self + +end + +--[[--------------------------------------------------------- + - func: SetMasked(masked) + - desc: sets whether or not the object is masked +--]]--------------------------------------------------------- +function newobject:SetMasked(masked) + + self.masked = masked + return self + +end + +--[[--------------------------------------------------------- + - func: GetMasked() + - desc: gets whether or not the object is masked +--]]--------------------------------------------------------- +function newobject:GetMasked() + + return self.masked + +end + +--[[--------------------------------------------------------- + - func: SetMaskChar(char) + - desc: sets the object's mask character +--]]--------------------------------------------------------- +function newobject:SetMaskChar(char) + + self.maskchar = char + return self + +end + +--[[--------------------------------------------------------- + - func: GetMaskChar() + - desc: gets the object's mask character +--]]--------------------------------------------------------- +function newobject:GetMaskChar() + + return self.maskchar + +end + +--[[--------------------------------------------------------- + - func: SetPlaceholderText(text) + - desc: sets the object's placeholder text +--]]--------------------------------------------------------- +function newobject:SetPlaceholderText(text) + + self.placeholder = text + return self + +end + +--[[--------------------------------------------------------- + - func: GetPlaceholderText() + - desc: gets the object's placeholder text +--]]--------------------------------------------------------- +function newobject:GetPlaceholderText() + + return self.placeholder + +end + +--[[--------------------------------------------------------- + - func: ClearLine(line) + - desc: clears the specified line +--]]--------------------------------------------------------- +function newobject:ClearLine(line) + + if self.lines[line] then + self.lines[line] = "" + end + + return self + +end + +--[[--------------------------------------------------------- + - func: SetTrackingEnabled(bool) + - desc: sets whether or not the object should + automatically scroll to the position of its + indicator +--]]--------------------------------------------------------- +function newobject:SetTrackingEnabled(bool) + + self.trackindicator = bool + return self + +end + +--[[--------------------------------------------------------- + - func: GetTrackingEnabled() + - desc: gets whether or not the object should + automatically scroll to the position of its + indicator +--]]--------------------------------------------------------- +function newobject:GetTrackingEnabled() + + return self.trackindicator + +end + +---------- module end ---------- +end diff --git a/loveframes/objects/tree.lua b/loveframes/objects/tree.lua new file mode 100644 index 0000000..8550da5 --- /dev/null +++ b/loveframes/objects/tree.lua @@ -0,0 +1,342 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- tree object +local newobject = loveframes.NewObject("tree", "loveframes_object_tree", true) + +--[[--------------------------------------------------------- + - func: initialize() + - desc: initializes the object +--]]--------------------------------------------------------- +function newobject:initialize() + + self.type = "tree" + self.width = 200 + self.height = 200 + self.offsetx = 0 + self.offsety = 0 + self.itemwidth = 0 + self.itemheight = 0 + self.extrawidth = 0 + self.extraheight = 0 + self.buttonscrollamount = 0.10 + self.vbar = false + self.hbar = false + self.internal = false + self.selectednode = false + self.OnSelectNode = nil + self.children = {} + self.internals = {} + + self:SetDrawFunc() +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 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 + + self.itemwidth = 0 + self.itemheight = 0 + + for k, v in ipairs(self.children) do + v.x = (v.parent.x + v.staticx) - self.offsetx + v.y = (self.y + self.itemheight) - self.offsety + if v.width > self.itemwidth then + self.itemwidth = v.width + end + self.itemheight = self.itemheight + v.height + v:update(dt) + end + + if self.vbar then + self.itemwidth = self.itemwidth + 16 + 5 + end + + self.extrawidth = self.itemwidth - self.width + self.extraheight = self.itemheight - self.height + + if self.itemheight > self.height then + if not self.vbar then + local scrollbody = loveframes.objects["scrollbody"]:new(self, "vertical") + table.insert(self.internals, scrollbody) + self.vbar = true + if self.hbar then + local vbody = self:GetVerticalScrollBody() + local vbodyheight = vbody:GetHeight() - 15 + local hbody = self:GetHorizontalScrollBody() + local hbodywidth = hbody:GetWidth() - 15 + vbody:SetHeight(vbodyheight) + hbody:SetWidth(hbodywidth) + end + end + else + if self.vbar then + self:GetVerticalScrollBody():Remove() + self.vbar = false + self.offsety = 0 + if self.hbar then + local hbody = self:GetHorizontalScrollBody() + local hbodywidth = hbody:GetWidth() - 15 + hbody:SetWidth(hbodywidth) + end + end + end + + if self.itemwidth > self.width then + if not self.hbar then + local scrollbody = loveframes.objects["scrollbody"]:new(self, "horizontal") + table.insert(self.internals, scrollbody) + self.hbar = true + if self.vbar then + local vbody = self:GetVerticalScrollBody() + local hbody = self:GetHorizontalScrollBody() + vbody:SetHeight(vbody:GetHeight() - 15) + hbody:SetWidth(hbody:GetWidth() - 15) + end + end + else + if self.hbar then + self:GetHorizontalScrollBody():Remove() + self.hbar = false + self.offsetx = 0 + if self.vbar then + local vbody = self:GetVerticalScrollBody() + if vbody then + vbody:SetHeight(vbody:GetHeight() + 15) + end + end + end + end + + for k, v in ipairs(self.internals) do + v:update(dt) + end + + if update then + update(self, dt) + end + +end + +--[[--------------------------------------------------------- + - func: draw() + - desc: draws the object +--]]--------------------------------------------------------- +function newobject:draw() + if loveframes.state ~= self.state then + return + end + + if not self.visible then + return + end + + local stencilfunc + + if self.vbar and not self.hbar then + stencilfunc = function() love.graphics.rectangle("fill", self.x, self.y, self.width - 16, self.height) end + elseif self.hbar and not self.vbar then + stencilfunc = function() love.graphics.rectangle("fill", self.x, self.y, self.width, self.height - 16) end + elseif self.vbar and self.hbar then + stencilfunc = function() love.graphics.rectangle("fill", self.x, self.y, self.width - 16, self.height - 16) end + end + + self:SetDrawOrder() + + love.graphics.stencil(stencilfunc) + love.graphics.setStencilTest("greater", 0) + + local drawfunc = self.Draw or self.drawfunc + if drawfunc then + drawfunc(self) + end + + local children = self.children + if children then + for k, v in ipairs(children) do + v:draw() + end + end + + love.graphics.setStencilTest() + + local internals = self.internals + if internals then + for k, v in ipairs(internals) do + v:draw() + end + 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 + + for k, v in ipairs(self.internals) do + v:mousepressed(x, y, button) + end + + for k, v in ipairs(self.children) do + v:mousepressed(x, y, button) + 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 + + for k, v in ipairs(self.internals) do + v:mousereleased(x, y, button) + end + + for k, v in ipairs(self.children) do + v:mousereleased(x, y, button) + end + +end + +--[[--------------------------------------------------------- + - func: AddNode(text) + - desc: adds a node to the object +--]]--------------------------------------------------------- +function newobject:AddNode(text) + + local node = loveframes.objects["treenode"]:new() + node.parent = self + node.tree = self + node.text = text + node.staticx = 0 + node.staticy = self.itemheight + table.insert(self.children, node) + return node + +end + +--[[--------------------------------------------------------- + - func: RemoveNode(id) + - desc: removes a node from the object +--]]--------------------------------------------------------- +function newobject:RemoveNode(id) + + for k, v in ipairs(self.children) do + if k == id then + v:Remove() + break + end + end + +end + +--[[--------------------------------------------------------- + - func: GetVerticalScrollBody() + - desc: gets the object's vertical scroll body +--]]--------------------------------------------------------- +function newobject:GetVerticalScrollBody() + + local vbar = self.vbar + local internals = self.internals + local item = false + + if vbar then + for k, v in ipairs(internals) do + if v.type == "scrollbody" and v.bartype == "vertical" then + item = v + end + end + end + + return item + +end + +--[[--------------------------------------------------------- + - func: GetHorizontalScrollBody() + - desc: gets the object's horizontal scroll body +--]]--------------------------------------------------------- +function newobject:GetHorizontalScrollBody() + + local hbar = self.hbar + local internals = self.internals + local item = false + + if hbar then + for k, v in ipairs(internals) do + if v.type == "scrollbody" and v.bartype == "horizontal" then + item = v + end + end + end + + return item + +end + +---------- module end ---------- +end diff --git a/loveframes/skins/Blue/images/arrow-down.png b/loveframes/skins/Blue/images/arrow-down.png new file mode 100644 index 0000000000000000000000000000000000000000..37d805800fd4b840d58fc637925316b0a4c697a1 GIT binary patch literal 344 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DkxL735kHCP2GC{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L0m@TF)WP}LPr z7sn6_|D%&{b2S?XxIDkScd-J;zLhW1J02WgYI}%n?ewUcj08h9V|C@UrThC8IKC{A zn`wE2`H@A~wA53d|7^OjVC$9BDqTvUp{mbi-oJ}pc=WOGlFU_!5;hNbtz-{eeDska zsWf(Z<}5wM85b8Eeaz@NX@v%tsqf;-dHjkqZaO!Moo7lg;5;0V8o4U>cC3)~Ok0zT zy*C-y9_oLo-QOrM+w|L+J&bD)qoukrfZiGM9iW4o<-YOgt$Id<&Q mt1o!lvI6;>1s;*b z3=DkxL735kHCP2GC{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L0m@TF)WP}Nya z7sn6_|D}^-xta|GTAsg9a|;w`*|YLUa>s**m-V}; zz53}!hNP$N3}ta%7EXDx8z#PSzH{V_T*0#N f%AVd?eNI2iCUnwgTe~DWM4fwk?E# literal 0 HcmV?d00001 diff --git a/loveframes/skins/Blue/images/arrow-right.png b/loveframes/skins/Blue/images/arrow-right.png new file mode 100644 index 0000000000000000000000000000000000000000..89b4818627737201d05713540777e2d19c06f43d GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DkxL735kHCP2GC{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L0m@TF)WP}Lbv z7sn6_|D}_oxta|GT;E?Z&GJxC_>u0iKc<;O?|^AXhxbO=mmZp)w~ieU;FxK=-ul36 z6;G!5ALl>#`%b6DAy8yOkka|j+<$}>P8&^0?OgZzf(h@IYaW-sShpB2SW$aFd0u+Y z!lvI6;>1s;*b z3=DkxL735kHCP2GC{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L0m@TF)WP}M6> z7sn6_|E-f^yIKqcT3)~Sw^)H=-^v%0(*+JPSFj0w)Yx5dam1j3-RA4AY7wnX3{dwyb*{y-A-*tWUUOkw<7~ri{CC zfq2403&u$neZ9K-zQi-Kt@%CI?B|!aQ|!cc?7e-T?GMv`=O9y_SBJHLzGm=r^>bP0 Hl+XkK=vs{Q literal 0 HcmV?d00001 diff --git a/loveframes/skins/Blue/images/close.png b/loveframes/skins/Blue/images/close.png new file mode 100644 index 0000000000000000000000000000000000000000..0825add2273d02377027f72a64d1704ddbb573a8 GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DjSK$uZf!>a)(C{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L0m@TF)WP*sJe zi(`m||Jun9`5F{BS}OnB+Z2`Zc75>>+h{qvK%P_MQ~SzQ38A@N+ne9ssP$cw%5x-- zt;)g8{&WH32SLTaH+EIAVi982g(64pH?0rJU`s6ZOq6_3{O!ivaF5j;oj-gcUb$pX rn3kL+&cC?Narfzqbv{eKsW@8KHKm2zN%(#e=mrK)S3j3^P6!lvI6;>1s;*b z3=Dh+L6~vJ#O${~L8%hgh?3y^w370~qEv=}#LT=BJwMkFg)(D3Q$0gN_s>q|KvmA3 zE{-7<{!33Aaxob296s>x|7E>cCk?4Z*9y81XrC1CVRK_%+<5UoMuN#ZgV@?%KWD77 k`}>ClDr6uf@qCk+;v_+-WnpeNfyOa-y85}Sb4q9e0Oi>~)Bpeg literal 0 HcmV?d00001 diff --git a/loveframes/skins/Blue/images/expand.png b/loveframes/skins/Blue/images/expand.png new file mode 100644 index 0000000000000000000000000000000000000000..753625b10513728b6fdaf399a31dbf9c342128d4 GIT binary patch literal 221 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=Dh+L6~vJ#O${~L8%hgh?3y^w370~qEv=}#LT=BJwMkFg)(D3Q$0gN_s>q|Kvj{R zE{-7<{!33gaxp0IFgyPL|FWymV}k7#i5aJ-ty}f0sgUV0%drO+eGS<9^O_7RN`!k3 zE}p$-;qKp)&%2j@SD)YMZhlb0W)~-14OqjzDCul2MXmVM%xNb!1@J z*w6hZkrl}2EbxddW?GP*_V=L}<7d|Pe0uNo zKfa$+*Ks*pbxn$5-$xyz#hn&5?uR(oo$9|Vs=Xk%yV^Trdt1QYs3jGm8%w>N%D9|% fJzLZ}_al47Y>!(z_SlpHtzz(W^>bP0l+XkK>;_US literal 0 HcmV?d00001 diff --git a/loveframes/skins/Blue/images/gradients/button-hover.png b/loveframes/skins/Blue/images/gradients/button-hover.png new file mode 100644 index 0000000000000000000000000000000000000000..13f51e05bca72ca85f5f77034a46410a3e816c5b GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{T!3HEx%~ItD2^0spJ29*~C-V}>VM%xNb!1@J z*w6hZkrl}2EbxddW?B%O_V=L}<7d|Pe0uNo zKfa$+*Ks*pbxn$5-$xyz#hn&5?uR(oo$9|Vs=Xk%yV^Trdt1QYs3jGm8%w>N%D9|% fJzLZ}_anQZxA*^l+lAPHRxx literal 0 HcmV?d00001 diff --git a/loveframes/skins/Blue/images/gradients/button-nohover.png b/loveframes/skins/Blue/images/gradients/button-nohover.png new file mode 100644 index 0000000000000000000000000000000000000000..39ff24a9cbb1d8427ecf6b432c1084f6c251bcb7 GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{T!3HEx%~ItD2^0spJ29*~C-V}>VM%xNb!1@J z*w6hZkrl}2EbxddW?wRU|_*9pt+DU&)3_c?JKs@9)Vd?@O-(XkiI%4Z^O{LoE}0~*TU>FVdQ I&MBb@06yMGfdBvi literal 0 HcmV?d00001 diff --git a/loveframes/skins/Blue/images/gradients/button-unclickable.png b/loveframes/skins/Blue/images/gradients/button-unclickable.png new file mode 100644 index 0000000000000000000000000000000000000000..ef8bf7defb2900d7e0487758332d1cc8a58dbf73 GIT binary patch literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{T!3HEx%~ItD2^0spJ29*~C-V}>VM%xNb!1@J z*w6hZkrl}2EbxddW?VM%xNb!1@J z*w6hZkrl}2EbxddW?LzG&HgubM}3gQ1&`=0?kOouvtDMWeHCRHq-8uy}rCtJu4}H;ei1Re#*u?(${6 aOZ>9M3P*&x&U>c zv7h@-A}f&3S>O>_%)r2R7=#&*=dVZs3QCo@MwA5SrEak75w3eAlBtnFg!RI1_pT6)sCeOpo^O{oPKvyK-ddjB&r<02 zBlX;K@rTaYw@lsJS^8^I*vZKe$M_G~+~s_1;qmLCo6e$n7rx0F-j7`xS)q7kfvU)U g#bt52zIVFnwR}7ds)mJL0NTai>FVdQ&MBb@03s_;-~a#s literal 0 HcmV?d00001 diff --git a/loveframes/skins/Blue/images/gradients/progressbar.png b/loveframes/skins/Blue/images/gradients/progressbar.png new file mode 100644 index 0000000000000000000000000000000000000000..7cdfb4b670b7ff968bb7b7f42fe4d78bf89fd28f GIT binary patch literal 199 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{T!3HEx%~ItD2^0spJ29*~C-V}>VM%xNb!1@J z*w6hZkrl}2EbxddW? o3mwdax<4GqWqJ0Hsr(0{P>s$v`89=ifhI6`y85}Sb4q9e0Es?4l>h($ literal 0 HcmV?d00001 diff --git a/loveframes/skins/Blue/images/multichoice-arrow.png b/loveframes/skins/Blue/images/multichoice-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..165121c956329680f817fdc62358e736bfebea59 GIT binary patch literal 284 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?(3p^r= z85sBufiR<}hF1enP^!c=q9iy!t)x7$D3u`~F*C13&(AePq0Cs%RL{`B;7id$psE?3 zE{-7<{(C21^lnCf7dUk^^n)TlAORn9F1`-=yF5J3IB6%{4LDoSPMkf7ZGu%Df z0;3<;h(roGttexXs1B{r-*|1(loW~T<&&RAEOPKt$Z2}|-r_k&!lvI6;>1s;*b z3=DjSK$uZf!>a)(C{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L2E{@KYKs7lGx z#W6%9IN8F1qaozaab7kDR%WdRj!7A8VGgdMKMpi9Gi)lh)k(9~cLl0u@O1TaS?83{ F1OU|CD9``^ literal 0 HcmV?d00001 diff --git a/loveframes/skins/Blue/images/tree-node-button-open.png b/loveframes/skins/Blue/images/tree-node-button-open.png new file mode 100644 index 0000000000000000000000000000000000000000..68b36cc13a11438894385c81a1e06d444b83ef57 GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1SHkYJtzcHEa{HEjtmSN`?>!lvI6;>1s;*b z3=DjSK$uZf!>a)(C{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L2E{@KYKs7l|{ z#W6%9IN8F1qaozaao!U_2M-)zNNr^7)M_X?!Jy=^NK(Kdf>lZ(iq)>*0RzLg4TctX Rynq^kz|+;wWt~$(699fEF6#gQ literal 0 HcmV?d00001 diff --git a/loveframes/skins/Blue/skin.lua b/loveframes/skins/Blue/skin.lua new file mode 100644 index 0000000..1f4e879 --- /dev/null +++ b/loveframes/skins/Blue/skin.lua @@ -0,0 +1,2110 @@ +--[[------------------------------------------------ + -- Love Frames - A GUI library for LOVE -- + -- Copyright (c) 2012-2014 Kenny Shields -- +--]]------------------------------------------------ + +return function(loveframes) +---------- module start ---------- + +-- skin table +local skin = {} + +-- skin info (you always need this in a skin) +skin.name = "Blue" +skin.author = "Nikolai Resokav" +skin.version = "1.0" + +local bordercolor = {0.56, 0.56, 0.56, 1} + +-- add skin directives to this table +skin.directives = {} + +-- controls +skin.controls = {} +skin.controls.smallfont = love.graphics.newFont(11) +skin.controls.imagebuttonfont = love.graphics.newFont(15) + +-- frame +skin.controls.frame_body_color = {0.91, 0.91, 0.91, 1} +skin.controls.frame_name_color = {1, 1, 1, 1} +skin.controls.frame_name_font = skin.controls.smallfont + +-- button +skin.controls.button_text_down_color = {1, 1, 1, 1} +skin.controls.button_text_nohover_color = {0, 0, 0, 0.78} +skin.controls.button_text_hover_color = {1, 1, 1, 1} +skin.controls.button_text_nonclickable_color = {0, 0, 0, 0.39} +skin.controls.button_text_font = skin.controls.smallfont + +-- imagebutton +skin.controls.imagebutton_text_down_color = {1, 1, 1, 1} +skin.controls.imagebutton_text_nohover_color = {1, 1, 1, 0.78} +skin.controls.imagebutton_text_hover_color = {1, 1, 1, 1} +skin.controls.imagebutton_text_font = skin.controls.imagebuttonfont + +-- closebutton +skin.controls.closebutton_body_down_color = {1, 1, 1, 1} +skin.controls.closebutton_body_nohover_color = {1, 1, 1, 1} +skin.controls.closebutton_body_hover_color = {1, 1, 1, 1} + +-- progressbar +skin.controls.progressbar_body_color = {1, 1, 1, 1} +skin.controls.progressbar_text_color = {0, 0, 0, 1} +skin.controls.progressbar_text_font = skin.controls.smallfont + +-- list +skin.controls.list_body_color = {0.91, 0.91, 0.91, 1} + +-- scrollarea +skin.controls.scrollarea_body_color = {0.86, 0.86, 0.86, 1} + +-- scrollbody +skin.controls.scrollbody_body_color = {0, 0, 0, 0} + +-- panel +skin.controls.panel_body_color = {0.91, 0.91, 0.91, 1} + +-- tabpanel +skin.controls.tabpanel_body_color = {0.91, 0.91, 0.91, 1} + +-- tabbutton +skin.controls.tab_text_nohover_color = {0, 0, 0, 0.78} +skin.controls.tab_text_hover_color = {1, 1, 1, 1} +skin.controls.tab_text_font = skin.controls.smallfont + +-- multichoice +skin.controls.multichoice_body_color = {0.94, 0.94, 0.94, 1} +skin.controls.multichoice_text_color = {0, 0, 0, 1} +skin.controls.multichoice_text_font = skin.controls.smallfont + +-- multichoicelist +skin.controls.multichoicelist_body_color = {0.94, 0.94, 0.94, 0.78} + +-- multichoicerow +skin.controls.multichoicerow_body_nohover_color = {0.94, 0.94, 0.94, 1} +skin.controls.multichoicerow_body_hover_color = {0.2, 0.8, 1, 1} +skin.controls.multichoicerow_text_nohover_color = {0, 0, 0, 0.59} +skin.controls.multichoicerow_text_hover_color = {1, 1, 1, 1} +skin.controls.multichoicerow_text_font = skin.controls.smallfont + +-- tooltip +skin.controls.tooltip_body_color = {1, 1, 1, 1} + +-- textinput +skin.controls.textinput_body_color = {0.98, 0.98, 0.98, 1} +skin.controls.textinput_indicator_color = {0, 0, 0, 1} +skin.controls.textinput_text_normal_color = {0, 0, 0, 1} +skin.controls.textinput_text_placeholder_color = {0.5, 0.5, 0.5, 1} +skin.controls.textinput_text_selected_color = {1, 1, 1, 1} +skin.controls.textinput_highlight_bar_color = {0.2, 0.8, 1, 1} + +-- slider +skin.controls.slider_bar_outline_color = {0.86, 0.86, 0.86, 1} + +-- checkbox +skin.controls.checkbox_body_color = {1, 1, 1, 1} +skin.controls.checkbox_check_color = {0.5, 0.8, 1, 1} +skin.controls.checkbox_text_font = skin.controls.smallfont + +-- radiobutton +skin.controls.radiobutton_body_color = {1, 1, 1, 1} +skin.controls.radiobutton_check_color = {0.5, 0.8, 1, 1} +skin.controls.radiobutton_inner_border_color = {0.3, 0.72, 1, 1} +skin.controls.radiobutton_text_font = skin.controls.smallfont + +-- collapsiblecategory +skin.controls.collapsiblecategory_text_color = {1, 1, 1, 1} + +-- columnlist +skin.controls.columnlist_body_color = {0.91, 0.91, 0.91, 1} + +-- columlistarea +skin.controls.columnlistarea_body_color = {0.91, 0.91, 0.91, 1} + +-- columnlistheader +skin.controls.columnlistheader_text_down_color = {1, 1, 1, 1} +skin.controls.columnlistheader_text_nohover_color = {0, 0, 0, 0.78} +skin.controls.columnlistheader_text_hover_color = {1, 1, 1, 1} +skin.controls.columnlistheader_text_font = skin.controls.smallfont + +-- columnlistrow +skin.controls.columnlistrow_body1_color = {0.96, 0.96, 0.96, 1} +skin.controls.columnlistrow_body2_color = {1, 1, 1, 1} +skin.controls.columnlistrow_body_selected_color = {0.1, 0.78, 1, 1} +skin.controls.columnlistrow_body_hover_color = {0.4, 0.85, 1, 1} +skin.controls.columnlistrow_text_color = {0.39, 0.39, 0.39, 1} +skin.controls.columnlistrow_text_hover_color = {1, 1, 1, 1} +skin.controls.columnlistrow_text_selected_color = {1, 1, 1, 1} + +-- modalbackground +skin.controls.modalbackground_body_color = {1, 1, 1, 0.39} + +-- linenumberspanel +skin.controls.linenumberspanel_text_color = {0.67, 0.67, 0.67, 1} +skin.controls.linenumberspanel_body_color = {0.92, 0.92, 0.92, 1} + +-- grid +skin.controls.grid_body_color = {0.9, 0.9, 0.9, 1} + +-- form +skin.controls.form_text_color = {0, 0, 0, 1} +skin.controls.form_text_font = skin.controls.smallfont + +-- menu +skin.controls.menu_body_color = {1, 1, 1, 1} + +-- menuoption +skin.controls.menuoption_body_hover_color = {0.2, 0.8, 1, 1} +skin.controls.menuoption_text_hover_color = {1, 1, 1, 1} +skin.controls.menuoption_text_color = {0.71, 0.71, 0.71, 1} + +local function ParseHeaderText(str, hx, hwidth, tx) + + local font = love.graphics.getFont() + local twidth = love.graphics.getFont():getWidth(str) + + if (tx + twidth) - hwidth/2 > hx + hwidth then + if #str > 1 then + return ParseHeaderText(loveframes.utf8.sub(str, 1, #str - 1), hx, hwidth, tx, twidth) + else + return str + end + else + return str + end + +end + +local function ParseRowText(str, rx, rwidth, tx1, tx2) + + local twidth = love.graphics.getFont():getWidth(str) + + if (tx1 + tx2) + twidth > rx + rwidth then + if #str > 1 then + return ParseRowText(loveframes.utf8.sub(str, 1, #str - 1), rx, rwidth, tx1, tx2) + else + return str + end + else + return str + end + +end + +function skin.PrintText(text, x, y) + love.graphics.print(text, math.floor(x + 0.5), math.floor(y + 0.5)) +end + +--[[ +local function DrawColumnHeaderText(text, hx, hwidth, tx, twidth) + + local new = "" + if tx + width > hx + hwidth then +--]] + +--[[--------------------------------------------------------- + - func: OutlinedRectangle(x, y, width, height, ovt, ovb, ovl, ovr) + - desc: creates and outlined rectangle +--]]--------------------------------------------------------- +function skin.OutlinedRectangle(x, y, width, height, ovt, ovb, ovl, ovr) + + local ovt = ovt or false + local ovb = ovb or false + local ovl = ovl or false + local ovr = ovr or false + + -- top + if not ovt then + love.graphics.rectangle("fill", x, y, width, 1) + end + + -- bottom + if not ovb then + love.graphics.rectangle("fill", x, y + height - 1, width, 1) + end + + -- left + if not ovl then + love.graphics.rectangle("fill", x, y, 1, height) + end + + -- right + if not ovr then + love.graphics.rectangle("fill", x + width - 1, y, 1, height) + end + +end + +--[[--------------------------------------------------------- + - func: DrawFrame(object) + - desc: draws the frame object +--]]--------------------------------------------------------- +function skin.frame(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 name = object:GetName() + local icon = object:GetIcon() + local bodycolor = skin.controls.frame_body_color + local topcolor = skin.controls.frame_top_color + local namecolor = skin.controls.frame_name_color + local font = skin.controls.frame_name_font + 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 bodyimage = skin.images["frame-body.png"] + local bodyimage_width = bodyimage:getWidth() + local bodyimage_height = bodyimage:getHeight() + local bodyimage_scalex = width/bodyimage_width + local bodyimage_scaley = height/bodyimage_height + + -- frame body + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(bodyimage, x, y, 0, bodyimage_scalex, bodyimage_scaley) + + -- frame top bar + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(topbarimage, x, y, 0, topbarimage_scalex, topbarimage_scaley) + + -- frame name section + love.graphics.setFont(font) + + if icon then + local iconwidth = icon:getWidth() + local iconheight = icon:getHeight() + icon:setFilter("nearest", "nearest") + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(icon, x + 5, y + 5) + love.graphics.setColor(namecolor) + skin.PrintText(name, x + iconwidth + 10, y + 5) + else + love.graphics.setColor(namecolor) + skin.PrintText(name, x + 5, y + 5) + end + + -- frame border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + + love.graphics.setColor(1, 1, 1, 0.27) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, 24) + + love.graphics.setColor(0.86, 0.86, 0.86, 1) + skin.OutlinedRectangle(x + 1, y + 25, width - 2, height - 26) + +end + +--[[--------------------------------------------------------- + - func: DrawButton(object) + - desc: draws the button object +--]]--------------------------------------------------------- +function skin.button(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 font = skin.controls.button_text_font + local twidth = font:getWidth(object.text) + local theight = font:getHeight(object.text) + local down = object:GetDown() + local checked = object.checked + local enabled = object:GetEnabled() + local clickable = object:GetClickable() + local textdowncolor = skin.controls.button_text_down_color + local texthovercolor = skin.controls.button_text_hover_color + local textnohovercolor = skin.controls.button_text_nohover_color + local textnonclickablecolor = skin.controls.button_text_nonclickable_color + local image_hover = skin.images["button-hover.png"] + local scaley = height/image_hover:getHeight() + + if not enabled or not clickable then + -- button body + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(skin.images["button-unclickable.png"], x, y, 0, width, scaley) + -- button text + love.graphics.setFont(font) + love.graphics.setColor(textnonclickablecolor) + skin.PrintText(text, x + width/2 - twidth/2, y + height/2 - theight/2) + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + return + end + + if object.toggleable then + if hover then + if down then + -- button body + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(skin.images["button-down.png"], x, y, 0, width, scaley) + -- button text + love.graphics.setFont(font) + love.graphics.setColor(textdowncolor) + skin.PrintText(text, x + width/2 - twidth/2, y + height/2 - theight/2) + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + else + -- button body + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image_hover, x, y, 0, width, scaley) + -- button text + love.graphics.setFont(font) + love.graphics.setColor(texthovercolor) + skin.PrintText(text, x + width/2 - twidth/2, y + height/2 - theight/2) + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + end + else + if object.toggle then + -- button body + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(skin.images["button-down.png"], x, y, 0, width, scaley) + -- button text + love.graphics.setFont(font) + love.graphics.setColor(textdowncolor) + skin.PrintText(text, x + width/2 - twidth/2, y + height/2 - theight/2) + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + else + -- button body + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(skin.images["button-nohover.png"], x, y, 0, width, scaley) + -- button text + love.graphics.setFont(font) + love.graphics.setColor(textnohovercolor) + skin.PrintText(text, x + width/2 - twidth/2, y + height/2 - theight/2) + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + end + end + else + if down or checked then + -- button body + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(skin.images["button-down.png"], x, y, 0, width, scaley) + -- button text + love.graphics.setFont(font) + if object.image then + love.graphics.setColor(1, 1, 1) + love.graphics.draw(object.image, x + 2, y + height/2 - object.image:getHeight()/2) + love.graphics.setColor(textdowncolor) + local text = object.text + local font = skin.controls.button_text_font + while font:getWidth(text) > width - object.image:getWidth() - 10 do + text =loveframes.utf8.sub(text, 2) + while text:byte(1, 1) > 127 do text = loveframes.utf8.sub(text, 2) end + end + skin.PrintText(text, x + object.image:getWidth() + 4, y + height/2 - theight/2) + else + love.graphics.setColor(textdowncolor) + skin.PrintText(text, x + width/2 - twidth/2, y + height/2 - theight/2) + end + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + elseif hover then + -- button body + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image_hover, x, y, 0, width, scaley) + -- button text + love.graphics.setFont(font) + if object.image then + love.graphics.setColor(1, 1, 1) + love.graphics.draw(object.image, x + 2, y + height/2 - object.image:getHeight()/2) + love.graphics.setColor(texthovercolor) + local text = object.text + local font = skin.controls.button_text_font + while font:getWidth(text) > width - object.image:getWidth() - 10 do + text =loveframes.utf8.sub(text, 2) + while text:byte(1, 1) > 127 do text = loveframes.utf8.sub(text, 2) end + end + skin.PrintText(text, x + object.image:getWidth() + 4, y + height/2 - theight/2) + else + love.graphics.setColor(texthovercolor) + skin.PrintText(text, x + width/2 - twidth/2, y + height/2 - theight/2) + end + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + else + -- button body + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(skin.images["button-nohover.png"], x, y, 0, width, scaley) + -- button text + love.graphics.setFont(font) + if object.image then + love.graphics.setColor(1, 1, 1) + love.graphics.draw(object.image, object:GetX() + 2, object:GetY() + object:GetHeight()/2 - object.image:getHeight()/2) + love.graphics.setColor(textnohovercolor) + local text = object.text + local font = skin.controls.button_text_font + while font:getWidth(text) > width - object.image:getWidth() - 10 do + text =loveframes.utf8.sub(text, 2) + while text:byte(1, 1) > 127 do text = loveframes.utf8.sub(text, 2) end + end + skin.PrintText(text, x + object.image:getWidth() + 4, y + height/2 - theight/2) + else + love.graphics.setColor(textnohovercolor) + skin.PrintText(text, x + width/2 - twidth/2, y + height/2 - theight/2) + end + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + end + end + + love.graphics.setColor(1, 1, 1, 0.59) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, height - 2) + +end + +--[[--------------------------------------------------------- + - func: DrawCloseButton(object) + - desc: draws the close button object +--]]--------------------------------------------------------- +function skin.closebutton(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local parent = object.parent + local parentwidth = parent:GetWidth() + local hover = object:GetHover() + local down = object.down + local image = skin.images["close.png"] + local bodydowncolor = skin.controls.closebutton_body_down_color + local bodyhovercolor = skin.controls.closebutton_body_hover_color + local bodynohovercolor = skin.controls.closebutton_body_nohover_color + + image:setFilter("nearest", "nearest") + + if down then + -- button body + love.graphics.setColor(bodydowncolor) + love.graphics.draw(image, x, y) + elseif hover then + -- button body + love.graphics.setColor(bodyhovercolor) + love.graphics.draw(image, x, y) + else + -- button body + love.graphics.setColor(bodynohovercolor) + love.graphics.draw(image, x, y) + end + +end + +--[[--------------------------------------------------------- + - func: DrawImage(object) + - desc: draws the image object +--]]--------------------------------------------------------- +function skin.image(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local orientation = object:GetOrientation() + local scalex = object:GetScaleX() + local scaley = object:GetScaleY() + local offsetx = object:GetOffsetX() + local offsety = object:GetOffsetY() + local shearx = object:GetShearX() + local sheary = object:GetShearY() + local image = object.image + local color = object.imagecolor + local stretch = object.stretch + + if stretch then + scalex, scaley = object:GetWidth() / image:getWidth(), object:GetHeight() / image:getHeight() + end + + if color then + love.graphics.setColor(color) + love.graphics.draw(image, x, y, orientation, scalex, scaley, offsetx, offsety, shearx, sheary) + else + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, orientation, scalex, scaley, offsetx, offsety, shearx, sheary) + end + +end + +--[[--------------------------------------------------------- + - func: DrawImageButton(object) + - desc: draws the image button object +--]]--------------------------------------------------------- +function skin.imagebutton(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local text = object:GetText() + local hover = object:GetHover() + local image = object:GetImage() + local imagecolor = object.imagecolor or {1, 1, 1, 1} + local down = object.down + local font = skin.controls.imagebutton_text_font + local twidth = font:getWidth(object.text) + local theight = font:getHeight(object.text) + local textdowncolor = skin.controls.imagebutton_text_down_color + local texthovercolor = skin.controls.imagebutton_text_hover_color + local textnohovercolor = skin.controls.imagebutton_text_nohover_color + local checked = object.checked + + if down then + if image then + love.graphics.setColor(imagecolor) + love.graphics.draw(image, x + 1, y + 1) + end + love.graphics.setFont(font) + love.graphics.setColor(0, 0, 0, 1) + skin.PrintText(text, x + width/2 - twidth/2 + 1, y + height - theight - 5 + 1) + love.graphics.setColor(textdowncolor) + skin.PrintText(text, x + width/2 - twidth/2 + 1, y + height - theight - 6 + 1) + elseif hover then + if image then + love.graphics.setColor(imagecolor) + love.graphics.draw(image, x, y) + end + love.graphics.setFont(font) + love.graphics.setColor(0, 0, 0, 1) + skin.PrintText(text, x + width/2 - twidth/2, y + height - theight - 5) + love.graphics.setColor(texthovercolor) + skin.PrintText(text, x + width/2 - twidth/2, y + height - theight - 6) + else + if image then + love.graphics.setColor(imagecolor) + love.graphics.draw(image, x, y) + end + love.graphics.setFont(font) + love.graphics.setColor(0, 0, 0, 1) + skin.PrintText(text, x + width/2 - twidth/2, y + height - theight - 5) + love.graphics.setColor(textnohovercolor) + skin.PrintText(text, x + width/2 - twidth/2, y + height - theight - 6) + end + if checked == true then + love.graphics.setColor(bordercolor) + love.graphics.setLineWidth(3) + love.graphics.setLineStyle("smooth") + love.graphics.rectangle("line", x+1, y+1, width-2, height-2) + end + +end + +--[[--------------------------------------------------------- + - func: DrawProgressBar(object) + - desc: draws the progress bar object +--]]--------------------------------------------------------- +function skin.progressbar(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local value = object:GetValue() + local max = object:GetMax() + local text = object:GetText() + local barwidth = object:GetBarWidth() + local font = skin.controls.progressbar_text_font + local twidth = font:getWidth(text) + local theight = font:getHeight("a") + local bodycolor = skin.controls.progressbar_body_color + local barcolor = skin.controls.progressbar_bar_color + local textcolor = skin.controls.progressbar_text_color + local image = skin.images["progressbar.png"] + local imageheight = image:getHeight() + local scaley = height/imageheight + + -- progress bar body + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x, y, width, height) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, barwidth, scaley) + love.graphics.setFont(font) + love.graphics.setColor(textcolor) + skin.PrintText(text, x + width/2 - twidth/2, y + height/2 - theight/2) + + -- progress bar border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + + object:SetText(value .. "/" ..max) + +end + +--[[--------------------------------------------------------- + - func: DrawScrollArea(object) + - desc: draws the scroll area object +--]]--------------------------------------------------------- +function skin.scrollarea(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local bartype = object:GetBarType() + local bodycolor = skin.controls.scrollarea_body_color + + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x, y, width, height) + love.graphics.setColor(bordercolor) + + if bartype == "vertical" then + --skin.OutlinedRectangle(x, y, width, height, true, true) + elseif bartype == "horizontal" then + --skin.OutlinedRectangle(x, y, width, height, false, false, true, true) + end + +end + +--[[--------------------------------------------------------- + - func: DrawScrollBar(object) + - desc: draws the scroll bar object +--]]--------------------------------------------------------- +function skin.scrollbar(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local dragging = object:IsDragging() + local hover = object:GetHover() + local bartype = object:GetBarType() + local bodydowncolor = skin.controls.scrollbar_body_down_color + local bodyhovercolor = skin.controls.scrollbar_body_hover_color + local bodynohvercolor = skin.controls.scrollbar_body_nohover_color + + if dragging then + local image = skin.images["button-down.png"] + local imageheight = image:getHeight() + local scaley = height/imageheight + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + elseif hover then + local image = skin.images["button-hover.png"] + local imageheight = image:getHeight() + local scaley = height/imageheight + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + else + local image = skin.images["button-nohover.png"] + local imageheight = image:getHeight() + local scaley = height/imageheight + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + end + +end + +--[[--------------------------------------------------------- + - func: DrawScrollBody(object) + - desc: draws the scroll body object +--]]--------------------------------------------------------- +function skin.scrollbody(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.scrollbody_body_color + + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: DrawPanel(object) + - desc: draws the panel object +--]]--------------------------------------------------------- +function skin.panel(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.panel_body_color + + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x, y, width, height) + + love.graphics.setColor(1, 1, 1, 0.78) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, height - 2) + + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: DrawList(object) + - desc: draws the list object +--]]--------------------------------------------------------- +function skin.list(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.list_body_color + + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: DrawList(object) + - desc: used to draw over the object and its children +--]]--------------------------------------------------------- +function skin.list_over(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: DrawTabPanel(object) + - desc: draws the tab panel object +--]]--------------------------------------------------------- +function skin.tabpanel(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local buttonheight = object:GetHeightOfButtons() + local bodycolor = skin.controls.tabpanel_body_color + + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x, y + buttonheight, width, height - buttonheight) + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y + buttonheight - 1, width, height - buttonheight + 2) + + object:SetScrollButtonSize(15, buttonheight) + +end + +--[[--------------------------------------------------------- + - func: DrawOverTabPanel(object) + - desc: draws over the tab panel object +--]]--------------------------------------------------------- +function skin.tabpanel_over(object) + +end + +--[[--------------------------------------------------------- + - func: DrawTabButton(object) + - desc: draws the tab button object +--]]--------------------------------------------------------- +function skin.tabbutton(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local hover = object:GetHover() + local text = object:GetText() + local image = object:GetImage() + local tabnumber = object:GetTabNumber() + local parent = object:GetParent() + local ptabnumber = parent:GetTabNumber() + local font = skin.controls.tab_text_font + local twidth = font:getWidth(object.text) + local theight = font:getHeight(object.text) + local imagewidth = 0 + local imageheight = 0 + local texthovercolor = skin.controls.button_text_hover_color + local textnohovercolor = skin.controls.button_text_nohover_color + + if image then + image:setFilter("nearest", "nearest") + imagewidth = image:getWidth() + imageheight = image:getHeight() + object.width = imagewidth + 15 + twidth + if imageheight > theight then + parent:SetTabHeight(imageheight + 5) + object.height = imageheight + 5 + else + object.height = parent.tabheight + end + else + object.width = 10 + twidth + object.height = parent.tabheight + end + + local width = object:GetWidth() + local height = object:GetHeight() + + if tabnumber == ptabnumber then + -- button body + local gradient = skin.images["button-hover.png"] + local gradientheight = gradient:getHeight() + local scaley = height/gradientheight + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(gradient, x, y, 0, width, scaley) + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + if image then + -- button image + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x + 5, y + height/2 - imageheight/2) + -- button text + love.graphics.setFont(font) + love.graphics.setColor(texthovercolor) + skin.PrintText(text, x + imagewidth + 10, y + height/2 - theight/2) + else + -- button text + love.graphics.setFont(font) + love.graphics.setColor(texthovercolor) + skin.PrintText(text, x + 5, y + height/2 - theight/2) + end + else + -- button body + local gradient = skin.images["button-nohover.png"] + local gradientheight = gradient:getHeight() + local scaley = height/gradientheight + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(gradient, x, y, 0, width, scaley) + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + if image then + -- button image + love.graphics.setColor(1, 1, 1, 0.59) + love.graphics.draw(image, x + 5, y + height/2 - imageheight/2) + -- button text + love.graphics.setFont(font) + love.graphics.setColor(textnohovercolor) + skin.PrintText(text, x + imagewidth + 10, y + height/2 - theight/2) + else + -- button text + love.graphics.setFont(font) + love.graphics.setColor(textnohovercolor) + skin.PrintText(text, x + 5, y + height/2 - theight/2) + end + end + +end + +--[[--------------------------------------------------------- + - func: DrawMultiChoice(object) + - desc: draws the multi choice object +--]]--------------------------------------------------------- +function skin.multichoice(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local text = object:GetText() + local choice = object:GetChoice() + local image = skin.images["multichoice-arrow.png"] + local font = skin.controls.multichoice_text_font + local theight = font:getHeight("a") + local bodycolor = skin.controls.multichoice_body_color + local textcolor = skin.controls.multichoice_text_color + + image:setFilter("nearest", "nearest") + + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x + 1, y + 1, width - 2, height - 2) + + love.graphics.setColor(textcolor) + love.graphics.setFont(font) + + if choice == "" then + skin.PrintText(text, x + 5, y + height/2 - theight/2) + else + skin.PrintText(choice, x + 5, y + height/2 - theight/2) + end + + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x + width - 20, y + 5) + + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: DrawMultiChoiceList(object) + - desc: draws the multi choice list object +--]]--------------------------------------------------------- +function skin.multichoicelist(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.multichoicelist_body_color + + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: DrawOverMultiChoiceList(object) + - desc: draws over the multi choice list object +--]]--------------------------------------------------------- +function skin.multichoicelist_over(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y - 1, width, height + 1) + +end + +--[[--------------------------------------------------------- + - func: DrawMultiChoiceRow(object) + - desc: draws the multi choice row object +--]]--------------------------------------------------------- +function skin.multichoicerow(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local text = object:GetText() + local font = skin.controls.multichoicerow_text_font + local bodyhovecolor = skin.controls.multichoicerow_body_hover_color + local texthovercolor = skin.controls.multichoicerow_text_hover_color + local bodynohovercolor = skin.controls.multichoicerow_body_nohover_color + local textnohovercolor = skin.controls.multichoicerow_text_nohover_color + + love.graphics.setFont(font) + + if object.hover then + love.graphics.setColor(bodyhovecolor) + love.graphics.rectangle("fill", x, y, width, height) + love.graphics.setColor(texthovercolor) + skin.PrintText(text, x + 5, y + 5) + else + love.graphics.setColor(bodynohovercolor) + love.graphics.rectangle("fill", x, y, width, height) + love.graphics.setColor(textnohovercolor) + skin.PrintText(text, x + 5, y + 5) + end + +end + +--[[--------------------------------------------------------- + - func: DrawToolTip(object) + - desc: draws the tool tip object +--]]--------------------------------------------------------- +function skin.tooltip(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.tooltip_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: DrawText(object) + - desc: draws the text object +--]]--------------------------------------------------------- +function skin.text(object) + local textdata = object.formattedtext + local x = object.x + local y = object.y + local shadow = object.shadow + local shadowxoffset = object.shadowxoffset + local shadowyoffset = object.shadowyoffset + local shadowcolor = object.shadowcolor + local inlist, list = object:IsInList() + local printfunc = function(text, x, y) + love.graphics.print(text, math.floor(x + 0.5), math.floor(y + 0.5)) + end + + for k, v in ipairs(textdata) do + local textx = v.x + local texty = v.y + local text = v.text + local color = v.color + local font = v.font + local link = v.link + local theight = font:getHeight("a") + if inlist then + local listy = list.y + local listhieght = list.height + if (y + texty) <= (listy + listhieght) and y + ((texty + theight)) >= listy then + love.graphics.setFont(font) + if shadow then + love.graphics.setColor(unpack(shadowcolor)) + printfunc(text, x + textx + shadowxoffset, y + texty + shadowyoffset) + end + if link then + local linkcolor = v.linkcolor + local linkhovercolor = v.linkhovercolor + local hover = v.hover + if hover then + love.graphics.setColor(linkhovercolor) + else + love.graphics.setColor(linkcolor) + end + else + love.graphics.setColor(unpack(color)) + end + printfunc(text, x + textx, y + texty) + end + else + love.graphics.setFont(font) + if shadow then + love.graphics.setColor(unpack(shadowcolor)) + printfunc(text, x + textx + shadowxoffset, y + texty + shadowyoffset) + end + if link then + local linkcolor = v.linkcolor + local linkhovercolor = v.linkhovercolor + local hover = v.hover + if hover then + love.graphics.setColor(linkhovercolor) + else + love.graphics.setColor(linkcolor) + end + else + love.graphics.setColor(unpack(color)) + end + printfunc(text, x + textx, y + texty) + end + end +end + +--[[--------------------------------------------------------- + - func: DrawTextInput(object) + - desc: draws the text input object +--]]--------------------------------------------------------- +function skin.textinput(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local font = object:GetFont() + local focus = object:GetFocus() + local showindicator = object:GetIndicatorVisibility() + local alltextselected = object:IsAllTextSelected() + local textx = object:GetTextX() + local texty = object:GetTextY() + local text = object:GetText() + local multiline = object:GetMultiLine() + local lines = object:GetLines() + local placeholder = object:GetPlaceholderText() + local offsetx = object:GetOffsetX() + local offsety = object:GetOffsetY() + local indicatorx = object:GetIndicatorX() + local indicatory = object:GetIndicatorY() + local vbar = object:HasVerticalScrollBar() + local hbar = object:HasHorizontalScrollBar() + local linenumbers = object:GetLineNumbersEnabled() + local itemwidth = object:GetItemWidth() + local masked = object:GetMasked() + local theight = font:getHeight("a") + local bodycolor = skin.controls.textinput_body_color + local textnormalcolor = skin.controls.textinput_text_normal_color + local textplaceholdercolor = skin.controls.textinput_text_placeholder_color + local textselectedcolor = skin.controls.textinput_text_selected_color + local highlightbarcolor = skin.controls.textinput_highlight_bar_color + local indicatorcolor = skin.controls.textinput_indicator_color + + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x, y, width, height) + + if alltextselected then + local bary = 0 + if multiline then + for i=1, #lines do + local str = lines[i] + if masked then + str = loveframes.utf8.gsub(str, ".", "*") + end + local twidth = font:getWidth(str) + if twidth == 0 then + twidth = 5 + end + love.graphics.setColor(highlightbarcolor) + love.graphics.rectangle("fill", textx, texty + bary, twidth, theight) + bary = bary + theight + end + else + local twidth = 0 + if masked then + local maskchar = object:GetMaskChar() + twidth = font:getWidth(loveframes.utf8.gsub(text, ".", maskchar)) + else + twidth = font:getWidth(text) + end + love.graphics.setColor(highlightbarcolor) + love.graphics.rectangle("fill", textx, texty, twidth, theight) + end + end + + if showindicator and focus then + love.graphics.setColor(indicatorcolor) + love.graphics.rectangle("fill", indicatorx, indicatory, 1, theight) + end + + if not multiline then + object:SetTextOffsetY(height/2 - theight/2) + if offsetx ~= 0 then + object:SetTextOffsetX(0) + else + object:SetTextOffsetX(5) + end + else + if vbar then + if offsety ~= 0 then + if hbar then + object:SetTextOffsetY(5) + else + object:SetTextOffsetY(-5) + end + else + object:SetTextOffsetY(5) + end + else + object:SetTextOffsetY(5) + end + + if hbar then + if offsety ~= 0 then + if linenumbers then + local panel = object:GetLineNumbersPanel() + if vbar then + object:SetTextOffsetX(5) + else + object:SetTextOffsetX(-5) + end + else + if vbar then + object:SetTextOffsetX(5) + else + object:SetTextOffsetX(-5) + end + end + else + object:SetTextOffsetX(5) + end + else + object:SetTextOffsetX(5) + end + + end + + textx = object:GetTextX() + texty = object:GetTextY() + + love.graphics.setFont(font) + + if alltextselected then + love.graphics.setColor(textselectedcolor) + elseif #lines == 1 and lines[1] == "" then + love.graphics.setColor(textplaceholdercolor) + else + love.graphics.setColor(textnormalcolor) + end + + local str = "" + if multiline then + for i=1, #lines do + str = lines[i] + if masked then + local maskchar = object:GetMaskChar() + str = loveframes.utf8.gsub(str, ".", maskchar) + end + skin.PrintText(#str > 0 and str or (#lines == 1 and placeholder or ""), textx, texty + theight * i - theight) + end + else + str = lines[1] + if masked then + local maskchar = object:GetMaskChar() + str = loveframes.utf8.gsub(str, ".", maskchar) + end + skin.PrintText(#str > 0 and str or placeholder, textx, texty) + end + + love.graphics.setColor(0.9, 0.9, 0.9, 1) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, height - 2) + +end + +--[[--------------------------------------------------------- + - func: DrawOverTextInput(object) + - desc: draws over the text input object +--]]--------------------------------------------------------- +function skin.textinput_over(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: DrawScrollButton(object) + - desc: draws the scroll button object +--]]--------------------------------------------------------- +function skin.scrollbutton(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 scrolltype = object:GetScrollType() + local down = object.down + local bodydowncolor = skin.controls.button_body_down_color + local bodyhovercolor = skin.controls.button_body_hover_color + local bodynohovercolor = skin.controls.button_body_nohover_color + + if down then + -- button body + local image = skin.images["button-down.png"] + local imageheight = image:getHeight() + local scaley = height/imageheight + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + + elseif hover then + -- button body + local image = skin.images["button-hover.png"] + local imageheight = image:getHeight() + local scaley = height/imageheight + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + else + -- button body + local image = skin.images["button-nohover.png"] + local imageheight = image:getHeight() + local scaley = height/imageheight + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + end + + if scrolltype == "up" then + local image = skin.images["arrow-up.png"] + local imagewidth = image:getWidth() + local imageheight = image:getHeight() + image:setFilter("nearest", "nearest") + if hover then + love.graphics.setColor(1, 1, 1, 1) + else + love.graphics.setColor(1, 1, 1, 0.59) + end + love.graphics.draw(image, x + width/2 - imagewidth/2, y + height/2 - imageheight/2) + elseif scrolltype == "down" then + local image = skin.images["arrow-down.png"] + local imagewidth = image:getWidth() + local imageheight = image:getHeight() + image:setFilter("nearest", "nearest") + if hover then + love.graphics.setColor(1, 1, 1, 1) + else + love.graphics.setColor(1, 1, 1, 0.59) + end + love.graphics.draw(image, x + width/2 - imagewidth/2, y + height/2 - imageheight/2) + elseif scrolltype == "left" then + local image = skin.images["arrow-left.png"] + local imagewidth = image:getWidth() + local imageheight = image:getHeight() + image:setFilter("nearest", "nearest") + if hover then + love.graphics.setColor(1, 1, 1, 1) + else + love.graphics.setColor(1, 1, 1, 0.59) + end + love.graphics.draw(image, x + width/2 - imagewidth/2, y + height/2 - imageheight/2) + elseif scrolltype == "right" then + local image = skin.images["arrow-right.png"] + local imagewidth = image:getWidth() + local imageheight = image:getHeight() + image:setFilter("nearest", "nearest") + if hover then + love.graphics.setColor(1, 1, 1, 1) + else + love.graphics.setColor(1, 1, 1, 0.59) + end + love.graphics.draw(image, x + width/2 - imagewidth/2, y + height/2 - imageheight/2) + end + +end + +--[[--------------------------------------------------------- + - func: skin.DrawSlider(object) + - desc: draws the slider object +--]]--------------------------------------------------------- +function skin.slider(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local slidtype = object:GetSlideType() + local baroutlinecolor = skin.controls.slider_bar_outline_color + + if slidtype == "horizontal" then + love.graphics.setColor(baroutlinecolor) + love.graphics.rectangle("fill", x, y + height/2 - 5, width, 10) + love.graphics.setColor(bordercolor) + love.graphics.rectangle("fill", x + 5, y + height/2, width - 10, 1) + elseif slidtype == "vertical" then + love.graphics.setColor(baroutlinecolor) + love.graphics.rectangle("fill", x + width/2 - 5, y, 10, height) + love.graphics.setColor(bordercolor) + love.graphics.rectangle("fill", x + width/2, y + 5, 1, height - 10) + end + +end + +--[[--------------------------------------------------------- + - func: skin.DrawSliderButton(object) + - desc: draws the slider button object +--]]--------------------------------------------------------- +function skin.sliderbutton(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 down = object.down + local parent = object:GetParent() + local enabled = parent:GetEnabled() + local bodydowncolor = skin.controls.button_body_down_color + local bodyhovercolor = skin.controls.button_body_hover_color + local bodynohvercolor = skin.controls.button_body_nohover_color + + if not enabled then + local image = skin.images["button-unclickable.png"] + local imageheight = image:getHeight() + local scaley = height/imageheight + -- button body + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + return + end + + if down then + -- button body + local image = skin.images["button-down.png"] + local imageheight = image:getHeight() + local scaley = height/imageheight + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + elseif hover then + -- button body + local image = skin.images["button-hover.png"] + local imageheight = image:getHeight() + local scaley = height/imageheight + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + else + -- button body + local image = skin.images["button-nohover.png"] + local imageheight = image:getHeight() + local scaley = height/imageheight + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + -- button border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + end + +end + +--[[--------------------------------------------------------- + - func: skin.DrawCheckBox(object) + - desc: draws the check box object +--]]--------------------------------------------------------- +function skin.checkbox(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetBoxWidth() + local height = object:GetBoxHeight() + local checked = object:GetChecked() + local hover = object:GetHover() + local bodycolor = skin.controls.checkbox_body_color + local checkcolor = skin.controls.checkbox_check_color + + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x, y, width, height) + + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + + if checked then + love.graphics.setColor(checkcolor) + love.graphics.rectangle("fill", x + 4, y + 4, width - 8, height - 8) + end + + if hover then + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x + 4, y + 4, width - 8, height - 8) + end + +end + +--[[--------------------------------------------------------- + - func: skin.DrawCheckBox(object) + - desc: draws the radio button object +--]]--------------------------------------------------------- +function skin.radiobutton(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetBoxWidth() + local height = object:GetBoxHeight() + local checked = object:GetChecked() + local hover = object:GetHover() + local bodycolor = skin.controls.radiobutton_body_color + local checkcolor = skin.controls.radiobutton_check_color + local inner_border = skin.controls.radiobutton_inner_border_color + + love.graphics.setColor(bordercolor) + love.graphics.setLineStyle("smooth") + love.graphics.setLineWidth(1) + love.graphics.circle("line", x + 10, y + 10, 8, 15) + + if checked then + love.graphics.setColor(checkcolor) + love.graphics.circle("fill", x + 10, y + 10, 5, 360) + love.graphics.setColor(inner_border) + love.graphics.circle("line", x + 10, y + 10, 5, 360) + end + + if hover then + love.graphics.setColor(bordercolor) + love.graphics.circle("line", x + 10, y + 10, 5, 360) + end + +end + +--[[--------------------------------------------------------- + - func: skin.DrawCollapsibleCategory(object) + - desc: draws the collapsible category object +--]]--------------------------------------------------------- +function skin.collapsiblecategory(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local text = object:GetText() + local open = object:GetOpen() + local textcolor = skin.controls.collapsiblecategory_text_color + local font = skin.controls.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(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(topbarimage, x, y, 0, topbarimage_scalex, topbarimage_scaley) + + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + + love.graphics.setColor(1, 1, 1, 1) + if open then + local icon = skin.images["collapse.png"] + icon:setFilter("nearest", "nearest") + love.graphics.draw(icon, x + width - 21, y + 5) + love.graphics.setColor(1, 1, 1, 0.27) + 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(1, 1, 1, 0.27) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, 23) + end + + love.graphics.setFont(font) + love.graphics.setColor(textcolor) + skin.PrintText(text, x + 5, y + 5) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawColumnList(object) + - desc: draws the column list object +--]]--------------------------------------------------------- +function skin.columnlist(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.columnlist_body_color + + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawColumnListHeader(object) + - desc: draws the column list header object +--]]--------------------------------------------------------- +function skin.columnlistheader(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 down = object.down + local font = skin.controls.columnlistheader_text_font + local theight = font:getHeight(object.name) + local bodydowncolor = skin.controls.columnlistheader_body_down_color + local textdowncolor = skin.controls.columnlistheader_text_down_color + local bodyhovercolor = skin.controls.columnlistheader_body_hover_color + local textdowncolor = skin.controls.columnlistheader_text_hover_color + local nohovercolor = skin.controls.columnlistheader_body_nohover_color + local textnohovercolor = skin.controls.columnlistheader_text_nohover_color + + local name = ParseHeaderText(object:GetName(), x, width, x + width/2, twidth) + local twidth = font:getWidth(name) + + if down then + local image = skin.images["button-down.png"] + local imageheight = image:getHeight() + local scaley = height/imageheight + -- header body + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + -- header name + love.graphics.setFont(font) + love.graphics.setColor(textdowncolor) + skin.PrintText(name, x + width/2 - twidth/2, y + height/2 - theight/2) + -- header border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + elseif hover then + local image = skin.images["button-hover.png"] + local imageheight = image:getHeight() + local scaley = height/imageheight + -- header body + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + -- header name + love.graphics.setFont(font) + love.graphics.setColor(textdowncolor) + skin.PrintText(name, x + width/2 - twidth/2, y + height/2 - theight/2) + -- header border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + else + local image = skin.images["button-nohover.png"] + local imageheight = image:getHeight() + local scaley = height/imageheight + -- header body + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + -- header name + love.graphics.setFont(font) + love.graphics.setColor(textnohovercolor) + skin.PrintText(name, x + width/2 - twidth/2, y + height/2 - theight/2) + -- header border + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + end + +end + +--[[--------------------------------------------------------- + - func: skin.DrawColumnListArea(object) + - desc: draws the column list area object +--]]--------------------------------------------------------- +function skin.columnlistarea(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.columnlistarea_body_color + + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x, y, width, height) + + local cheight = 0 + local columns = object:GetParent():GetChildren() + if #columns > 0 then + cheight = columns[1]:GetHeight() + end + + local image = skin.images["button-nohover.png"] + local scaley = cheight/image:getHeight() + + -- header body + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, x, y, 0, width, scaley) + + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, cheight, true, false, true, true) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawOverColumnListArea(object) + - desc: draws over the column list area object +--]]--------------------------------------------------------- +function skin.columnlistarea_over(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawColumnListRow(object) + - desc: draws the column list row object +--]]--------------------------------------------------------- +function skin.columnlistrow(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local colorindex = object:GetColorIndex() + local font = object:GetFont() + local columndata = object:GetColumnData() + local textx = object:GetTextX() + local texty = object:GetTextY() + local parent = object:GetParent() + local theight = font:getHeight("a") + local hover = object:GetHover() + local selected = object:GetSelected() + local body1color = skin.controls.columnlistrow_body1_color + local body2color = skin.controls.columnlistrow_body2_color + local bodyhovercolor = skin.controls.columnlistrow_body_hover_color + local bodyselectedcolor = skin.controls.columnlistrow_body_selected_color + local textcolor = skin.controls.columnlistrow_text_color + local texthovercolor = skin.controls.columnlistrow_text_hover_color + local textselectedcolor = skin.controls.columnlistrow_text_selected_color + + object:SetTextPos(5, height/2 - theight/2) + + if selected then + love.graphics.setColor(bodyselectedcolor) + love.graphics.rectangle("fill", x, y, width, height) + elseif hover then + love.graphics.setColor(bodyhovercolor) + love.graphics.rectangle("fill", x, y, width, height) + elseif colorindex == 1 then + love.graphics.setColor(body1color) + love.graphics.rectangle("fill", x, y, width, height) + else + love.graphics.setColor(body2color) + love.graphics.rectangle("fill", x, y, width, height) + end + + love.graphics.setFont(font) + if selected then + love.graphics.setColor(textselectedcolor) + elseif hover then + love.graphics.setColor(texthovercolor) + else + love.graphics.setColor(textcolor) + end + for k, v in ipairs(columndata) do + local rwidth = parent.parent:GetColumnWidth(k) + if rwidth then + local text = ParseRowText(v, x, rwidth, x, textx) + skin.PrintText(text, x + textx, y + texty) + x = x + parent.parent.children[k]:GetWidth() + else + break + end + end + +end + +--[[--------------------------------------------------------- + - func: skin.DrawModalBackground(object) + - desc: draws the modal background object +--]]--------------------------------------------------------- +function skin.modalbackground(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.modalbackground_body_color + + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawLineNumbersPanel(object) + - desc: draws the line numbers panel object +--]]--------------------------------------------------------- +function skin.linenumberspanel(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local offsety = object:GetOffsetY() + local parent = object:GetParent() + local lines = parent:GetLines() + local font = parent:GetFont() + local theight = font:getHeight("a") + local textcolor = skin.controls.linenumberspanel_text_color + local bodycolor = skin.controls.linenumberspanel_body_color + + object:SetWidth(10 + font:getWidth(#lines)) + love.graphics.setFont(font) + + love.graphics.setColor(bodycolor) + love.graphics.rectangle("fill", x, y, width, height) + + love.graphics.setColor(bordercolor) + --skin.OutlinedRectangle(x, y, width, height, true, true, true, false) + + local startline = math.ceil(offsety / theight) + if startline < 1 then + startline = 1 + end + local endline = math.ceil(startline + (height / theight)) + 1 + if endline > #lines then + endline = #lines + end + + for i=startline, endline do + love.graphics.setColor(textcolor) + skin.PrintText(i, x + 5, (y + (theight * (i - 1))) - offsety) + end + +end + +--[[--------------------------------------------------------- + - func: skin.DrawNumberBox(object) + - desc: draws the numberbox object +--]]--------------------------------------------------------- +function skin.numberbox(object) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawGrid(object) + - desc: draws the grid object +--]]--------------------------------------------------------- +function skin.grid(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.grid_body_color + + love.graphics.setColor(bordercolor) + skin.OutlinedRectangle(x, y, width, height) + + local cx = x + local cy = y + local cw = object.cellwidth + (object.cellpadding * 2) + local ch = object.cellheight + (object.cellpadding * 2) + + for i=1, object.rows do + for n=1, object.columns do + local ovt = false + local ovl = false + if i > 1 then + ovt = true + end + 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 + cx = x + cy = cy + ch + end + +end + +--[[--------------------------------------------------------- + - func: skin.DrawForm(object) + - desc: draws the form object +--]]--------------------------------------------------------- +function skin.form(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local topmargin = object.topmargin + local name = object.name + local font = skin.controls.form_text_font + local textcolor = skin.controls.form_text_color + local twidth = font:getWidth(name) + + love.graphics.setFont(font) + love.graphics.setColor(textcolor) + skin.PrintText(name, x + 7, y) + + love.graphics.setColor(bordercolor) + love.graphics.rectangle("fill", x, y + 7, 5, 1) + love.graphics.rectangle("fill", x + twidth + 9, y + 7, width - (twidth + 9), 1) + love.graphics.rectangle("fill", x, y + height, width, 1) + love.graphics.rectangle("fill", x, y + 7, 1, height - 7) + love.graphics.rectangle("fill", x + width - 1, y + 7, 1, height - 7) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawMenu(object) + - desc: draws the menu object +--]]--------------------------------------------------------- +function skin.menu(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.menuoption(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 = skin.controls.smallfont:getWidth(text) + + + if option_type == "divider" then + love.graphics.setColor(0.78, 0.78, 0.78, 1) + love.graphics.rectangle("fill", x + 4, y + 2, width - 8, 1) + object.contentheight = 10 + else + love.graphics.setFont(skin.controls.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) + skin.PrintText(text, x + 26, y + 5) + else + love.graphics.setColor(text_color) + skin.PrintText(text, x + 26, y + 5) + end + if icon then + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(icon, x + 5, y + 5) + end + object.contentwidth = twidth + 31 + object.contentheight = 25 + end + +end + +function skin.tree(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(0.78, 0.78, 0.78, 1) + love.graphics.rectangle("fill", x, y, width, height) + +end + +function skin.treenode(object) + + local icon = object.icon + local buttonimage = skin.images["tree-node-button-open.png"] + local width = 0 + local x = object.x + local leftpadding = 15 * object.level + + if object.level > 0 then + leftpadding = leftpadding + buttonimage:getWidth() + 5 + else + leftpadding = buttonimage:getWidth() + 5 + end + + local iconwidth + if icon then + iconwidth = icon:getWidth() + end + + local twidth = loveframes.basicfont:getWidth(object.text) + local theight = loveframes.basicfont:getHeight(object.text) + + if object.tree.selectednode == object then + love.graphics.setColor(0.4, 0.55, 1, 1) + love.graphics.rectangle("fill", x + leftpadding + 2 + iconwidth, object.y + 2, twidth, theight) + end + + width = width + iconwidth + loveframes.basicfont:getWidth(object.text) + leftpadding + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(icon, x + leftpadding, object.y) + love.graphics.setFont(loveframes.basicfont) + love.graphics.setColor(0, 0, 0, 1) + skin.PrintText(object.text, x + leftpadding + 2 + iconwidth, object.y + 2) + + object:SetWidth(width + 5) + +end + +function skin.treenodebutton(object) + + local leftpadding = 15 * object.parent.level + local image + + if object.parent.open then + image = skin.images["tree-node-button-close.png"] + else + image = skin.images["tree-node-button-open.png"] + end + + image:setFilter("nearest", "nearest") + + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(image, object.x, object.y) + + object:SetPos(2 + leftpadding, 3) + object:SetSize(image:getWidth(), image:getHeight()) + +end + +-- register the skin +loveframes.RegisterSkin(skin) + +---------- module end ---------- +end diff --git a/loveframes/skins/Default/images/arrow-down.png b/loveframes/skins/Default/images/arrow-down.png new file mode 100644 index 0000000000000000000000000000000000000000..504f52747977672b6d4b18027d45b48d1d924d27 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1TyJY5_^ zEP9g@Bv_ky{`~*H|BroQfPbgr4^v@-7K^hMJc_=?lN5RX|Noz_;Qd)cL5_hze_2uX T&tzX+pl$|FS3j3^P64nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1SXJzX3_ zEP9g@BqSgF|Noy?B=aATs_!zHoXW5%Z4$4;^`7$#YBG=Rdu|eJ*FJUf8%91 literal 0 HcmV?d00001 diff --git a/loveframes/skins/Default/images/arrow-right.png b/loveframes/skins/Default/images/arrow-right.png new file mode 100644 index 0000000000000000000000000000000000000000..1ed3fa4433fc481c0d1f4b6977738945b141c4b9 GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1T?JY5_^ zEP9g@B=$Y{|Np=26sZsMm7M=6GgP+yac5m3{YhRp!L+55#dv@4qo%4!CW|E lpSa9px}Y)VtTQ(QL(}{Om%9f4*8xpq@O1TaS?83{1OT$YJq`c> literal 0 HcmV?d00001 diff --git a/loveframes/skins/Default/images/arrow-up.png b/loveframes/skins/Default/images/arrow-up.png new file mode 100644 index 0000000000000000000000000000000000000000..f6b9375110e2ecba531f0b82bdbbd923e1fb7587 GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1U_JY5_^ zEP9g@Bv`kw{{R0!|HuFT_3Wy%5*tjMFPKbDHebK8mzoE PK%ESpu6{1-oD!M<<&QG2 literal 0 HcmV?d00001 diff --git a/loveframes/skins/Default/images/check-off.png b/loveframes/skins/Default/images/check-off.png new file mode 100644 index 0000000000000000000000000000000000000000..6e18c0e2f38c4e07e0a726884d09b873292ab66f GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1UtJzX3_ zEPCHg-pJUXz;i$;|AlGaqth|YJC*fp7>IZ|V9$D&-4}HAIdfxUv%~rsKSF>;GI+ZBxvX4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1TIJY5_^ zEPBsQ+Q{2rAi%6YvpF>*aYD~YgY$Ck&a7PmogEv#EPZ?V^orHHe#b4;^W;rf$T;Yu;gwbt>DRC9?GYIzHhWUwz5~lQxzBzVx8T=bnj|YJm1I Nc)I$ztaD0e0sv9?OfLWc literal 0 HcmV?d00001 diff --git a/loveframes/skins/Default/images/close.png b/loveframes/skins/Default/images/close.png new file mode 100644 index 0000000000000000000000000000000000000000..a1605ddea9c00a5d7fa390f5a5a5cf9d99dc6de0 GIT binary patch literal 241 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1U@JY5_^ zEPC%wa^z}I5MfSbN8vzZ({#1uGk1!sGFdJ&vpYQ3+omQ_ fcWh(-m$NaO(|_iMmU!s`ZD#Ov^>bP0l+XkKUt&@% literal 0 HcmV?d00001 diff --git a/loveframes/skins/Default/images/collapse.png b/loveframes/skins/Default/images/collapse.png new file mode 100644 index 0000000000000000000000000000000000000000..ad22eb9d258af660548548deef493f2afe9e4cc8 GIT binary patch literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1T)JzX3_ zEP9g@Bv=nK7%bxc^Z);U`#9d79*wFQE8Z>&G*Dq=c#_D%GC8X11yDJIr>mdKI;Vst E0FP)chyVZp literal 0 HcmV?d00001 diff --git a/loveframes/skins/Default/images/drawing.svg b/loveframes/skins/Default/images/drawing.svg new file mode 100644 index 0000000..9ee9086 --- /dev/null +++ b/loveframes/skins/Default/images/drawing.svg @@ -0,0 +1,519 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/loveframes/skins/Default/images/expand.png b/loveframes/skins/Default/images/expand.png new file mode 100644 index 0000000000000000000000000000000000000000..c1bd253fc5c4aad5b7294fe0491bf81d9fc504dd GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1U_JY5_^ zEP9g@Bv>mB)@vMC-qso9tzp(67~3#mvZSPB;Fo|mOnVYCSRQF4Brq@}*$Dr6wYt|3 PsFT6d)z4*}Q$iB}dZICh literal 0 HcmV?d00001 diff --git a/loveframes/skins/Default/images/multichoice-arrow.png b/loveframes/skins/Default/images/multichoice-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..710b2e4e2a2b54a318a39d04ad59261ac036e2f9 GIT binary patch literal 241 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1U@JY5_^ zEPCJe@8)eV;9=#}P1>Wu8#--4O1F-)<2R-f5tl;~521q%-#D~47lXp)%mEn7PxJ4yI36IY2#iaxJHGM eWBmjEROZ&kng0*1eYgl{GlQqApUXO@geCxE&Q4AM literal 0 HcmV?d00001 diff --git a/loveframes/skins/Default/images/radio-off.png b/loveframes/skins/Default/images/radio-off.png new file mode 100644 index 0000000000000000000000000000000000000000..4ae6d7b4c66738ce512830648533a597a957318d GIT binary patch literal 429 zcmV;e0aE^nP)2khloxfddmCOMpP|aU67g3F#1Q`Xo0ssQbT76$EGOAbGEQ>ZVw_}@ zh;LBRV0UlS95&q!yjBu|Fq{A9M-4NE8wGQ|3eU1X(Fz68NH*ToX zR``j*90dmW(cut}<|wd=!)o?C!n)bN@gCk`wX3Sncx&RYS>B>r?whI__f}rOdz_nC z`Q)0;TeyYws`}MIRb8|dzM42}14Asf7~)wQ`%4dB*&@j>$xf2vBquG7lWZq>FrEJo X;WLT3`EIK)00000NkvXXu0mjfCgrw; literal 0 HcmV?d00001 diff --git a/loveframes/skins/Default/images/radio-on.png b/loveframes/skins/Default/images/radio-on.png new file mode 100644 index 0000000000000000000000000000000000000000..161a23dfb716611656214f06c382da507693eca5 GIT binary patch literal 365 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1TEdAc}; zSoF@F?C8bpDBya(Mho}NIsZV?WL>Gahn|Ao-I+SZHsW`? zF8gpB^K(hP`v2bKgnAqP@9d#q7LQ7)lPqz`lKf*KQNx> z-*}wu>^AS$rd|(}C(mY3|M<<*?X%yU4eNZk4_BsfuNgdD{an^L HB{Ts5T0@N> literal 0 HcmV?d00001 diff --git a/loveframes/skins/Default/images/slider.png b/loveframes/skins/Default/images/slider.png new file mode 100644 index 0000000000000000000000000000000000000000..fa14eddcee63fb4ec55497ade15c519bfdf0f0e7 GIT binary patch literal 477 zcmV<30V4j1P)<(8?@17CWyD>u$(}%go$4=gej9y-Zn>)g;f7jFSAW zKB}?v)A*LSlw_D>ocT6RvYBM5=ars}*SLWLyu%*8Roq!z#WgJAEpC-k{`3Mv+`|t% z#+NyXu3!VFF)XFrFG*JM35R%i1i2M?gbtS$a2F@A(~uW1z#4*GY++n6?{O1%I;>aH zhvt<5ZsR0Q)%~Ek->d6-hvjBSq~6B*&t2(iiqkeLcG&DoAL|;mGYw#OhCmzZ zv0por&x0!sU<=#$S$!L?n)@ERQ<7Z3N5?PYIg>ILT)9j47=4Ab)@i*s|V4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1S7JzX3_ zEPCHg+$h*!z;on@OtOI>&!mHMZC$1^3I!L|Jax0WZ~tm7-}T9_M6;OGt4{{pZDGt1 z{h{2HEGH4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1TIJY5_^ zEPCHgKFHf(z{9LRx4AQ60^hxNg?mnQhb?{7`r-OU;hS8q7KY7VyrOyq>x~F!&Z~0L zf{X^UJiBM_Pbp} hx + hwidth then + if #str > 1 then + return ParseHeaderText(loveframes.utf8.sub(str, 1, #str - 1), hx, hwidth, tx, twidth) + else + return str + end + else + return str + end + +end + +local function ParseRowText(str, rx, rwidth, tx1, tx2) + + local twidth = love.graphics.getFont():getWidth(str) + + if (tx1 + tx2) + twidth > rx + rwidth then + if #str > 1 then + return ParseRowText(loveframes.utf8.sub(str, 1, #str - 1), rx, rwidth, tx1, tx2) + else + return str + end + else + return str + end + +end + +function skin.PrintText(text, x, y) + love.graphics.print(text, math.floor(x + 0.5), math.floor(y + 0.5)) +end + +--[[--------------------------------------------------------- + - func: OutlinedRectangle(x, y, width, height, ovt, ovb, ovl, ovr) + - desc: creates and outlined rectangle +--]]--------------------------------------------------------- +function skin.OutlinedRectangle(x, y, width, height, ovt, ovb, ovl, ovr) + + local ovt = ovt or false + local ovb = ovb or false + local ovl = ovl or false + local ovr = ovr or false + + -- top + if not ovt then + love.graphics.rectangle("fill", x, y, width, 1) + end + + -- bottom + if not ovb then + love.graphics.rectangle("fill", x, y + height - 1, width, 1) + end + + -- left + if not ovl then + love.graphics.rectangle("fill", x, y, 1, height) + end + + -- right + if not ovr then + love.graphics.rectangle("fill", x + width - 1, y, 1, height) + end + +end + +--[[--------------------------------------------------------- + - func: DrawFrame(object) + - desc: draws the frame object +--]]--------------------------------------------------------- +function skin.frame(object) + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local hover = object:IsTopChild() + local name = object:GetName() + local icon = object:GetIcon() + local font = skin.controls.smallfont + + local body = skin.controls.color_back0 + local top = hover and skin.controls.color_active or skin.controls.color_fore0 + local fore = skin.controls.color_back0 + local border = skin.controls.color_back1 + + -- frame body + love.graphics.setColor(body) + love.graphics.rectangle("fill", x, y, width, height) + + -- frame top bar + love.graphics.setColor(top) + love.graphics.rectangle("fill", x, y, width, 25) + + -- frame name section + love.graphics.setFont(font) + + if icon then + local iconwidth = icon:getWidth() + local iconheight = icon:getHeight() + --icon:setFilter("nearest", "nearest") + love.graphics.setColor(skin.controls.color_image) + love.graphics.draw(icon, x + 5, y + 5) + love.graphics.setColor(fore) + skin.PrintText(name, x + iconwidth + 10, y + 5) + else + love.graphics.setColor(fore) + skin.PrintText(name, x + 5, y + 5) + end + + -- frame border + love.graphics.setColor(border) + skin.OutlinedRectangle(x, y, width, height) + love.graphics.setColor(border) + skin.OutlinedRectangle(x, y, width, height) +end + +--[[--------------------------------------------------------- + - func: DrawButton(object) + - desc: draws the button object +--]]--------------------------------------------------------- + +function skin.button(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 font = skin.controls.smallfont + local twidth = font:getWidth(object.text) + local theight = font:getHeight(object.text) + local down = object:GetDown() + local checked = object.checked + local enabled = object:GetEnabled() + local clickable = object:GetClickable() + local back, fore, border + + love.graphics.setFont(font) + + if not enabled or not clickable then + back = skin.controls.color_back1 + fore = skin.controls.color_back2 + border = skin.controls.color_back2 + -- button body + love.graphics.setColor(back) + love.graphics.rectangle("fill", x, y, width, height) + -- button text + love.graphics.setFont(font) + love.graphics.setColor(skin.controls.color_back3) + skin.PrintText(text, x + width/2 - twidth/2, y + height/2 - theight/2) + -- button border + love.graphics.setColor(border) + skin.OutlinedRectangle(x, y, width, height) + return + end + + if object.toggleable then + if hover then + if down then + back = skin.controls.color_active + fore = skin.controls.color_back0 + border = skin.controls.color_fore2 + else + back = skin.controls.color_active + fore = skin.controls.color_back0 + border = skin.controls.color_fore1 + end + else + if object.toggle then + back = skin.controls.color_fore0 + fore = skin.controls.color_back0 + border = skin.controls.color_fore2 + else + back = skin.controls.color_back2 + fore = skin.controls.color_fore0 + border = skin.controls.color_fore0 + end + end + + -- button body + love.graphics.setColor(back) + love.graphics.rectangle("fill", x, y, width, height) + -- button text + love.graphics.setColor(fore) + skin.PrintText(text, x + width/2 - twidth/2, y + height/2 - theight/2) + -- button border + love.graphics.setColor(border) + skin.OutlinedRectangle(x, y, width, height) + + else + if down or checked then + back = skin.controls.color_fore0 + fore = skin.controls.color_back0 + border = skin.controls.color_fore2 + elseif hover then + back = skin.controls.color_active + fore = skin.controls.color_back0 + border = skin.controls.color_fore1 + else + back = skin.controls.color_back2 + fore = skin.controls.color_fore0 + border = skin.controls.color_fore0 + end + + -- button body + love.graphics.setColor(back) + love.graphics.rectangle("fill", x, y, width, height) + -- button text + if object.image then + love.graphics.setColor(skin.controls.color_image) + love.graphics.draw(object.image, x + 5, y + height/2 - object.image:getHeight()/2) + end + + love.graphics.setColor(fore) + skin.PrintText(text, x + width/2 - twidth/2, y + height/2 - theight/2) + -- button border + love.graphics.setColor(border) + skin.OutlinedRectangle(x, y, width, height) + end + + love.graphics.setColor(skin.controls.color_back0) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, height - 2) + +end + +--[[--------------------------------------------------------- + - func: DrawCloseButton(object) + - desc: draws the close button object +--]]--------------------------------------------------------- +function skin.closebutton(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local parent = object.parent + local parentwidth = parent:GetWidth() + local hover = object:GetHover() + local down = object.down + local image = skin.images["close.png"] + local fore + + --image:setFilter("nearest", "nearest") + + if down then + fore = skin.controls.color_back2 + elseif hover then + fore = skin.controls.color_back1 + else + fore = skin.controls.color_back0 + end + + love.graphics.setColor(fore) + love.graphics.draw(image, x, y) +end + +--[[--------------------------------------------------------- + - func: DrawImage(object) + - desc: draws the image object +--]]--------------------------------------------------------- +function skin.image(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local orientation = object:GetOrientation() + local scalex = object:GetScaleX() + local scaley = object:GetScaleY() + local offsetx = object:GetOffsetX() + local offsety = object:GetOffsetY() + local shearx = object:GetShearX() + local sheary = object:GetShearY() + local image = object.image + local imagecolor = object.imagecolor or skin.controls.color_image + local stretch = object.stretch + + if stretch then + scalex, scaley = object:GetWidth() / image:getWidth(), object:GetHeight() / image:getHeight() + end + + love.graphics.setColor(imagecolor) + love.graphics.draw(image, x, y, orientation, scalex, scaley, offsetx, offsety, shearx, sheary) + +end + +--[[--------------------------------------------------------- + - func: DrawImageButton(object) + - desc: draws the image button object +--]]--------------------------------------------------------- +function skin.imagebutton(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local text = object:GetText() + local hover = object:GetHover() + local image = object:GetImage() + local imagecolor = object.imagecolor or skin.controls.color_image + local down = object.down + local font = skin.controls.imagebuttonfont + local twidth = font:getWidth(object.text) + local theight = font:getHeight(object.text) + local checked = object.checked + + local fore1, fore2 = skin.controls.color_back0 + + if down then + if image then + love.graphics.setColor(imagecolor) + love.graphics.draw(image, x + 1, y + 1) + end + love.graphics.setFont(font) + love.graphics.setColor(skin.controls.color_back2) + skin.PrintText(text, x + width/2 - twidth/2 + 1, y + height - theight - 5 + 1) + love.graphics.setColor(skin.controls.color_fore3) + skin.PrintText(text, x + width/2 - twidth/2 + 1, y + height - theight - 6 + 1) + elseif hover then + if image then + love.graphics.setColor(imagecolor) + love.graphics.draw(image, x, y) + end + love.graphics.setFont(font) + love.graphics.setColor(skin.controls.color_back1) + skin.PrintText(text, x + width/2 - twidth/2, y + height - theight - 5) + love.graphics.setColor(skin.controls.color_fore2) + skin.PrintText(text, x + width/2 - twidth/2, y + height - theight - 6) + else + if image then + love.graphics.setColor(imagecolor) + love.graphics.draw(image, x, y) + end + love.graphics.setFont(font) + love.graphics.setColor(skin.controls.color_back0) + skin.PrintText(text, x + width/2 - twidth/2, y + height - theight - 5) + love.graphics.setColor(skin.controls.color_fore0) + skin.PrintText(text, x + width/2 - twidth/2, y + height - theight - 6) + end + if checked == true then + love.graphics.setColor(skin.controls.color_back2) + love.graphics.setLineWidth(3) + love.graphics.setLineStyle("smooth") + love.graphics.rectangle("line", x+1, y+1, width-2, height-2) + end + +end + +--[[--------------------------------------------------------- + - func: DrawProgressBar(object) + - desc: draws the progress bar object +--]]--------------------------------------------------------- +function skin.progressbar(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local value = object:GetValue() + local max = object:GetMax() + local text = object:GetText() + local barwidth = object:GetBarWidth() + local font = skin.controls.smallfont + local twidth = font:getWidth(text) + local theight = font:getHeight("m") + + -- progress bar body + love.graphics.setColor(skin.controls.color_back0) + love.graphics.rectangle("fill", x, y, width, height) + love.graphics.setColor(skin.controls.color_back2) + love.graphics.rectangle("fill", x, y, barwidth, height) + love.graphics.setFont(font) + love.graphics.setColor(skin.controls.color_fore0) + skin.PrintText(text, x + width/2 - twidth/2, y + height/2 - theight/2) + + -- progress bar border + love.graphics.setColor(skin.controls.color_fore0) + skin.OutlinedRectangle(x, y, width, height) + + object:SetText(value .. "/" ..max) + +end + +--[[--------------------------------------------------------- + - func: DrawScrollArea(object) + - desc: draws the scroll area object +--]]--------------------------------------------------------- +function skin.scrollarea(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local bartype = object:GetBarType() + + love.graphics.setColor(skin.controls.color_back0) + love.graphics.rectangle("fill", x, y, width, height) + love.graphics.setColor(skin.controls.color_back1) + + if bartype == "vertical" then + skin.OutlinedRectangle(x, y, width, height, true, true) + elseif bartype == "horizontal" then + skin.OutlinedRectangle(x, y, width, height, false, false, true, true) + end + +end + +--[[--------------------------------------------------------- + - func: DrawScrollBar(object) + - desc: draws the scroll bar object +--]]--------------------------------------------------------- +function skin.scrollbar(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local dragging = object:IsDragging() + local hover = object:GetHover() + local bartype = object:GetBarType() + local back, border + + if dragging then + back = skin.controls.color_fore0 + border = skin.controls.color_fore2 + elseif hover then + back = skin.controls.color_active + border = skin.controls.color_fore1 + else + back = skin.controls.color_back2 + border = skin.controls.color_fore0 + end + + love.graphics.setColor(back) + love.graphics.rectangle("fill", x, y, width, height) + love.graphics.setColor(border) + skin.OutlinedRectangle(x, y, width, height) + + love.graphics.setColor(skin.controls.color_back0) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, height - 2) +end + +--[[--------------------------------------------------------- + - func: DrawScrollBody(object) + - desc: draws the scroll body object +--]]--------------------------------------------------------- +function skin.scrollbody(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.scrollbody_body_color + + love.graphics.setColor(skin.controls.color_back1) + love.graphics.rectangle("fill", x, y, width, height) + love.graphics.setColor(skin.controls.color_back2) + skin.OutlinedRectangle(x, y, width, height) + +end + + +--[[--------------------------------------------------------- + - func: DrawScrollButton(object) + - desc: draws the scroll button object +--]]--------------------------------------------------------- +function skin.scrollbutton(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 scrolltype = object:GetScrollType() + local down = object.down + local back, fore, border + + if down then + back = skin.controls.color_fore0 + fore = skin.controls.color_back0 + border = skin.controls.color_fore2 + elseif hover then + back = skin.controls.color_active + fore = skin.controls.color_back0 + border = skin.controls.color_fore1 + else + back = skin.controls.color_back2 + fore = skin.controls.color_fore0 + border = skin.controls.color_fore0 + end + + -- button back + love.graphics.setColor(back) + love.graphics.rectangle("fill", x, y, width, height) + -- button border + love.graphics.setColor(border) + skin.OutlinedRectangle(x, y, width, height) + + local image + if scrolltype == "up" then + image = skin.images["arrow-up.png"] + elseif scrolltype == "down" then + image = skin.images["arrow-down.png"] + elseif scrolltype == "left" then + image = skin.images["arrow-left.png"] + elseif scrolltype == "right" then + image = skin.images["arrow-right.png"] + end + + local imagewidth = image:getWidth() + local imageheight = image:getHeight() + --image:setFilter("nearest", "nearest") + love.graphics.setColor(fore) + + love.graphics.draw(image, x + width/2 - imagewidth/2, y + height/2 - imageheight/2) + + love.graphics.setColor(skin.controls.color_back0) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, height - 2) +end + +--[[--------------------------------------------------------- + - func: skin.DrawSlider(object) + - desc: draws the slider object +--]]--------------------------------------------------------- +function skin.slider(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local slidtype = object:GetSlideType() + local body = skin.controls.color_back1 + local border = skin.controls.color_back3 + + if slidtype == "horizontal" then + love.graphics.setColor(body) + love.graphics.rectangle("fill", x, y + height/2 - 3, width, 6) + love.graphics.setColor(border) + love.graphics.rectangle("fill", x + 5, y + height/2 - 1, width - 10, 2) + elseif slidtype == "vertical" then + love.graphics.setColor(body) + love.graphics.rectangle("fill", x + width/2 - 3, y, 6, height) + love.graphics.setColor(border) + love.graphics.rectangle("fill", x + width/2 - 1, y + 5, 2, height - 10) + end + +end + +--[[--------------------------------------------------------- + - func: skin.DrawSliderButton(object) + - desc: draws the slider button object +--]]--------------------------------------------------------- +function skin.sliderbutton(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 down = object.down + local parent = object:GetParent() + local enabled = parent:GetEnabled() + + if not enabled then + -- button body + love.graphics.setColor(skin.controls.color_back1) + love.graphics.rectangle("fill", x, y, width, height) + -- button border + love.graphics.setColor(skin.controls.color_back2) + skin.OutlinedRectangle(x, y, width, height) + return + end + + + local image = skin.images["slider.png"] + local imagewidth = image:getWidth() + local imageheight = image:getHeight() + --image:setFilter("nearest", "nearest") + + local fore + if down then + fore = skin.controls.color_fore0 + elseif hover then + fore = skin.controls.color_active + else + fore = skin.controls.color_back3 + end + + love.graphics.setColor(fore) + love.graphics.draw(image, x + (width - imagewidth) / 2, y + (height - imageheight) / 2) +end + +--[[--------------------------------------------------------- + - func: DrawPanel(object) + - desc: draws the panel object +--]]--------------------------------------------------------- +function skin.panel(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(skin.controls.color_back1) + love.graphics.rectangle("fill", x, y, width, height) + + --love.graphics.setColor(skin.controls.color_back1) + --skin.OutlinedRectangle(x + 1, y + 1, width - 2, height - 2) + + love.graphics.setColor(skin.controls.color_back2) + skin.OutlinedRectangle(x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: DrawList(object) + - desc: draws the list object +--]]--------------------------------------------------------- +function skin.list(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.list_body_color + + love.graphics.setColor(skin.controls.color_back0) + love.graphics.rectangle("fill", x, y, width, height) + --love.graphics.setColor(skin.controls.color_back3) + --skin.OutlinedRectangle(x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: DrawList(object) + - desc: used to draw over the object and its children +--]]--------------------------------------------------------- +function skin.list_over(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(skin.controls.color_back3) + skin.OutlinedRectangle(x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: DrawTabPanel(object) + - desc: draws the tab panel object +--]]--------------------------------------------------------- +function skin.tabpanel(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local buttonheight = object:GetHeightOfButtons() + + love.graphics.setColor(skin.controls.color_back1) + love.graphics.rectangle("fill", x, y + buttonheight, width, height - buttonheight) + love.graphics.setColor(skin.controls.color_back2) + skin.OutlinedRectangle(x, y + buttonheight - 1, width, height - buttonheight + 2) + + object:SetScrollButtonSize(15, buttonheight) + +end + +--[[--------------------------------------------------------- + - func: DrawOverTabPanel(object) + - desc: draws over the tab panel object +--]]--------------------------------------------------------- +function skin.tabpanel_over(object) + +end + +--[[--------------------------------------------------------- + - func: DrawTabButton(object) + - desc: draws the tab button object +--]]--------------------------------------------------------- +function skin.tabbutton(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local hover = object:GetHover() + local text = object:GetText() + local image = object:GetImage() + local tabnumber = object:GetTabNumber() + local parent = object:GetParent() + local ptabnumber = parent:GetTabNumber() + local font = skin.controls.smallfont + local twidth = font:getWidth(object.text) + local theight = font:getHeight(object.text) + local imagewidth = 0 + local imageheight = 0 + local texthovercolor = skin.controls.button_text_hover_color + local textnohovercolor = skin.controls.button_text_nohover_color + + if image then + --image:setFilter("nearest", "nearest") + imagewidth = image:getWidth() + imageheight = image:getHeight() + object.width = imagewidth + 15 + twidth + if imageheight > theight then + parent:SetTabHeight(imageheight + 10) + object.height = imageheight + 10 + else + object.height = parent.tabheight + end + else + object.width = 10 + twidth + object.height = parent.tabheight + end + + local width = object:GetWidth() + local height = object:GetHeight() + + local back, fore, border + + if tabnumber ~= ptabnumber then + back = skin.controls.color_back1 + border = skin.controls.color_back2 + fore = skin.controls.color_fore0 + else + back = skin.controls.color_active + border = skin.controls.color_back2 + fore = skin.controls.color_back0 + end + + -- button body + love.graphics.setColor(back) + love.graphics.rectangle("fill", x, y, width, height) + -- button border + love.graphics.setColor(border) + skin.OutlinedRectangle(x, y, width, height) + + love.graphics.setFont(font) + if image then + -- button image + love.graphics.setColor(skin.controls.color_image) + love.graphics.draw(image, x + 5, y + height/2 - imageheight/2) + -- button text + love.graphics.setColor(fore) + skin.PrintText(text, x + imagewidth + 10, y + height/2 - theight/2) + else + -- button text + love.graphics.setColor(fore) + skin.PrintText(text, x + 5, y + height/2 - theight/2) + end + +end + +--[[--------------------------------------------------------- + - func: DrawMultiChoice(object) + - desc: draws the multi choice object +--]]--------------------------------------------------------- +function skin.multichoice(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local text = object:GetText() + local choice = object:GetChoice() + local image = skin.images["multichoice-arrow.png"] + local font = skin.controls.smallfont + local theight = font:getHeight("a") + local hover = object:GetHover() + --local down = object:GetDown() + + --image:setFilter("nearest", "nearest") + + local back, fore, border + if hover then + back = skin.controls.color_active + fore = skin.controls.color_back0 + border = skin.controls.color_fore1 + else + back = skin.controls.color_back2 + fore = skin.controls.color_fore0 + border = skin.controls.color_fore0 + end + + love.graphics.setColor(back) + love.graphics.rectangle("fill", x, y, width, height) + + love.graphics.setColor(fore) + love.graphics.setFont(font) + + if choice == "" then + skin.PrintText(text, x + 5, y + height/2 - theight/2) + else + skin.PrintText(choice, x + 5, y + height/2 - theight/2) + end + + love.graphics.draw(image, x + width - 20, y + 5) + + love.graphics.setColor(border) + skin.OutlinedRectangle(x, y, width, height) + + love.graphics.setColor(skin.controls.color_back0) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, height - 2) +end + +--[[--------------------------------------------------------- + - func: DrawMultiChoiceList(object) + - desc: draws the multi choice list object +--]]--------------------------------------------------------- +function skin.multichoicelist(object) + + local skin = object:GetSkin() + local x = object:GetX() + 2 + local y = object:GetY() + local width = object:GetWidth() - 4 + local height = object:GetHeight() + + love.graphics.setColor(skin.controls.color_back1) + love.graphics.rectangle("fill", x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: DrawOverMultiChoiceList(object) + - desc: draws over the multi choice list object +--]]--------------------------------------------------------- +function skin.multichoicelist_over(object) + + local skin = object:GetSkin() + local x = object:GetX() + 2 + local y = object:GetY() - 1 + local width = object:GetWidth() - 4 + local height = object:GetHeight() + 1 + + love.graphics.setColor(skin.controls.color_fore0) + skin.OutlinedRectangle(x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: DrawMultiChoiceRow(object) + - desc: draws the multi choice row object +--]]--------------------------------------------------------- +function skin.multichoicerow(object) + + local skin = object:GetSkin() + local x = object:GetX() + 2 + local y = object:GetY() + local width = object:GetWidth() - 4 + local height = object:GetHeight() + local text = object:GetText() + local font = skin.controls.smallfont + local back, fore + + love.graphics.setFont(font) + + if object.hover then + back = skin.controls.color_active + fore = skin.controls.color_back0 + else + back = skin.controls.color_back2 + fore = skin.controls.color_fore0 + end + + love.graphics.setColor(back) + love.graphics.rectangle("fill", x, y, width, height) + love.graphics.setColor(fore) + skin.PrintText(text, x + 5, y + 5) + +end + +--[[--------------------------------------------------------- + - func: DrawToolTip(object) + - desc: draws the tool tip object +--]]--------------------------------------------------------- +function skin.tooltip(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(skin.controls.color_back1) + love.graphics.rectangle("fill", x, y, width, height) + love.graphics.setColor(skin.controls.color_back2) + skin.OutlinedRectangle(x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: DrawText(object) + - desc: draws the text object +--]]--------------------------------------------------------- +function skin.text(object) + local textdata = object.formattedtext + local x = object.x + local y = object.y + local shadow = object.shadow + local shadowxoffset = object.shadowxoffset + local shadowyoffset = object.shadowyoffset + local shadowcolor = object.shadowcolor + local inlist, list = object:IsInList() + local printfunc = function(text, x, y) + love.graphics.print(text, math.floor(x + 0.5), math.floor(y + 0.5)) + end + + for k, v in ipairs(textdata) do + local textx = v.x + local texty = v.y + local text = v.text + local color = v.color + local font = v.font + local link = v.link + local theight = font:getHeight("a") + if inlist then + local listy = list.y + local listhieght = list.height + if (y + texty) <= (listy + listhieght) and y + ((texty + theight)) >= listy then + love.graphics.setFont(font) + if shadow then + love.graphics.setColor(unpack(shadowcolor)) + printfunc(text, x + textx + shadowxoffset, y + texty + shadowyoffset) + end + if link then + local linkcolor = v.linkcolor + local linkhovercolor = v.linkhovercolor + local hover = v.hover + if hover then + love.graphics.setColor(linkhovercolor) + else + love.graphics.setColor(linkcolor) + end + else + love.graphics.setColor(unpack(color)) + end + printfunc(text, x + textx, y + texty) + end + else + love.graphics.setFont(font) + if shadow then + love.graphics.setColor(unpack(shadowcolor)) + printfunc(text, x + textx + shadowxoffset, y + texty + shadowyoffset) + end + if link then + local linkcolor = v.linkcolor + local linkhovercolor = v.linkhovercolor + local hover = v.hover + if hover then + love.graphics.setColor(linkhovercolor) + else + love.graphics.setColor(linkcolor) + end + else + love.graphics.setColor(unpack(color)) + end + printfunc(text, x + textx, y + texty) + end + end +end + +--[[--------------------------------------------------------- + - func: DrawTextInput(object) + - desc: draws the text input object +--]]--------------------------------------------------------- +function skin.textinput(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local font = object:GetFont() + local focus = object:GetFocus() + local showindicator = object:GetIndicatorVisibility() + local alltextselected = object:IsAllTextSelected() + local textx = object:GetTextX() + local texty = object:GetTextY() + local text = object:GetText() + local multiline = object:GetMultiLine() + local lines = object:GetLines() + local placeholder = object:GetPlaceholderText() + local offsetx = object:GetOffsetX() + local offsety = object:GetOffsetY() + local indicatorx = object:GetIndicatorX() + local indicatory = object:GetIndicatorY() + local vbar = object:HasVerticalScrollBar() + local hbar = object:HasHorizontalScrollBar() + local linenumbers = object:GetLineNumbersEnabled() + local itemwidth = object:GetItemWidth() + local masked = object:GetMasked() + local theight = font:getHeight("a") + + love.graphics.setColor(skin.controls.color_back0) + love.graphics.rectangle("fill", x, y, width, height) + + if alltextselected then + local bary = 0 + if multiline then + for i=1, #lines do + local str = lines[i] + if masked then + str = loveframes.utf8.gsub(str, ".", "*") + end + local twidth = font:getWidth(str) + if twidth == 0 then + twidth = 5 + end + love.graphics.setColor(skin.controls.color_active) + love.graphics.rectangle("fill", textx, texty + bary, twidth, theight) + bary = bary + theight + end + else + local twidth = 0 + if masked then + local maskchar = object:GetMaskChar() + twidth = font:getWidth(loveframes.utf8.gsub(text, ".", maskchar)) + else + twidth = font:getWidth(text) + end + love.graphics.setColor(skin.controls.color_active) + love.graphics.rectangle("fill", textx, texty, twidth, theight) + end + end + + if showindicator and focus then + love.graphics.setColor(skin.controls.color_fore0) + love.graphics.rectangle("fill", indicatorx, indicatory, 1, theight) + end + + if not multiline then + object:SetTextOffsetY(height/2 - theight/2) + if offsetx ~= 0 then + object:SetTextOffsetX(0) + else + object:SetTextOffsetX(5) + end + else + if vbar then + if offsety ~= 0 then + if hbar then + object:SetTextOffsetY(5) + else + object:SetTextOffsetY(-5) + end + else + object:SetTextOffsetY(5) + end + else + object:SetTextOffsetY(5) + end + + if hbar then + if offsety ~= 0 then + if linenumbers then + local panel = object:GetLineNumbersPanel() + if vbar then + object:SetTextOffsetX(5) + else + object:SetTextOffsetX(-5) + end + else + if vbar then + object:SetTextOffsetX(5) + else + object:SetTextOffsetX(-5) + end + end + else + object:SetTextOffsetX(5) + end + else + object:SetTextOffsetX(5) + end + + end + + textx = object:GetTextX() + texty = object:GetTextY() + + love.graphics.setFont(font) + + if alltextselected then + love.graphics.setColor(skin.controls.color_back0) + elseif #lines == 1 and lines[1] == "" then + love.graphics.setColor(skin.controls.color_back2) + else + love.graphics.setColor(skin.controls.color_fore0) + end + + local str = "" + if multiline then + for i=1, #lines do + str = lines[i] + if masked then + local maskchar = object:GetMaskChar() + str = loveframes.utf8.gsub(str, ".", maskchar) + end + skin.PrintText(#str > 0 and str or (#lines == 1 and placeholder or ""), textx, texty + theight * i - theight) + end + else + str = lines[1] + if masked then + local maskchar = object:GetMaskChar() + str = loveframes.utf8.gsub(str, ".", maskchar) + end + skin.PrintText(#str > 0 and str or placeholder, textx, texty) + end + + --love.graphics.setColor(skin.controls.color_back3) + --skin.OutlinedRectangle(x + 1, y + 1, width - 2, height - 2) + +end + +--[[--------------------------------------------------------- + - func: DrawOverTextInput(object) + - desc: draws over the text input object +--]]--------------------------------------------------------- +function skin.textinput_over(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(skin.controls.color_back3) + skin.OutlinedRectangle(x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawCheckBox(object) + - desc: draws the check box object +--]]--------------------------------------------------------- +function skin.checkbox(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetBoxWidth() + local height = object:GetBoxHeight() + local checked = object:GetChecked() + local hover = object:GetHover() + local buttonimage + if checked then + buttonimage = skin.images["check-on.png"] + else + buttonimage = skin.images["check-off.png"] + end + + if hover ~= checked then + love.graphics.setColor(skin.controls.color_active) + else + love.graphics.setColor(skin.controls.color_fore0) + end + local iwidth = buttonimage:getWidth() + local iheight = buttonimage:getHeight() + --buttonimage:setFilter("nearest", "nearest") + love.graphics.draw(buttonimage, x + (width - iwidth) / 2, y + (height - iheight) / 2) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawCheckBox(object) + - desc: draws the radio button object +--]]--------------------------------------------------------- +function skin.radiobutton(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetBoxWidth() + local height = object:GetBoxHeight() + local checked = object:GetChecked() + local hover = object:GetHover() + local buttonimage + if checked then + buttonimage = skin.images["radio-on.png"] + else + buttonimage = skin.images["radio-off.png"] + end + + if hover ~= checked then + love.graphics.setColor(skin.controls.color_active) + else + love.graphics.setColor(skin.controls.color_fore0) + end + local iwidth = buttonimage:getWidth() + local iheight = buttonimage:getHeight() + --buttonimage:setFilter("nearest", "nearest") + love.graphics.draw(buttonimage, x + (width - iwidth) / 2, y + (height - iheight) / 2) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawCollapsibleCategory(object) + - desc: draws the collapsible category object +--]]--------------------------------------------------------- +function skin.collapsiblecategory(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local text = object:GetText() + local open = object:GetOpen() + local font = skin.controls.smallfont + + love.graphics.setColor(skin.controls.color_back1) + love.graphics.rectangle("fill", x, y, width, height) + + love.graphics.setColor(skin.controls.color_active) + love.graphics.rectangle("fill", x, y, width, 25) + + love.graphics.setColor(skin.controls.color_back3) + skin.OutlinedRectangle(x, y, width, height) + + love.graphics.setColor(skin.controls.color_back0) + if open then + local icon = skin.images["collapse.png"] + --icon:setFilter("nearest", "nearest") + love.graphics.draw(icon, x + width - 21, y + 5) + love.graphics.setColor(skin.controls.color_back0) + 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(skin.controls.color_back0) + skin.OutlinedRectangle(x + 1, y + 1, width - 2, 23) + end + + love.graphics.setFont(font) + love.graphics.setColor(skin.controls.color_back0) + skin.PrintText(text, x + 5, y + 5) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawColumnList(object) + - desc: draws the column list object +--]]--------------------------------------------------------- +function skin.columnlist(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(skin.controls.color_active) + love.graphics.rectangle("fill", x, y, width, height) +end + +--[[--------------------------------------------------------- + - func: skin.DrawColumnListHeader(object) + - desc: draws the column list header object +--]]--------------------------------------------------------- +function skin.columnlistheader(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 down = object.down + local font = skin.controls.smallfont + local theight = font:getHeight(object.name) + + local name = ParseHeaderText(object:GetName(), x, width, x + width/2) + local twidth = font:getWidth(name) + + local back, fore, border + + if down then + back = skin.controls.color_fore0 + fore = skin.controls.color_back0 + border = skin.controls.color_fore2 + elseif hover then + back = skin.controls.color_active + fore = skin.controls.color_back0 + border = skin.controls.color_fore1 + else + back = skin.controls.color_back2 + fore = skin.controls.color_fore0 + border = skin.controls.color_fore0 + end + + -- header body + love.graphics.setColor(back) + love.graphics.rectangle("fill", x, y, width, height) + -- header name + love.graphics.setFont(font) + love.graphics.setColor(fore) + skin.PrintText(name, x + width/2 - twidth/2, y + height/2 - theight/2) + -- header border + love.graphics.setColor(border) + skin.OutlinedRectangle(x, y, width+1, height) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawColumnListArea(object) + - desc: draws the column list area object +--]]--------------------------------------------------------- +function skin.columnlistarea(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(skin.controls.color_back0) + love.graphics.rectangle("fill", x, y, width, height) + + local cheight = 0 + local columns = object:GetParent():GetChildren() + if #columns > 0 then + cheight = columns[1]:GetHeight() + end + + -- header body + love.graphics.setColor(skin.controls.color_back1) + love.graphics.rectangle("fill", x, y, width, cheight) + + love.graphics.setColor(skin.controls.color_back2) + skin.OutlinedRectangle(x, y, width, cheight) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawOverColumnListArea(object) + - desc: draws over the column list area object +--]]--------------------------------------------------------- +function skin.columnlistarea_over(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(skin.controls.color_back3) + skin.OutlinedRectangle(x, y, width, height) +end + +--[[--------------------------------------------------------- + - func: skin.DrawColumnListRow(object) + - desc: draws the column list row object +--]]--------------------------------------------------------- +function skin.columnlistrow(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local colorindex = object:GetColorIndex() + local font = object:GetFont() + local columndata = object:GetColumnData() + local textx = object:GetTextX() + local texty = object:GetTextY() + local parent = object:GetParent() + local theight = font:getHeight("a") + local hover = object:GetHover() + local selected = object:GetSelected() + + object:SetTextPos(5, height/2 - theight/2) + + if selected then + love.graphics.setColor(skin.controls.color_back3) + elseif hover then + love.graphics.setColor(skin.controls.color_active) + elseif colorindex == 1 then + love.graphics.setColor(skin.controls.color_back1) + else + love.graphics.setColor(skin.controls.color_back2) + end + + love.graphics.rectangle("fill", x, y, width, height) + + love.graphics.setFont(font) + if selected then + love.graphics.setColor(skin.controls.color_fore3) + elseif hover then + love.graphics.setColor(skin.controls.color_back0) + else + love.graphics.setColor(skin.controls.color_fore0) + end + for k, v in ipairs(columndata) do + local rwidth = parent.parent:GetColumnWidth(k) + if rwidth then + local text = ParseRowText(v, x, rwidth, x, textx) + skin.PrintText(text, x + textx, y + texty) + x = x + parent.parent.children[k]:GetWidth() + else + break + end + end + +end + +--[[--------------------------------------------------------- + - func: skin.DrawModalBackground(object) + - desc: draws the modal background object +--]]--------------------------------------------------------- +function skin.modalbackground(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(skin.controls.color_back2) + love.graphics.rectangle("fill", x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawLineNumbersPanel(object) + - desc: draws the line numbers panel object +--]]--------------------------------------------------------- +function skin.linenumberspanel(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local offsety = object:GetOffsetY() + local parent = object:GetParent() + local lines = parent:GetLines() + local font = parent:GetFont() + local theight = font:getHeight("8") + + + object:SetWidth(10 + font:getWidth(#lines)) + love.graphics.setFont(font) + + love.graphics.setColor(skin.controls.color_back1) + love.graphics.rectangle("fill", x, y, width, height) + + love.graphics.setColor(skin.controls.color_back0) + skin.OutlinedRectangle(x, y, width, height, true, true, true, false) + + local startline = math.ceil(offsety / theight) + if startline < 1 then + startline = 1 + end + local endline = math.ceil(startline + (height / theight)) + 1 + if endline > #lines then + endline = #lines + end + + for i=startline, endline do + love.graphics.setColor(skin.controls.color_back3) + skin.PrintText(i, x + 5, (y + (theight * (i - 1))) - offsety) + end + +end + +--[[--------------------------------------------------------- + - func: skin.DrawNumberBox(object) + - desc: draws the numberbox object +--]]--------------------------------------------------------- +function skin.numberbox(object) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawGrid(object) + - desc: draws the grid object +--]]--------------------------------------------------------- +function skin.grid(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + --love.graphics.setColor(colors.hl4) + --love.graphics.rectangle("fill", x-1, y-1, width+2, height+2) + + local cx = x + local cy = y + local cw = object.cellwidth + (object.cellpadding * 2) + local ch = object.cellheight + (object.cellpadding * 2) + + for i=1, object.rows do + for n=1, object.columns do + local ovt = false + local ovl = false + if i > 1 then + ovt = true + end + if n > 1 then + ovl = true + end + love.graphics.setColor(skin.controls.color_back1) + love.graphics.rectangle("fill", cx, cy, cw, ch) + love.graphics.setColor(skin.controls.color_back3) + skin.OutlinedRectangle(cx, cy, cw, ch, ovt, false, ovl, false) + cx = cx + cw + end + cx = x + cy = cy + ch + end + +end + +--[[--------------------------------------------------------- + - func: skin.DrawForm(object) + - desc: draws the form object +--]]--------------------------------------------------------- +function skin.form(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + local topmargin = object.topmargin + local name = object.name + local font = skin.controls.smallfont + local textcolor = skin.controls.form_text_color + local twidth = font:getWidth(name) + + love.graphics.setFont(font) + love.graphics.setColor(skin.controls.color_fore0) + skin.PrintText(name, x + 7, y) + + love.graphics.setColor(skin.controls.color_back3) + love.graphics.rectangle("fill", x, y + 7, 5, 1) + love.graphics.rectangle("fill", x + twidth + 9, y + 7, width - (twidth + 9), 1) + love.graphics.rectangle("fill", x, y + height, width, 1) + love.graphics.rectangle("fill", x, y + 7, 1, height - 7) + love.graphics.rectangle("fill", x + width - 1, y + 7, 1, height - 7) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawMenu(object) + - desc: draws the menu object +--]]--------------------------------------------------------- +function skin.menu(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(skin.controls.color_back1) + love.graphics.rectangle("fill", x, y, width, height) + + love.graphics.setColor(skin.controls.color_back2) + skin.OutlinedRectangle(x, y, width, height) + +end + +--[[--------------------------------------------------------- + - func: skin.DrawMenuOption(object) + - desc: draws the menuoption object +--]]--------------------------------------------------------- +function skin.menuoption(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 font = skin.controls.smallfont + local twidth = font:getWidth(text) + + + if option_type == "divider" then + love.graphics.setColor(skin.controls.color_fore0) + love.graphics.rectangle("fill", x + 4, y + 2, width - 8, 1) + object.contentheight = 10 + else + love.graphics.setFont(font) + if hover then + love.graphics.setColor(skin.controls.color_active) + love.graphics.rectangle("fill", x + 2, y + 2, width - 4, height - 4) + love.graphics.setColor(skin.controls.color_back0) + skin.PrintText(text, x + 26, y + 5) + else + love.graphics.setColor(skin.controls.color_fore0) + skin.PrintText(text, x + 26, y + 5) + end + if icon then + love.graphics.setColor(skin.controls.color_image) + love.graphics.draw(icon, x + 5, y + 5) + end + object.contentwidth = twidth + 31 + object.contentheight = 25 + end + +end + +function skin.tree(object) + + local skin = object:GetSkin() + local x = object:GetX() + local y = object:GetY() + local width = object:GetWidth() + local height = object:GetHeight() + + love.graphics.setColor(skin.controls.color_back1) + love.graphics.rectangle("fill", x, y, width, height) + +end + +function skin.treenode(object) + + local icon = object.icon + local buttonimage = skin.images["tree-node-button-open.png"] + local width = 0 + local x = object.x + local leftpadding = 15 * object.level + + if object.level > 0 then + leftpadding = leftpadding + buttonimage:getWidth() + 5 + else + leftpadding = buttonimage:getWidth() + 5 + end + + local iconwidth = 24 + if icon then + iconwidth = icon:getWidth() + end + + local twidth = loveframes.basicfont:getWidth(object.text) + local theight = loveframes.basicfont:getHeight(object.text) + + if object.tree.selectednode == object then + love.graphics.setColor(skin.controls.color_active) + love.graphics.rectangle("fill", x + leftpadding + 2 + iconwidth, object.y + 2, twidth, theight) + end + + width = width + iconwidth + loveframes.basicfont:getWidth(object.text) + leftpadding + --love.graphics.setColor(skin.controls.color_image) + --love.graphics.draw(icon, x + leftpadding, object.y) + love.graphics.setFont(loveframes.basicfont) + love.graphics.setColor(skin.controls.color_fore0) + skin.PrintText(object.text, x + leftpadding + 2 + iconwidth, object.y + 2) + + object:SetWidth(width + 5) + +end + +function skin.treenodebutton(object) + + local leftpadding = 15 * object.parent.level + local image + + if object.parent.open then + image = skin.images["tree-node-button-close.png"] + else + image = skin.images["tree-node-button-open.png"] + end + + --image:setFilter("nearest", "nearest") + + love.graphics.setColor(skin.controls.color_image) + love.graphics.draw(image, object.x, object.y) + + object:SetPos(2 + leftpadding, 3) + object:SetSize(image:getWidth(), image:getHeight()) + +end + +-- register the main skin +loveframes.RegisterSkin(skin) + +-- alternate active colors +local subskin = {} +subskin.author = skin.author +subskin.version = skin.version +subskin.base = skin.name +subskin.directory = skin.dir --loveframes.config["DIRECTORY"] .. "/skins/" ..skin.name +subskin.controls = {} + +local colors = { + red = color"b36262", + orange = color"b38a62", + green = color"7db362", + cyan = color"62b3a5", + blue = color"6298b3", + magenta = color"8a62b3", + pink = color"cc70b5" +} + +for k, v in pairs(colors) do + subskin.name = skin.name .. " " .. k + subskin.controls.color_active = v + loveframes.RegisterSkin(subskin) +end + +-- Dark variant with alternate active colors +subskin.controls.color_back0 = color"101010" +subskin.controls.color_back1 = color"202020" +subskin.controls.color_back2 = color"373737" +subskin.controls.color_back3 = color"505050" +subskin.controls.color_fore0 = color"a0a0a0" +subskin.controls.color_fore1 = color"c0c0c0" +subskin.controls.color_fore2 = color"e0e0e0" +subskin.controls.color_fore3 = color"f0f0f0" + +for k, v in pairs(colors) do + subskin.name = "Dark " .. k + subskin.controls.color_active = v + loveframes.RegisterSkin(subskin) +end + +--return skin + +---------- module end ---------- +end diff --git a/loveframes/skins/Orange/images/arrow-down.png b/loveframes/skins/Orange/images/arrow-down.png new file mode 100644 index 0000000000000000000000000000000000000000..37d805800fd4b840d58fc637925316b0a4c697a1 GIT binary patch literal 344 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DkxL735kHCP2GC{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L0m@TF)WP}LPr z7sn6_|D%&{b2S?XxIDkScd-J;zLhW1J02WgYI}%n?ewUcj08h9V|C@UrThC8IKC{A zn`wE2`H@A~wA53d|7^OjVC$9BDqTvUp{mbi-oJ}pc=WOGlFU_!5;hNbtz-{eeDska zsWf(Z<}5wM85b8Eeaz@NX@v%tsqf;-dHjkqZaO!Moo7lg;5;0V8o4U>cC3)~Ok0zT zy*C-y9_oLo-QOrM+w|L+J&bD)qoukrfZiGM9iW4o<-YOgt$Id<&Q mt1o!lvI6;>1s;*b z3=DkxL735kHCP2GC{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L0m@TF)WP}Nya z7sn6_|D}^-xta|GTAsg9a|;w`*|YLUa>s**m-V}; zz53}!hNP$N3}ta%7EXDx8z#PSzH{V_T*0#N f%AVd?eNI2iCUnwgTe~DWM4fwk?E# literal 0 HcmV?d00001 diff --git a/loveframes/skins/Orange/images/arrow-right.png b/loveframes/skins/Orange/images/arrow-right.png new file mode 100644 index 0000000000000000000000000000000000000000..89b4818627737201d05713540777e2d19c06f43d GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DkxL735kHCP2GC{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L0m@TF)WP}Lbv z7sn6_|D}_oxta|GT;E?Z&GJxC_>u0iKc<;O?|^AXhxbO=mmZp)w~ieU;FxK=-ul36 z6;G!5ALl>#`%b6DAy8yOkka|j+<$}>P8&^0?OgZzf(h@IYaW-sShpB2SW$aFd0u+Y z!lvI6;>1s;*b z3=DkxL735kHCP2GC{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L0m@TF)WP}M6> z7sn6_|E-f^yIKqcT3)~Sw^)H=-^v%0(*+JPSFj0w)Yx5dam1j3-RA4AY7wnX3{dwyb*{y-A-*tWUUOkw<7~ri{CC zfq2403&u$neZ9K-zQi-Kt@%CI?B|!aQ|!cc?7e-T?GMv`=O9y_SBJHLzGm=r^>bP0 Hl+XkK=vs{Q literal 0 HcmV?d00001 diff --git a/loveframes/skins/Orange/images/close.png b/loveframes/skins/Orange/images/close.png new file mode 100644 index 0000000000000000000000000000000000000000..0825add2273d02377027f72a64d1704ddbb573a8 GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DjSK$uZf!>a)(C{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L0m@TF)WP*sJe zi(`m||Jun9`5F{BS}OnB+Z2`Zc75>>+h{qvK%P_MQ~SzQ38A@N+ne9ssP$cw%5x-- zt;)g8{&WH32SLTaH+EIAVi982g(64pH?0rJU`s6ZOq6_3{O!ivaF5j;oj-gcUb$pX rn3kL+&cC?Narfzqbv{eKsW@8KHKm2zN%(#e=mrK)S3j3^P6!lvI6;>1s;*b z3=Dh+L6~vJ#O${~L8%hgh?3y^w370~qEv=}#LT=BJwMkFg)(D3Q$0gN_s>q|KvmA3 zE{-7<{!33Aaxob296s>x|7E>cCk?4Z*9y81XrC1CVRK_%+<5UoMuN#ZgV@?%KWD77 k`}>ClDr6uf@qCk+;v_+-WnpeNfyOa-y85}Sb4q9e0Oi>~)Bpeg literal 0 HcmV?d00001 diff --git a/loveframes/skins/Orange/images/expand.png b/loveframes/skins/Orange/images/expand.png new file mode 100644 index 0000000000000000000000000000000000000000..753625b10513728b6fdaf399a31dbf9c342128d4 GIT binary patch literal 221 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=Dh+L6~vJ#O${~L8%hgh?3y^w370~qEv=}#LT=BJwMkFg)(D3Q$0gN_s>q|Kvj{R zE{-7<{!33gaxp0IFgyPL|FWymV}k7#i5aJ-ty}f0sgUV0%drO+eGS<9^O_7RN`!k3 zE}p$-;qKp)&%2j@SD)YMZhlb0W)~-14OqjzDCul2MXmVM%xNb!1@J z*w6hZkrl}2EbxddW?~4KG*Eio07TgnY_+`}gTe~DWM4f_s3C> literal 0 HcmV?d00001 diff --git a/loveframes/skins/Orange/images/gradients/button-hover.png b/loveframes/skins/Orange/images/gradients/button-hover.png new file mode 100644 index 0000000000000000000000000000000000000000..f621691cd53f8dbcfc098d44e27e5e371ad616e7 GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{T!3HEx%~ItD2^0spJ29*~C-V}>VM%xNb!1@J z*w6hZkrl}2EbxddW?VM%xNb!1@J z*w6hZkrl}2EbxddW?wRU|_*9pt+DU&)3_c?JKs@9)Vd?@O-(XkiI%4Z^O{LoE}0~*TU>FVdQ I&MBb@06yMGfdBvi literal 0 HcmV?d00001 diff --git a/loveframes/skins/Orange/images/gradients/button-unclickable.png b/loveframes/skins/Orange/images/gradients/button-unclickable.png new file mode 100644 index 0000000000000000000000000000000000000000..ef8bf7defb2900d7e0487758332d1cc8a58dbf73 GIT binary patch literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{T!3HEx%~ItD2^0spJ29*~C-V}>VM%xNb!1@J z*w6hZkrl}2EbxddW?VM%xNb!1@J z*w6hZkrl}2EbxddW?LzG&HgubM}3gQ1&`=0?kOouvtDMWeHCRHq-8uy}rCtJu4}H;ei1Re#*u?(${6 aOZ>9M3P*&x&U>c zv7h@-A}f&3S>O>_%)r2R7=#&*=dVZs3QCo@MwA5SrEak75pH^HtKb0!9tJ~y`7}ABGjnPlyQx=d|9ql3b$3EIUpkxn zsyCdslOmKOoKpF2JURU0-~+9_hpnWexTS(u^8T#zHnH&x2xW=}8pz=3>gTe~DWM4f DW*tCO literal 0 HcmV?d00001 diff --git a/loveframes/skins/Orange/images/gradients/progressbar.png b/loveframes/skins/Orange/images/gradients/progressbar.png new file mode 100644 index 0000000000000000000000000000000000000000..7cdfb4b670b7ff968bb7b7f42fe4d78bf89fd28f GIT binary patch literal 199 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{T!3HEx%~ItD2^0spJ29*~C-V}>VM%xNb!1@J z*w6hZkrl}2EbxddW? o3mwdax<4GqWqJ0Hsr(0{P>s$v`89=ifhI6`y85}Sb4q9e0Es?4l>h($ literal 0 HcmV?d00001 diff --git a/loveframes/skins/Orange/images/multichoice-arrow.png b/loveframes/skins/Orange/images/multichoice-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..165121c956329680f817fdc62358e736bfebea59 GIT binary patch literal 284 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?(3p^r= z85sBufiR<}hF1enP^!c=q9iy!t)x7$D3u`~F*C13&(AePq0Cs%RL{`B;7id$psE?3 zE{-7<{(C21^lnCf7dUk^^n)TlAORn9F1`-=yF5J3IB6%{4LDoSPMkf7ZGu%Df z0;3<;h(roGttexXs1B{r-*|1(loW~T<&&RAEOPKt$Z2}|-r_k&upper case mappings) is loaded, these +-- additional functions are available: +-- * utf8upper(s) +-- * utf8lower(s) +-- +-- All functions behave as their non UTF-8 aware counterparts with the exception +-- that UTF-8 characters are used instead of bytes for all units. + +--[[ +Copyright (c) 2006-2007, Kyle Smith +All rights reserved. + +Contributors: + Alimov Stepan + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--]] + +-- ABNF from RFC 3629 +-- +-- UTF8-octets = *( UTF8-char ) +-- UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4 +-- UTF8-1 = %x00-7F +-- UTF8-2 = %xC2-DF UTF8-tail +-- UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / +-- %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) +-- UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / +-- %xF4 %x80-8F 2( UTF8-tail ) +-- UTF8-tail = %x80-BF +-- + +local byte = string.byte +local char = string.char +local dump = string.dump +local find = string.find +local format = string.format +local len = string.len +local lower = string.lower +local rep = string.rep +local sub = string.sub +local upper = string.upper + +-- returns the number of bytes used by the UTF-8 character at byte i in s +-- also doubles as a UTF-8 character validator +local function utf8charbytes (s, i) + -- argument defaults + i = i or 1 + + -- argument checking + if type(s) ~= "string" then + error("bad argument #1 to 'utf8charbytes' (string expected, got ".. type(s).. ")") + end + if type(i) ~= "number" then + error("bad argument #2 to 'utf8charbytes' (number expected, got ".. type(i).. ")") + end + + local c = byte(s, i) + + -- determine bytes needed for character, based on RFC 3629 + -- validate byte 1 + if c > 0 and c <= 127 then + -- UTF8-1 + return 1 + + elseif c >= 194 and c <= 223 then + -- UTF8-2 + local c2 = byte(s, i + 1) + + if not c2 then + error("UTF-8 string terminated early") + end + + -- validate byte 2 + if c2 < 128 or c2 > 191 then + error("Invalid UTF-8 character") + end + + return 2 + + elseif c >= 224 and c <= 239 then + -- UTF8-3 + local c2 = byte(s, i + 1) + local c3 = byte(s, i + 2) + + if not c2 or not c3 then + error("UTF-8 string terminated early") + end + + -- validate byte 2 + if c == 224 and (c2 < 160 or c2 > 191) then + error("Invalid UTF-8 character") + elseif c == 237 and (c2 < 128 or c2 > 159) then + error("Invalid UTF-8 character") + elseif c2 < 128 or c2 > 191 then + error("Invalid UTF-8 character") + end + + -- validate byte 3 + if c3 < 128 or c3 > 191 then + error("Invalid UTF-8 character") + end + + return 3 + + elseif c >= 240 and c <= 244 then + -- UTF8-4 + local c2 = byte(s, i + 1) + local c3 = byte(s, i + 2) + local c4 = byte(s, i + 3) + + if not c2 or not c3 or not c4 then + error("UTF-8 string terminated early") + end + + -- validate byte 2 + if c == 240 and (c2 < 144 or c2 > 191) then + error("Invalid UTF-8 character") + elseif c == 244 and (c2 < 128 or c2 > 143) then + error("Invalid UTF-8 character") + elseif c2 < 128 or c2 > 191 then + error("Invalid UTF-8 character") + end + + -- validate byte 3 + if c3 < 128 or c3 > 191 then + error("Invalid UTF-8 character") + end + + -- validate byte 4 + if c4 < 128 or c4 > 191 then + error("Invalid UTF-8 character") + end + + return 4 + + else + error("Invalid UTF-8 character") + end +end + +-- returns the number of characters in a UTF-8 string +local function utf8len (s) + -- argument checking + if type(s) ~= "string" then + for k,v in pairs(s) do print('"',tostring(k),'"',tostring(v),'"') end + error("bad argument #1 to 'utf8len' (string expected, got ".. type(s).. ")") + end + + local pos = 1 + local bytes = len(s) + local length = 0 + + while pos <= bytes do + length = length + 1 + pos = pos + utf8charbytes(s, pos) + end + + return length +end + +-- functions identically to string.sub except that i and j are UTF-8 characters +-- instead of bytes +local function utf8sub (s, i, j) + -- argument defaults + j = j or -1 + + local pos = 1 + local bytes = len(s) + local length = 0 + + -- only set l if i or j is negative + local l = (i >= 0 and j >= 0) or utf8len(s) + local startChar = (i >= 0) and i or l + i + 1 + local endChar = (j >= 0) and j or l + j + 1 + + -- can't have start before end! + if startChar > endChar then + return "" + end + + -- byte offsets to pass to string.sub + local startByte,endByte = 1,bytes + + while pos <= bytes do + length = length + 1 + + if length == startChar then + startByte = pos + end + + pos = pos + utf8charbytes(s, pos) + + if length == endChar then + endByte = pos - 1 + break + end + end + + if startChar > length then startByte = bytes+1 end + if endChar < 1 then endByte = 0 end + + return sub(s, startByte, endByte) +end + +--[[ +-- replace UTF-8 characters based on a mapping table +local function utf8replace (s, mapping) + -- argument checking + if type(s) ~= "string" then + error("bad argument #1 to 'utf8replace' (string expected, got ".. type(s).. ")") + end + if type(mapping) ~= "table" then + error("bad argument #2 to 'utf8replace' (table expected, got ".. type(mapping).. ")") + end + + local pos = 1 + local bytes = len(s) + local charbytes + local newstr = "" + + while pos <= bytes do + charbytes = utf8charbytes(s, pos) + local c = sub(s, pos, pos + charbytes - 1) + + newstr = newstr .. (mapping[c] or c) + + pos = pos + charbytes + end + + return newstr +end + + +-- identical to string.upper except it knows about unicode simple case conversions +local function utf8upper (s) + return utf8replace(s, utf8_lc_uc) +end + +-- identical to string.lower except it knows about unicode simple case conversions +local function utf8lower (s) + return utf8replace(s, utf8_uc_lc) +end +]] + +-- identical to string.reverse except that it supports UTF-8 +local function utf8reverse (s) + -- argument checking + if type(s) ~= "string" then + error("bad argument #1 to 'utf8reverse' (string expected, got ".. type(s).. ")") + end + + local bytes = len(s) + local pos = bytes + local charbytes + local newstr = "" + + while pos > 0 do + local c = byte(s, pos) + while c >= 128 and c <= 191 do + pos = pos - 1 + c = byte(s, pos) + end + + charbytes = utf8charbytes(s, pos) + + newstr = newstr .. sub(s, pos, pos + charbytes - 1) + + pos = pos - 1 + end + + return newstr +end + +-- http://en.wikipedia.org/wiki/Utf8 +-- http://developer.coronalabs.com/code/utf-8-conversion-utility +local function utf8char(unicode) + if unicode <= 0x7F then return char(unicode) end + + if (unicode <= 0x7FF) then + local Byte0 = 0xC0 + math.floor(unicode / 0x40); + local Byte1 = 0x80 + (unicode % 0x40); + return char(Byte0, Byte1); + end; + + if (unicode <= 0xFFFF) then + local Byte0 = 0xE0 + math.floor(unicode / 0x1000); + local Byte1 = 0x80 + (math.floor(unicode / 0x40) % 0x40); + local Byte2 = 0x80 + (unicode % 0x40); + return char(Byte0, Byte1, Byte2); + end; + + if (unicode <= 0x10FFFF) then + local code = unicode + local Byte3= 0x80 + (code % 0x40); + code = math.floor(code / 0x40) + local Byte2= 0x80 + (code % 0x40); + code = math.floor(code / 0x40) + local Byte1= 0x80 + (code % 0x40); + code = math.floor(code / 0x40) + local Byte0= 0xF0 + code; + + return char(Byte0, Byte1, Byte2, Byte3); + end; + + error 'Unicode cannot be greater than U+10FFFF!' +end + +local shift_6 = 2^6 +local shift_12 = 2^12 +local shift_18 = 2^18 + +local utf8unicode +utf8unicode = function(str, i, j, byte_pos) + i = i or 1 + j = j or i + + if i > j then return end + + local ch,bytes + + if byte_pos then + bytes = utf8charbytes(str,byte_pos) + ch = sub(str,byte_pos,byte_pos-1+bytes) + else + ch,byte_pos = utf8sub(str,i,i), 0 + bytes = #ch + end + + local unicode + + if bytes == 1 then unicode = byte(ch) end + if bytes == 2 then + local byte0,byte1 = byte(ch,1,2) + local code0,code1 = byte0-0xC0,byte1-0x80 + unicode = code0*shift_6 + code1 + end + if bytes == 3 then + local byte0,byte1,byte2 = byte(ch,1,3) + local code0,code1,code2 = byte0-0xE0,byte1-0x80,byte2-0x80 + unicode = code0*shift_12 + code1*shift_6 + code2 + end + if bytes == 4 then + local byte0,byte1,byte2,byte3 = byte(ch,1,4) + local code0,code1,code2,code3 = byte0-0xF0,byte1-0x80,byte2-0x80,byte3-0x80 + unicode = code0*shift_18 + code1*shift_12 + code2*shift_6 + code3 + end + + return unicode,utf8unicode(str, i+1, j, byte_pos+bytes) +end + +-- Returns an iterator which returns the next substring and its byte interval +local function utf8gensub(str, sub_len) + sub_len = sub_len or 1 + local byte_pos = 1 + local length = #str + return function(skip) + if skip then byte_pos = byte_pos + skip end + local char_count = 0 + local start = byte_pos + repeat + if byte_pos > length then return end + char_count = char_count + 1 + local bytes = utf8charbytes(str,byte_pos) + byte_pos = byte_pos+bytes + + until char_count == sub_len + + local last = byte_pos-1 + local slice = sub(str,start,last) + return slice, start, last + end +end + +local function binsearch(sortedTable, item, comp) + local head, tail = 1, #sortedTable + local mid = math.floor((head + tail)/2) + if not comp then + while (tail - head) > 1 do + if sortedTable[tonumber(mid)] > item then + tail = mid + else + head = mid + end + mid = math.floor((head + tail)/2) + end + end + if sortedTable[tonumber(head)] == item then + return true, tonumber(head) + elseif sortedTable[tonumber(tail)] == item then + return true, tonumber(tail) + else + return false + end +end +local function classMatchGenerator(class, plain) + local codes = {} + local ranges = {} + local ignore = false + local range = false + local firstletter = true + local unmatch = false + + local it = utf8gensub(class) + + local skip + for c, _, be in it do + skip = be + if not ignore and not plain then + if c == "%" then + ignore = true + elseif c == "-" then + table.insert(codes, utf8unicode(c)) + range = true + elseif c == "^" then + if not firstletter then + error('!!!') + else + unmatch = true + end + elseif c == ']' then + break + else + if not range then + table.insert(codes, utf8unicode(c)) + else + table.remove(codes) -- removing '-' + table.insert(ranges, {table.remove(codes), utf8unicode(c)}) + range = false + end + end + elseif ignore and not plain then + if c == 'a' then -- %a: represents all letters. (ONLY ASCII) + table.insert(ranges, {65, 90}) -- A - Z + table.insert(ranges, {97, 122}) -- a - z + elseif c == 'c' then -- %c: represents all control characters. + table.insert(ranges, {0, 31}) + table.insert(codes, 127) + elseif c == 'd' then -- %d: represents all digits. + table.insert(ranges, {48, 57}) -- 0 - 9 + elseif c == 'g' then -- %g: represents all printable characters except space. + table.insert(ranges, {1, 8}) + table.insert(ranges, {14, 31}) + table.insert(ranges, {33, 132}) + table.insert(ranges, {134, 159}) + table.insert(ranges, {161, 5759}) + table.insert(ranges, {5761, 8191}) + table.insert(ranges, {8203, 8231}) + table.insert(ranges, {8234, 8238}) + table.insert(ranges, {8240, 8286}) + table.insert(ranges, {8288, 12287}) + elseif c == 'l' then -- %l: represents all lowercase letters. (ONLY ASCII) + table.insert(ranges, {97, 122}) -- a - z + elseif c == 'p' then -- %p: represents all punctuation characters. (ONLY ASCII) + table.insert(ranges, {33, 47}) + table.insert(ranges, {58, 64}) + table.insert(ranges, {91, 96}) + table.insert(ranges, {123, 126}) + elseif c == 's' then -- %s: represents all space characters. + table.insert(ranges, {9, 13}) + table.insert(codes, 32) + table.insert(codes, 133) + table.insert(codes, 160) + table.insert(codes, 5760) + table.insert(ranges, {8192, 8202}) + table.insert(codes, 8232) + table.insert(codes, 8233) + table.insert(codes, 8239) + table.insert(codes, 8287) + table.insert(codes, 12288) + elseif c == 'u' then -- %u: represents all uppercase letters. (ONLY ASCII) + table.insert(ranges, {65, 90}) -- A - Z + elseif c == 'w' then -- %w: represents all alphanumeric characters. (ONLY ASCII) + table.insert(ranges, {48, 57}) -- 0 - 9 + table.insert(ranges, {65, 90}) -- A - Z + table.insert(ranges, {97, 122}) -- a - z + elseif c == 'x' then -- %x: represents all hexadecimal digits. + table.insert(ranges, {48, 57}) -- 0 - 9 + table.insert(ranges, {65, 70}) -- A - F + table.insert(ranges, {97, 102}) -- a - f + else + if not range then + table.insert(codes, utf8unicode(c)) + else + table.remove(codes) -- removing '-' + table.insert(ranges, {table.remove(codes), utf8unicode(c)}) + range = false + end + end + ignore = false + else + if not range then + table.insert(codes, utf8unicode(c)) + else + table.remove(codes) -- removing '-' + table.insert(ranges, {table.remove(codes), utf8unicode(c)}) + range = false + end + ignore = false + end + + firstletter = false + end + + table.sort(codes) + + local function inRanges(charCode) + for _,r in ipairs(ranges) do + if r[1] <= charCode and charCode <= r[2] then + return true + end + end + return false + end + if not unmatch then + return function(charCode) + return binsearch(codes, charCode) or inRanges(charCode) + end, skip + else + return function(charCode) + return charCode ~= -1 and not (binsearch(codes, charCode) or inRanges(charCode)) + end, skip + end +end + +--[[ +-- utf8sub with extra argument, and extra result value +local function utf8subWithBytes (s, i, j, sb) + -- argument defaults + j = j or -1 + + local pos = sb or 1 + local bytes = len(s) + local length = 0 + + -- only set l if i or j is negative + local l = (i >= 0 and j >= 0) or utf8len(s) + local startChar = (i >= 0) and i or l + i + 1 + local endChar = (j >= 0) and j or l + j + 1 + + -- can't have start before end! + if startChar > endChar then + return "" + end + + -- byte offsets to pass to string.sub + local startByte,endByte = 1,bytes + + while pos <= bytes do + length = length + 1 + + if length == startChar then + startByte = pos + end + + pos = pos + utf8charbytes(s, pos) + + if length == endChar then + endByte = pos - 1 + break + end + end + + if startChar > length then startByte = bytes+1 end + if endChar < 1 then endByte = 0 end + + return sub(s, startByte, endByte), endByte + 1 +end +]] + +local cache = setmetatable({},{ + __mode = 'kv' +}) +local cachePlain = setmetatable({},{ + __mode = 'kv' +}) +local function matcherGenerator(regex, plain) + local matcher = { + functions = {}, + captures = {} + } + if not plain then + cache[regex] = matcher + else + cachePlain[regex] = matcher + end + local function simple(func) + return function(cC) + if func(cC) then + matcher:nextFunc() + matcher:nextStr() + else + matcher:reset() + end + end + end + local function star(func) + return function(cC) + if func(cC) then + matcher:fullResetOnNextFunc() + matcher:nextStr() + else + matcher:nextFunc() + end + end + end + local function minus(func) + return function(cC) + if func(cC) then + matcher:fullResetOnNextStr() + end + matcher:nextFunc() + end + end + local function question(func) + return function(cC) + if func(cC) then + matcher:fullResetOnNextFunc() + matcher:nextStr() + end + matcher:nextFunc() + end + end + + local function capture(id) + return function(_) + local l = matcher.captures[id][2] - matcher.captures[id][1] + local captured = utf8sub(matcher.string, matcher.captures[id][1], matcher.captures[id][2]) + local check = utf8sub(matcher.string, matcher.str, matcher.str + l) + if captured == check then + for _ = 0, l do + matcher:nextStr() + end + matcher:nextFunc() + else + matcher:reset() + end + end + end + local function captureStart(id) + return function(_) + matcher.captures[id][1] = matcher.str + matcher:nextFunc() + end + end + local function captureStop(id) + return function(_) + matcher.captures[id][2] = matcher.str - 1 + matcher:nextFunc() + end + end + + local function balancer(str) + local sum = 0 + local bc, ec = utf8sub(str, 1, 1), utf8sub(str, 2, 2) + local skip = len(bc) + len(ec) + bc, ec = utf8unicode(bc), utf8unicode(ec) + return function(cC) + if cC == ec and sum > 0 then + sum = sum - 1 + if sum == 0 then + matcher:nextFunc() + end + matcher:nextStr() + elseif cC == bc then + sum = sum + 1 + matcher:nextStr() + else + if sum == 0 or cC == -1 then + sum = 0 + matcher:reset() + else + matcher:nextStr() + end + end + end, skip + end + + matcher.functions[1] = function(_) + matcher:fullResetOnNextStr() + matcher.seqStart = matcher.str + matcher:nextFunc() + if (matcher.str > matcher.startStr and matcher.fromStart) or matcher.str >= matcher.stringLen then + matcher.stop = true + matcher.seqStart = nil + end + end + + local lastFunc + local ignore = false + local skip = nil + local it = (function() + local gen = utf8gensub(regex) + return function() + return gen(skip) + end + end)() + local cs = {} + for c, bs, be in it do + skip = nil + if plain then + table.insert(matcher.functions, simple(classMatchGenerator(c, plain))) + else + if ignore then + if find('123456789', c, 1, true) then + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + lastFunc = nil + end + table.insert(matcher.functions, capture(tonumber(c))) + elseif c == 'b' then + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + lastFunc = nil + end + local b + b, skip = balancer(sub(regex, be + 1, be + 9)) + table.insert(matcher.functions, b) + else + lastFunc = classMatchGenerator('%' .. c) + end + ignore = false + else + if c == '*' then + if lastFunc then + table.insert(matcher.functions, star(lastFunc)) + lastFunc = nil + else + error('invalid regex after ' .. sub(regex, 1, bs)) + end + elseif c == '+' then + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + table.insert(matcher.functions, star(lastFunc)) + lastFunc = nil + else + error('invalid regex after ' .. sub(regex, 1, bs)) + end + elseif c == '-' then + if lastFunc then + table.insert(matcher.functions, minus(lastFunc)) + lastFunc = nil + else + error('invalid regex after ' .. sub(regex, 1, bs)) + end + elseif c == '?' then + if lastFunc then + table.insert(matcher.functions, question(lastFunc)) + lastFunc = nil + else + error('invalid regex after ' .. sub(regex, 1, bs)) + end + elseif c == '^' then + if bs == 1 then + matcher.fromStart = true + else + error('invalid regex after ' .. sub(regex, 1, bs)) + end + elseif c == '$' then + if be == len(regex) then + matcher.toEnd = true + else + error('invalid regex after ' .. sub(regex, 1, bs)) + end + elseif c == '[' then + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + end + lastFunc, skip = classMatchGenerator(sub(regex, be + 1)) + elseif c == '(' then + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + lastFunc = nil + end + table.insert(matcher.captures, {}) + table.insert(cs, #matcher.captures) + table.insert(matcher.functions, captureStart(cs[#cs])) + if sub(regex, be + 1, be + 1) == ')' then matcher.captures[#matcher.captures].empty = true end + elseif c == ')' then + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + lastFunc = nil + end + local cap = table.remove(cs) + if not cap then + error('invalid capture: "(" missing') + end + table.insert(matcher.functions, captureStop(cap)) + elseif c == '.' then + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + end + lastFunc = function(cC) return cC ~= -1 end + elseif c == '%' then + ignore = true + else + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + end + lastFunc = classMatchGenerator(c) + end + end + end + end + if #cs > 0 then + error('invalid capture: ")" missing') + end + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + end + + table.insert(matcher.functions, function() + if matcher.toEnd and matcher.str ~= matcher.stringLen then + matcher:reset() + else + matcher.stop = true + end + end) + + matcher.nextFunc = function(self) + self.func = self.func + 1 + end + matcher.nextStr = function(self) + self.str = self.str + 1 + end + matcher.strReset = function(self) + local oldReset = self.reset + local str = self.str + self.reset = function(s) + s.str = str + s.reset = oldReset + end + end + matcher.fullResetOnNextFunc = function(self) + local oldReset = self.reset + local func = self.func +1 + local str = self.str + self.reset = function(s) + s.func = func + s.str = str + s.reset = oldReset + end + end + matcher.fullResetOnNextStr = function(self) + local oldReset = self.reset + local str = self.str + 1 + local func = self.func + self.reset = function(s) + s.func = func + s.str = str + s.reset = oldReset + end + end + + matcher.process = function(self, str, start) + + self.func = 1 + start = start or 1 + self.startStr = (start >= 0) and start or utf8len(str) + start + 1 + self.seqStart = self.startStr + self.str = self.startStr + self.stringLen = utf8len(str) + 1 + self.string = str + self.stop = false + + self.reset = function(s) + s.func = 1 + end + + -- local lastPos = self.str + -- local lastByte + local ch + while not self.stop do + if self.str < self.stringLen then + --[[ if lastPos < self.str then + print('last byte', lastByte) + ch, lastByte = utf8subWithBytes(str, 1, self.str - lastPos - 1, lastByte) + ch, lastByte = utf8subWithBytes(str, 1, 1, lastByte) + lastByte = lastByte - 1 + else + ch, lastByte = utf8subWithBytes(str, self.str, self.str) + end + lastPos = self.str ]] + ch = utf8sub(str, self.str,self.str) + --print('char', ch, utf8unicode(ch)) + self.functions[self.func](utf8unicode(ch)) + else + self.functions[self.func](-1) + end + end + + if self.seqStart then + local captures = {} + for _,pair in pairs(self.captures) do + if pair.empty then + table.insert(captures, pair[1]) + else + table.insert(captures, utf8sub(str, pair[1], pair[2])) + end + end + return self.seqStart, self.str - 1, unpack(captures) + end + end + + return matcher +end + +-- string.find +local function utf8find(str, regex, init, plain) + local matcher = cache[regex] or matcherGenerator(regex, plain) + return matcher:process(str, init) +end + +-- string.match +local function utf8match(str, regex, init) + init = init or 1 + local found = {utf8find(str, regex, init)} + if found[1] then + if found[3] then + return unpack(found, 3) + end + return utf8sub(str, found[1], found[2]) + end +end + +-- string.gmatch +local function utf8gmatch(str, regex, all) + regex = (utf8sub(regex,1,1) ~= '^') and regex or '%' .. regex + local lastChar = 1 + return function() + local found = {utf8find(str, regex, lastChar)} + if found[1] then + lastChar = found[2] + 1 + if found[all and 1 or 3] then + return unpack(found, all and 1 or 3) + end + return utf8sub(str, found[1], found[2]) + end + end +end + +local function replace(repl, args) + local ret = '' + if type(repl) == 'string' then + local ignore = false + local num + for c in utf8gensub(repl) do + if not ignore then + if c == '%' then + ignore = true + else + ret = ret .. c + end + else + num = tonumber(c) + if num then + ret = ret .. args[num] + else + ret = ret .. c + end + ignore = false + end + end + elseif type(repl) == 'table' then + ret = repl[args[1] or args[0]] or '' + elseif type(repl) == 'function' then + if #args > 0 then + ret = repl(unpack(args, 1)) or '' + else + ret = repl(args[0]) or '' + end + end + return ret +end +-- string.gsub +local function utf8gsub(str, regex, repl, limit) + limit = limit or -1 + local ret = '' + local prevEnd = 1 + local it = utf8gmatch(str, regex, true) + local found = {it()} + local n = 0 + while #found > 0 and limit ~= n do + local args = {[0] = utf8sub(str, found[1], found[2]), unpack(found, 3)} + ret = ret .. utf8sub(str, prevEnd, found[1] - 1) + .. replace(repl, args) + prevEnd = found[2] + 1 + n = n + 1 + found = {it()} + end + return ret .. utf8sub(str, prevEnd), n +end + +local utf8 = {} +utf8.len = utf8len +utf8.sub = utf8sub +utf8.reverse = utf8reverse +utf8.char = utf8char +utf8.unicode = utf8unicode +utf8.gensub = utf8gensub +utf8.byte = utf8unicode +utf8.find = utf8find +utf8.match = utf8match +utf8.gmatch = utf8gmatch +utf8.gsub = utf8gsub +utf8.dump = dump +utf8.format = format +utf8.lower = lower +utf8.upper = upper +utf8.rep = rep +return utf8 diff --git a/main.lua b/main.lua index 1b84bf4..0392dc1 100644 --- a/main.lua +++ b/main.lua @@ -1,6 +1,38 @@ +local Time = require"time" +local loveframes = require"loveframes" + local Clock = require"clock" -local clockTransform = love.math.newTransform(love.graphics.getWidth()/2, love.graphics.getHeight()/2) -local clock = Clock:new(nil, 400, clockTransform) +local clock = Clock:new(nil, love.graphics.getHeight()) + +local controls = loveframes.Create("panel"):SetPos(10,10) +local toggleTime = loveframes.Create("checkbox"):SetParent(controls):SetPos(0,0) +toggleTime:SetText("Show time") +local hourBox = loveframes.Create("numberbox"):SetMinMax(1, 12):SetValue(12) +hourBox:SetParent(controls):SetPos(0,30) +local minuteBox = loveframes.Create("numberbox"):SetMinMax(0, 59):SetValue(0) +loveframes.Create("text"):SetText(":"):SetParent(controls):SetPos(80,30) +minuteBox:SetParent(controls):SetPos(100,30) + +function setClock() + local t = Time:new(hourBox:GetValue(), minuteBox:GetValue()) + clock:setTime(t) +end +hourBox.OnValueChanged = setClock +minuteBox.OnValueChanged = setClock + +function updateInputNoCallback(input, value) + callback = input.onValueChanged + input.onValueChanged = nil + input:SetValue(value) + input.onValueChanged = callback +end + +function updateInputs(time) + local h, m = time:get() + updateInputNoCallback(hourBox, h) + updateInputNoCallback(minuteBox, math.floor(m)) +end +clock.onSetHands = updateInputs function love.mousemoved(x, y, dx, dy, istouch) clock:movemouse(x, y) @@ -9,17 +41,36 @@ end -- todo mousepressed & mousereleased function love.mousepressed(x, y, button, istouch, presses) clock:pressmouse(x, y, button) + loveframes.mousepressed(x, y, button) end function love.mousereleased(x, y, button, istouch, presses) clock:releasemouse(button) + loveframes.mousereleased(x, y, button) +end + +function love.keypressed(key, scancode, isrepeat) + loveframes.keypressed(key, isrepeat) +end + +function love.keyreleased(key) + loveframes.keyreleased(key) +end + +function love.textinput(text) + loveframes.textinput(text) end function love.load() - love.graphics.setBackgroundColor(0,0,0) + love.graphics.setBackgroundColor(0.02,0.53,0.77) +end + +function love.update(dt) + loveframes.update(dt) end function love.draw() - love.graphics.print(clock:getTime():fmt()) + loveframes.draw() + local shift = (love.graphics.getWidth() - love.graphics.getHeight()) / 2 clock:draw() end diff --git a/time.lua b/time.lua new file mode 100644 index 0000000..b46aa73 --- /dev/null +++ b/time.lua @@ -0,0 +1,39 @@ +local MAX_MINUTES = 60 * 12 + +local Time = {} +Time.__index = Time + +local function newTimeRaw(rawMinutes) + local t = { + rawminutes = rawMinutes % MAX_MINUTES + } + return setmetatable(t, Time) +end + +function Time:new(hour, minute) + return newTimeRaw((hour or 12) % 12 * 60 + (minute or 0)) +end + +function Time:get() + local h = math.floor(self.rawminutes / 60 % 12) + if h == 0 then h = 12 end + local m = self.rawminutes % 60 + return h, m +end + +function Time:getHoursSinceTwelve() + local h = self.rawminutes / 60 + if h < 1 then h = h + 12 end + return h +end + +function Time:addMinutes(minutes) + return newTimeRaw(self.rawminutes + minutes) +end + +function Time:__tostring() + local h, m = self:get() + return string.format("%2d:%02d", h, m) +end + +return Time