#include "ui_defs.lua" #include "script/common.lua" #include "ui_object.lua" function Ui.ScrollableArea(obj) local area = Ui.Object:new { navId = "", contentW = 100, contentH = 100, scrollbarOffset = 5, scrollBar = { drag = false, dragPos = 0, delta = 0, deltaLerp = 0, lerpStartTime = 0, lerping = false, visibleSize = 100, contentSize = 100, isShown = false, thumbView = { w = 8, h = 100, draw = function(self) UiPush() UiTranslate(2, 2) UiColor(1, 1, 1, 1) UiImageBox("common/rect_c#ffffff_o1.00_cr3.png", self.w, self.h, 3, 3) UiPop() end }, bgView = { w = 12, h = 100, draw = function(self) UiPush() UiColor(1, 1, 1, 1) UiImageBox("common/rect_c#525252_o1.00_cr4.png", self.w, self.h, 4, 4) UiPop() end }, draw = function(self) if not self.isShown then return end UiPush() UiColorFilter(1,1,1,0.5) self.bgView:draw() UiTranslate(0, self.deltaLerp) if not UiIsMouseInRect(self.thumbView.w, self.thumbView.h) and not self.drag then UiColorFilter(0.5, 0.5, 0.5, 1) elseif not self.drag then UiColorFilter(0.7, 0.7, 0.7, 1) end self.thumbView:draw() UiPop() end, update = function(self, visibleSize, contentSize) contentSize = isNan(contentSize) and 0 or contentSize self.visibleSize = visibleSize self.contentSize = contentSize self.isShown = contentSize > visibleSize if not self.isShown then return end self.bgView.h = visibleSize self.thumbView.h = self.bgView.h * visibleSize / contentSize self.deltaLerp = lerp(self.deltaLerp, self.delta, (GetTime() - self.lerpStartTime) * 5) if self.deltaLerp == self.delta and self.lerping then self.lerping = false end UiPush() UiTranslate(0, self.deltaLerp) if InputPressed("lmb") and UiIsMouseInRect(self.thumbView.w, self.thumbView.h) then self.drag = true _, self.dragPos = UiGetMousePos() elseif self.drag and InputDown("lmb") then local _, my = UiGetMousePos() self.delta = self.delta + my - self.dragPos self.delta = clamp(self.delta, 0, self.bgView.h - self.thumbView.h) self.deltaLerp = self.delta elseif InputReleased("lmb") then self.drag = false end UiPop() self.deltaLerp = clamp(self.deltaLerp, 0, (self.bgView.h - self.thumbView.h)) end, getOffset = function(self) if self.isShown then return -(self.contentSize - self.visibleSize) * self.deltaLerp / (self.bgView.h - self.thumbView.h) else return 0 end end, addOffset = function(self, offset, noLerp) if not self.isShown or offset == 0 then return end self.delta = self.delta - offset * (self.bgView.h - self.thumbView.h) / (self.contentSize - self.visibleSize) self.delta = clamp(self.delta, 0, (self.bgView.h - self.thumbView.h)) if noLerp then self.deltaLerp = self.delta else self.lerpStartTime = GetTime() self.lerping = true end end, getRelativeOffset = function(self) return self.deltaLerp / (self.bgView.h - self.thumbView.h) end, reset = function(self) self.delta = 0 self.deltaLerp = 0 end }, draw = function(self) UiFrameOccupy(self.w, self.h) UiFrameSkipItem(true) UiPush() UiClipRect(self.w, self.h, true) if UiIsMouseInRect(self.w, self.h) then local mouseScroll = InputValue("mousewheel") * 20 self.scrollBar:addOffset(mouseScroll, self.h, self.contentH) end self.navId = UiNavComponent(self.w, self.h) if UiIsComponentInFocus(self.navId) then local gamepadScroll = (InputValue("menu_up") - InputValue("menu_down")) * 500 * GetTimeStep() self.scrollBar:addOffset(gamepadScroll, self.h, self.contentH) end UiTranslate(0, self.scrollBar:getOffset()) UiBeginFrame() self.children[1]:draw() local sx,sy = UiGetScale() local cw, ch = UiEndFrame() self.contentW, self.contentH = cw / sx , ch / sy UiPop() UiPush() UiTranslate(self.w + self.scrollbarOffset, 0) self.scrollBar:update(self.h, self.contentH) self.scrollBar:draw() UiPop() UiFrameSkipItem(false) end } return area:new(obj) end