diff --git a/.github/images/prs-screenshot-01.png b/.github/images/prs-screenshot-01.png new file mode 100644 index 0000000..8c599de Binary files /dev/null and b/.github/images/prs-screenshot-01.png differ diff --git a/.github/images/prs-screenshot-tab-stats.png b/.github/images/prs-screenshot-tab-stats.png new file mode 100644 index 0000000..0fc0185 Binary files /dev/null and b/.github/images/prs-screenshot-tab-stats.png differ diff --git a/.github/images/prs-screenshot-tell.png b/.github/images/prs-screenshot-tell.png new file mode 100644 index 0000000..93b80bf Binary files /dev/null and b/.github/images/prs-screenshot-tell.png differ diff --git a/.github/images/prs-screenshot-unlocked.png b/.github/images/prs-screenshot-unlocked.png new file mode 100644 index 0000000..0c5527d Binary files /dev/null and b/.github/images/prs-screenshot-unlocked.png differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6f9a44 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode/settings.json diff --git a/AdjustableTabWindow/AdjustableTabWindow.lua b/AdjustableTabWindow/AdjustableTabWindow.lua new file mode 100644 index 0000000..cbdc8e3 --- /dev/null +++ b/AdjustableTabWindow/AdjustableTabWindow.lua @@ -0,0 +1,1530 @@ +-- Adjustable TabWindow +-- TabWindow code by Mudlet Wiki +-- other functions +-- by Edru 10th October 2020 +-- https://github.com/Edru2/AdjustableTabWindow +Adjustable = Adjustable or {} +Adjustable.TabWindow = Adjustable.TabWindow or Geyser.Container:new({ + name = "AdjustableTabWindowClass" +}) +local tab_pos = nil + +-- Geyser.Label echo function overwritten to not have the color function in it +-- needed for allowing stylesheet to control the text color +local function noColorEcho(self, message, color, format) + message = message or self.message + self.message = message + if format then + self:processFormatString(format) + end + + local ft = self.formatTable + local fs = ft.fontSize + local alignment = ft.alignment + if alignment ~= "" then + alignment = string.format([[align="%s" ]], alignment) + end + if ft.bold then + message = "" .. message .. "" + end + if ft.italics then + message = "" .. message .. "" + end + if ft.underline then + message = "" .. message .. "" + end + if ft.strikethrough then + message = "" .. message .. "" + end + if self.font and self.font ~= "" then + message = string.format('%s', self.font, message) + end + if not fs then + fs = tostring(self.fontSize) + end + fs = "font-size: " .. fs .. "pt; " + message = [[
]] .. message .. [[
]] + echo(self.name, message) +end + +function Adjustable.TabWindow:createBaseContainers() + self.tabBar = self.tabBar or Geyser.Label:new({ + name = self.name .. "tabBar", + x = 0, + y = 0, + width = "100%", + height = self.tabBarHeight + }, self) + self.tabBar:setStyleSheet(self.tabBarStyle) + + self.header = self.header or Geyser.HBox:new({ + name = self.name .. "header", + x = 0, + y = 0, + width = "100%", + height = "100%" + }, self.tabBar) + + self.overlay = self.overlay or Geyser.Label:new({ + name = self.name .. "overlay", + x = 0, + y = 0, + width = "100%", + height = "100%" + }, self.tabBar) + + self.overlay:setStyleSheet(self.overlayStyle) + self.overlay:setMoveCallback(function(event) + self:onOverlayMove(event) + end) + self.overlay:setOnLeave(function(event) + self:onOverlayLeave(event) + end) + self.overlay:setClickCallback(function(event) + self:onOverlayClick(event) + end) + self.overlay:hide() + + self.footerContainer = self.footerContainer or Geyser.Container:new({ + name = self.name .. "footerContainer", + x = 0, + y = self.tabBarHeight, + width = "100%", + height = "-0" + }, self) + + self.footer = self.footer or Geyser.Label:new({ + name = self.name .. "footer", + x = 0, + y = self.gap, + width = "100%", + height = "-0" + }, self.footerContainer) + + self.footer:setStyleSheet(self.footerStyle) +end + +local function setTabToolTip(tab) + -- put ToolTip on Label if TabText is to long to display + local w, h = calcFontSize(tab.adjLabel.fontSize) + local txt_width = #tab.tabText * w + if tab.adjLabel:get_width() < txt_width then + tab.adjLabel:setToolTip(tab.tabText) + else + tab.adjLabel:resetToolTip() + end +end + +-- function to create new tabs in tabs table or to rewrite/readjust them +function Adjustable.TabWindow:createTabs() + for k, v in ipairs(self.tabs) do + self[v .. "center"] = self[v .. "center"] or Geyser.Label:new({ + name = v .. "center", + x = 0, + y = 0, + width = "100%", + height = "100%" + }, self.footer) + + self[v .. "center"]:setStyleSheet(self.centerStyle) + + local tabText = self[v] and self[v].tabText or v + + self[v] = self[v] or Adjustable.Container:new({ + name = self.name .. " Tab: " .. v, + tabname = v, + origin = self, + noLimit = true, + tabText = tabText, + padding = 0, + locked = true, + autoSave = false, + autoLoad = false, + raiseOnClick = false, + adjLabelstyle = self.inactiveTabStyle, + titleTxtColor = self.tabTxtColor + + }, self.header) + + self[v].adjLabel.echo = noColorEcho + self[v]:setTitle(tabText) + self[v]:newLockStyle("tab", function(self) + self.Inside:resize("-" .. self.padding, "-" .. self.padding) + self.Inside:move(self.padding, self.padding * 2) + end) + + self[v].lockStyle = "tab" + + self[v].unlockContainer = function() + Adjustable.Container.unlockContainer(self[v]) + self[v].adjLabel:echo(self[v].tabText, nil, "c") + end + + Adjustable.TabWindow.allTabs[v] = self + + self[v]:newCustomItem("Tabify", function() + Adjustable.TabWindow.allTabs[v]:createTempWindow(self[v]) + end) + + self[v].reposition = self.reposition + local delIndex = table.index_of(Adjustable.Container.all_windows, self[v].name) + if delIndex then + table.remove(Adjustable.Container.all_windows, delIndex) + end + Adjustable.Container.all[self[v].name] = nil + self[v].adjLabelstyle = self.inactiveTabStyle + self[v].titleTxtColor = self.tabTxtColor + self[v].adjLabel:setStyleSheet(self.inactiveTabStyle) + + self[v].adjLabel:echo(self[v].tabText, nil, "c") + self[v].adjLabel:setClickCallback(function(event) + self:onClick(v, event) + end) + self[v].adjLabel:setReleaseCallback(function(event) + self:onRelease(v, event) + end) + self[v].adjLabel:setMoveCallback(function(event) + self:onMove(v, event) + end) + self[v].adjLabel:setDoubleClickCallback(function(event) + self:onDoubleClick(v, event) + end) + self[v].minimizeLabel:setClickCallback(function() + self:onMinimizeClick(v) + end) + self[v].minimizeLabel:echo("
🗗
") + self[v].minLabel:setClickCallback(function() + self:onMinimizeClick(v) + end) + self[v .. "center"]:hide() + -- put ToolTip on Label if TabText is to long to display + setTabToolTip(self[v]) + end +end + +--- Sets the amount of space to use between the tabs and the consoles +-- @tparam number gap Number of pixels to keep between the tabs and consoles +function Adjustable.TabWindow:setGap(gap) + local gapNumber = tonumber(gap) + local gapType = type(gap) + assert(gapType == "number", "gap expected as number, got " .. gapType) + self.gap = gapNumber + self.footer:move(0, gapNumber) +end + +--- Sets the height of the tabs in pixels/percent +-- @tparam number tabHeight the height of the tabs for the object, in pixels/percent +function Adjustable.TabWindow:setTabHeight(tabHeight) + self.tabBarHeight = tabHeight + self.tabBar:resize("100%", tabHeight) + self.footerContainer:move(0, tabHeight) + self.footerContainer:resize("100%", "-0") +end + +--- Sets the CSS to use for the tab box which contains the tabs for the object +-- @tparam string css The css styling to use for the tab box +function Adjustable.TabWindow:setTabBarCSS(css) + local cssType = type(css) + assert(cssType == "string", "css as string expected, got " .. cssType) + self.tabBarStyle = css + self.tabBar:setStyleSheet(self.tabBarStyle) +end + +--- Sets the color to use for the tab box background +-- @param color Color string suitable for decho or hecho, or color name eg "purple", or table of colors {r,g,b} +function Adjustable.TabWindow:setTabBarColor(color) + self.tabBarColor = color + self.tabBarStyle = "" + self.tabBar:setStyleSheet(self.tabBarStyle) + self.tabBar:setColor(self.tabBarColor) +end + +--- Sets the FG color for the active tab +-- @param color Color string suitable for decho or hecho, or color name eg "purple", or table of colors {r,g,b} +function Adjustable.TabWindow:setActiveTabFGColor(color) + local found + local add_css + local r, g, b = Geyser.Color.parse(color) + local rgb = string.format("rgb(%s, %s, %s)", r, g, b) + self.activeTabFGColor = color + self.activeTabStyle, found = string.gsub(" " .. self.activeTabStyle, "(%scolor:).-(;)", "%1" .. rgb .. "%2") + if found == 0 then + if string.match(self.activeTabStyle, "QLabel{") then + add_css = "\nQLabel{color:" .. rgb .. ";}" + else + add_css = "\ncolor:" .. rgb .. ";" + end + self.activeTabStyle = self.activeTabStyle .. add_css + end + self:adjustTabStyle() +end + +--- Sets the FG color for the inactive tab +-- @param color Color string suitable for decho or hecho, or color name eg "purple", or table of colors {r,g,b} +function Adjustable.TabWindow:setInactiveTabFGColor(color) + local found + local add_css + self.inactiveTabFGColor = color + local r, g, b = Geyser.Color.parse(color) + local rgb = string.format("rgb(%s, %s, %s)", r, g, b) + + self.inactiveTabStyle, found = string.gsub(" " .. self.inactiveTabStyle, "(%scolor:).-(;)", "%1" .. rgb .. "%2") + if found == 0 then + if string.match(self.inactiveTabStyle, "QLabel{") then + add_css = "\nQLabel{color:" .. rgb .. ";}" + elseif string.match(self.inactiveTabStyle, "QLabel::!hover{") then + add_css = "" + self.inactiveTabStyle = string.gsub(self.inactiveTabStyle, "(QLabel::!.-)(})", + "%1" .. "color:" .. rgb .. ";" .. "%2") + else + add_css = "\ncolor:" .. rgb .. ";" + end + self.inactiveTabStyle = self.inactiveTabStyle .. add_css + end + self:adjustTabStyle() +end + +--- Sets the BG color for the active tab. +--
NOTE: If you set CSS for the active tab, it will override this setting. +-- @param color Color string suitable for decho or hecho, or color name eg "purple", or table of colors {r,g,b} +function Adjustable.TabWindow:setActiveTabBGColor(color) + self.activeTabBGColor = color + local r, g, b = Geyser.Color.parse(color) + local rgba = string.format("rgba(%s, %s, %s, %s)", r, g, b, "100%%") + self.activeTabStyle = string.gsub(self.activeTabStyle, "(background%-color:.-).-(;)", "%1 " .. rgba .. "%2") + self:adjustTabStyle() +end + +--- Sets the BG color for the inactive tab. +--
NOTE: If you set CSS for the inactive tab, it will override this setting. +-- @param color Color string suitable for decho or hecho, or color name eg "purple", or table of colors {r,g,b} +function Adjustable.TabWindow:setInactiveTabBGColor(color) + self.inactiveTabBGColor = color + local r, g, b = Geyser.Color.parse(color) + local rgba = string.format("rgba(%s, %s, %s, %s)", r, g, b, "100%%") + self.inactiveTabStyle = string.gsub(self.inactiveTabStyle, "(background%-color:.-).-(;)", "%1 " .. rgba .. "%2") + self:adjustTabStyle() +end + +function Adjustable.TabWindow:adjustTabStyle() + local abg_rgb = string.match(self.activeTabBGColor, "%d+.-%d+.-%d+") + local ibg_rgb = string.match(self.inactiveTabBGColor, "%d+.-%d+.-%d+") + for k, v in ipairs(self.tabs) do + if v == self.current then + self[v].adjLabelstyle = self.activeTabStyle + self[v].adjLabel:setStyleSheet(self.activeTabStyle) + if abg_rgb then + self[v].adjLabel:setColor("<" .. abg_rgb .. ">") + else + self[v].adjLabel:setColor(self.activeTabBGColor) + end + else + self[v].adjLabelstyle = self.inactiveTabStyle + self[v].adjLabel:setStyleSheet(self.inactiveTabStyle) + if ibg_rgb then + self[v].adjLabel:setColor("<" .. ibg_rgb .. ">") + else + self[v].adjLabel:setColor(self.inactiveTabBGColor) + end + end + end +end + +--- sets the font for all tabs +--- @tparam string font the font to use. +function Adjustable.TabWindow:setTabFont(font) + self.tabFont = font + for k, v in ipairs(self.tabs) do + self[v].adjLabel:setFont(font) + end +end + +--- sets the font for a single tab. If you use setTabFont this will be overridden +--- @tparam string tabName the tab to change the font of +--- @tparam string font the font to use for that tab +function Adjustable.TabWindow:setSingleTabFont(tabName, font) + local funcName = "EMCO:setSingleTabFont(tabName, font)" + if not table.contains(self.tabs, tabName) then + error("tabName must be an existing tab") + end + self[tabName].adjLabel:setFont(font) +end + +-- finds the right position to drop the tab into +function Adjustable.TabWindow:findPosition(tab) + local myWindow = Adjustable.TabWindow.currentWindow or self + local x, w = myWindow.get_x(), myWindow.get_width() + local total = w / #myWindow.tabs + local tab_x = tab.get_x() - x + local position = (tab_x / total) + 1 + position = math.floor(position + 0.5) + if position < 1 then + position = 1 + end + if position > #myWindow.tabs then + position = #myWindow.tabs + 1 + end + return position +end + +-- checks if 2 elements collide +local function checkCollision(x1, y1, w1, h1, x2, y2, w2, h2) + if x1 < x2 + w2 and x2 < x1 + w1 and y1 < y2 + h2 and y2 < y1 + h1 then + return true + end +end + +local function getFloatingWindows() + local floatingWindows = {} + for k, v in pairs(Adjustable.TabWindow.allTabs) do + if v[k].floating then + floatingWindows[k] = v[k] + end + end + return floatingWindows + +end + +-- checks if your tab collides with one of the tabwindows +function Adjustable.TabWindow:checkMultiCollision(tab) + local floatingWindows = getFloatingWindows() + local x1, y1, w1, h1 = tab:get_x(), tab:get_y(), tab:get_width(), tab:get_height() + for k, v in pairs(floatingWindows) do + local x2, y2, w2, h2 = v:get_x(), v:get_y(), v:get_width(), v:get_height() + if checkCollision(x1, y1, w1, h1, x2, y2, w2, h2) and v.windowname == self.windowname and + not (v.hidden or v.auto_hidden) and not (v == tab) and not v.locked then + return "floating", v + end + end + for k, v in pairs(Adjustable.TabWindow.all) do + local x2, y2, w2, h2 = v:get_x(), v:get_y(), v:get_width(), v:get_height() + + if checkCollision(x1, y1, w1, h1, x2, y2, w2, h2) and v.windowname == self.windowname and + not (v.hidden or v.auto_hidden) then + return "TabWindow", v + end + end +end + +-- onMove function +-- contains all the functionality to move the tab (collision check, make space ...) +function Adjustable.TabWindow:onMove(tab, event) + self[tab]:onMove(self[tab].adjLabel, event) + self[tab].adjLabel:setAlignment("c") + if self[tab].floating or not Adjustable.TabWindow.clicked then + return + end + local result, value = self:checkMultiCollision(self[tab]) + if Adjustable.TabWindow.currentWindow and Adjustable.TabWindow.currentWindow ~= value and + not Adjustable.TabWindow.currentWindow.floating then + -- reset the tab space + self:makeSpace(Adjustable.TabWindow.currentWindow, nil, true) + end + if result == "TabWindow" then + Adjustable.TabWindow.currentWindow = value + tab_pos = value:findPosition(self[tab]) + self:makeSpace(value, tab_pos) + return + end + if result == "floating" and not (value.locked) then + Adjustable.TabWindow.currentWindow = value + return + end + if Adjustable.TabWindow.currentWindow then + Adjustable.TabWindow.currentWindow = nil + end +end + +--- Transforms a floating Tab into a temporary TabWindow +-- @tparam tab the tab which will be transformed +function Adjustable.TabWindow:createTempWindow(tab, tempName) + if tab and not (tab.floating) then + return + end + + local rnd_nr = 0 + for i = 0, #Adjustable.TabWindow.all_windows do + if not Adjustable.TabWindow.all["tempTabWindow" .. i] then + rnd_nr = i + break + end + end + + local window = tab and tab.windowname ~= "main" and + Geyser.windowList[tab.windowname .. "Container"].windowList[tab.windowname] or Geyser + local tempWindowName = tempName and "tempWindow" .. string.match(tempName, "%d+") or "tempWindow" .. rnd_nr + local tempTabWindowName = tempName or "tempTabWindow" .. rnd_nr + local x, y, width, height = 0, 0, 100, 100 + if tab then + x, y, width, height = tab:get_x(), tab:get_y(), tab:get_width(), tab:get_height() + end + local tempWindowConf = { + name = tempWindowName, + titleText = "", + x = x, + y = y, + width = width, + height = height, + autoSave = false, + autoLoad = false + } + tempWindowConf = table.union(tempWindowConf, self.tempWindowConf) + + local windowCont = Adjustable.Container:new(tempWindowConf) + windowCont:move(x, y) + windowCont:resize(width, height) + table.remove(Adjustable.Container.all_windows, table.index_of(Adjustable.Container.all_windows, windowCont.name)) + Adjustable.Container.all[windowCont.name] = nil + + local tabWindow = Adjustable.TabWindow:new({ + name = tempTabWindowName, + x = 0, + y = 0, + width = "100%", + height = "100%", + tabTxtColor = self.tabTxtColor, + tabPadding = self.tabPadding, + activeTabFGColor = self.activeTabFGColor, + inactiveTabFGColor = self.inactiveTabFGColor, + activeTabBGColor = self.activeTabBGColor, + inactiveTabBGColor = self.inactiveTabBGColor, + tabBarColor = self.tabBarColor, + tabBarStyle = self.tabBarStyle, + color1 = self.color1, + color2 = self.color2, + tabBarHeight = self.tabBarHeight, + footerStyle = self.footerStyle, + centerStyle = self.centerStyle, + inactiveTabStyle = self.inactiveTabStyle, + activeTabStyle = self.activeTabStyle, + chosenTabStyle = self.chosenTabStyle, + overlayStyle = self.overlayStyle, + gap = self.gap, + temporary = true + }, windowCont) + + -- save name to get the style on loading + tabWindow.tempStyle = self.tempStyle or self.name + if tab then + self:restoreTab(tab.tabname, tabWindow) + tab.tempWindow = windowCont + tab.tempTabWindow = tabWindow + tab.tempWindow:changeContainer(window) + tab.tempWindow:setPercent(true, true) + end + windowCont:show() + windowCont.tabWindow = tabWindow + return windowCont +end + +-- mouse movement on the overlay label +function Adjustable.TabWindow:onOverlayMove(event) + Adjustable.TabWindow.currentWindow = self + local tab = Adjustable.TabWindow.clickedTab.name + if Adjustable.TabWindow.clickedTab ~= self.header.windowList[tab] then + -- need to feed values to findPosition + local fakeTab = {} + fakeTab.get_x = function() + return event.x + self.header.get_x() + end + tab_pos = self:findPosition(fakeTab) + self:makeSpace(self, tab_pos) + end +end + +-- reset tabspace after mouse leaves overlay label and resets the currentWindow +function Adjustable.TabWindow:onOverlayLeave(event) + Adjustable.TabWindow.currentWindow = nil + if not (Adjustable.TabWindow.doubleClick) then + return + end + local tab = Adjustable.TabWindow.clickedTab.name + if Adjustable.TabWindow.clickedTab ~= self.header.windowList[tab] then + self:makeSpace(nil, nil, true) + end +end + +-- reset the Overlay label to be hidden +local function resetOverlay() + local tab = Adjustable.TabWindow.clickedTab + if Adjustable.TabWindow.overlayTimer then + killTimer(Adjustable.TabWindow.overlayTimer) + Adjustable.TabWindow.overlayTimer = nil + end + for k, v in pairs(Adjustable.TabWindow.all) do + v.overlay:setStyleSheet("background-color: rgba(0,0,0,0%);") + v.overlay:hide() + end + if Adjustable.TabWindow.currentWindow then + Adjustable.TabWindow.currentWindow:makeSpace(nil, nil, true) + end + Adjustable.TabWindow.doubleClick = nil + tab_pos = nil + + -- reset Style if overlay is resetet without action + if tab then + tab.adjLabel:setStyleSheet(tab.adjLabelstyle) + end + + if Adjustable.TabWindow.MouseEventID then + killAnonymousEventHandler(Adjustable.TabWindow.MouseEventID) + Adjustable.TabWindow.MouseEventID = nil + end +end + +-- handles on overlay click event +function Adjustable.TabWindow:onOverlayClick(event) + Adjustable.TabWindow.doubleClick = nil + local tab = Adjustable.TabWindow.clickedTab + local container = Adjustable.TabWindow.allTabs[tab.tabname] or self + tab.adjLabel:setStyleSheet(container.activeTabStyle) + if container[tab.tabname].floating then + container:restoreTab(tab.tabname, self) + self:addTab(tab.tabname, tab_pos) + else + container:onRelease(tab.tabname, event) + end + resetOverlay() +end + +-- if clicked on the minimize label the tab will be +-- restored to be in a tabwindow again +function Adjustable.TabWindow:onMinimizeClick(tab) + local result, value = self:checkMultiCollision(self[tab]) + if result == "floating" then + value = nil + end + self:restoreTab(tab, value) +end + +-- activates the tab tab (doesn't deactivate the previous tab) +-- @see Adjustable.TabWindow:deactivateTab() +function Adjustable.TabWindow:activateTab(tab) + self:deactivateTab() + tab = self[tab] and tab or self.tabs[1] + self.current = tab + if self.current then + self[tab].adjLabelstyle = self.activeTabStyle + self[tab].adjLabel:setStyleSheet(self.activeTabStyle) + self[self.current .. "center"]:show() + end + self:raiseAll() +end + +-- deactivates and hides the current active tab +function Adjustable.TabWindow:deactivateTab() + if self.current and self[self.current] then + self[self.current].adjLabelstyle = self.inactiveTabStyle + self[self.current].adjLabel:setStyleSheet(self.inactiveTabStyle) + self[self.current .. "center"]:hide() + end +end + +-- handles click event on tab +function Adjustable.TabWindow:onClick(tab, event) + if Adjustable.TabWindow.doubleClick then + return + end + Adjustable.TabWindow.currentWindow = self + Adjustable.TabWindow.clicked = true + Adjustable.TabWindow.clickedTab = self[tab] + if event.button == "LeftButton" and not self[tab].floating then + self[tab]:resize(self[tab].get_width(), self[tab].get_height()) + self[tab].container = Geyser + -- set minimized to true to prevent resizing + self[tab].minimized = true + self[tab]:unlockContainer() + self[tab]:onClick(self[tab].adjLabel, event) + self[tab].exitLabel:hide() + self[tab].minimizeLabel:hide() + Adjustable.TabWindow.clicked = true + Adjustable.TabWindow.clickedTab = self[tab] + self[tab].adjLabel:echo(self[tab].tabText, nil, "c") + end + + if self[tab].floating then + self[tab]:onClick(self[tab].adjLabel, event) + end + if not self[tab].floating then + self:activateTab(tab) + self[tab].adjLabel:raise(false) + end +end + +-- handles double click event on getAreaTable +-- activates the tab overlay +function Adjustable.TabWindow:onDoubleClick(tab, event) + Adjustable.TabWindow.currentWindow = self + Adjustable.TabWindow.doubleClick = true + Adjustable.TabWindow.clickedTab = self[tab] + self[tab].adjLabel:setStyleSheet(self.chosenTabStyle) + for k, v in pairs(Adjustable.TabWindow.all) do + v.overlay:show() + v.overlay:raise() + v.overlay:setStyleSheet(v.overlayStyle) + end + Adjustable.TabWindow.overlayTimer = Adjustable.TabWindow.overlayTimer or tempTimer(10, function() + resetOverlay() + end) + Adjustable.TabWindow.MouseEventID = Adjustable.TabWindow.MouseEventID or + registerAnonymousEventHandler("sysWindowMousePressEvent", + "Adjustable.TabWindow.onMouseClick", true) +end + +-- handles the mouseclick event +-- used for sending windows to the main or userwindow after using doubleclick on a tab +function Adjustable.TabWindow.onMouseClick(event, button, x, y, windowname) + local newContainer = Geyser + if windowname ~= "main" then + newContainer = Geyser.windowList[windowname .. "Container"].windowList[windowname] + end + local tab = Adjustable.TabWindow.clickedTab + local container = Adjustable.TabWindow.allTabs[tab.tabname] + + container:transformTabContainer(tab.tabname) + local width, height = math.min(newContainer.get_width(), tab:get_width()), + math.min(newContainer.get_height(), tab:get_height()) + + tab:changeContainer(newContainer) + tab:raiseAll() + local x = math.min(newContainer.get_width() - width, math.max(0, x - width / 2)) + local y = math.min(newContainer.get_height() - height, math.max(0, y)) + tab:move(x, y) + tab:resize(width, height) + tab:setPercent(true, true) + killAnonymousEventHandler(Adjustable.TabWindow.MouseEventID) + Adjustable.TabWindow.MouseEventID = nil + resetOverlay() +end + +-- transforms the tab to a window +function Adjustable.TabWindow:transformTabContainer(tab) + local myWindow = Adjustable.TabWindow.allTabs[tab] or self + local container = self[tab] + if container.windowname == "main" then + Geyser:add(container) + else + Geyser.windowList[container.windowname .. "Container"].windowList[container.windowname]:add(container) + end + container:unlockContainer() + container:resize(self.get_width(), self.get_height()) + container:add(self[tab .. "center"]) + myWindow:removeTab(tab) + myWindow:createTabs() + container:setPadding(self.tabPadding) + container:show() + container:raiseAll() + myWindow[tab].floating = true + container.raiseOnClick = true + container.adjLabel:echo(self[tab].tabText, nil, "c") + container.adjLabel:resetToolTip() + container.minimized = false + container:setPercent(true, true) + myWindow:activateTab(tab) + if #myWindow.tabs > 0 then + myWindow:activateTab(myWindow.tabs[1]) + else + myWindow.current = nil + end + local found + container.adjLabelstyle, found = string.gsub(self.activeTabStyle, "(qproperty%-alignment%:.-).-(;)", + "%1 'AlignTop' %2") + if found == 0 then + container.adjLabelstyle = container.adjLabelstyle .. "\nqproperty-alignment: 'AlignTop' ;\n" + end + container.adjLabel:setStyleSheet(container.adjLabelstyle) + self[tab .. "center"]:show() +end + +-- restores the window to be a tab again +function Adjustable.TabWindow:restoreTab(tab, myWindow) + myWindow = myWindow or self + local container = self[tab] + container.container:remove(container) + container:remove(self[tab .. "center"]) + container:setPadding(0) + container:lockContainer() + container:detach() + container:disconnect() + container.adjLabel:echo(self[tab].tabText, nil, "c") + self:changeTabContainer(tab, myWindow) + self[tab].floating = false + container.raiseOnClick = false + tempTimer(0, function() + myWindow:activateTab(tab) + end) +end + +-- function to make a gap where the tab can be dropped in +function Adjustable.TabWindow:makeSpace(myWindow, position, resetSpace) + myWindow = myWindow or self + position = position or #myWindow.header.windows + if position < 1 then + position = 1 + end + local current_Tab = Adjustable.TabWindow.clickedTab or {} + local total_count = #myWindow.header.windows + 1 + -- close the space if resetSpace is true + if resetSpace then + position = -1 + total_count = total_count - 1 + end + + if myWindow == self and current_Tab.name and not (Adjustable.TabWindow.doubleClick) then + total_count = total_count - 1 + end + local new_width = myWindow.get_width() / total_count + local new_x = 0 + local counter = 1 + for k, v in ipairs(myWindow.header.windows) do + if v ~= current_Tab.name then + if counter == position then + new_x = new_x + new_width + end + myWindow.header.windowList[v]:resize(new_width) + myWindow.header.windowList[v]:move(new_x) + new_x = new_x + new_width + counter = counter + 1 + end + end +end + +-- function to change the parent window of the tab +function Adjustable.TabWindow:changeTabContainer(tab, myWindow, position) + if self ~= myWindow or self[tab].floating then + myWindow[tab] = self[tab] + myWindow[tab .. "center"] = self[tab .. "center"] + self[tab].container = not (self[tab].floating) and self.header or Geyser + self[tab .. "center"]:changeContainer(myWindow.footer) + self[tab]:changeContainer(myWindow.header) + if not (self[tab].floating) then + self:removeTab(tab) + self:createTabs() + end + myWindow:createTabs() + myWindow[tab]:show() + if not (myWindow.hidden or myWindow.auto_hidden) then + myWindow:show() + end + end + myWindow:addTab(tab, position) + if self.current then + self[self.current]:show() + end + if #self.tabs > 0 then + if not (self[tab].floating) then + self:activateTab(self.tabs[1]) + end + else + self.current = nil + end + myWindow:activateTab(tab) +end + +-- handles the release event +function Adjustable.TabWindow:onRelease(tab, event, position) + if Adjustable.TabWindow.doubleClick then + return + end + local myWindow = Adjustable.TabWindow.currentWindow or self + local floating = self[tab].floating + if event.button == "LeftButton" and Adjustable.TabWindow.currentWindow and myWindow.type == "adjustabletabwindow" and + not floating then + self[tab]:lockContainer() + self[tab].container = self.header + self[tab]:onRelease(self[tab].adjLabel, event) + self[tab].adjLabel:echo(self[tab].tabText, nil, "c") + tab_pos = tab_pos or myWindow:findPosition(self[tab]) + if myWindow ~= self then + self:changeTabContainer(tab, myWindow) + end + myWindow:addTab(tab, tab_pos) + myWindow:raiseAll() + end + + if event.button == "LeftButton" and myWindow.type == "adjustablecontainer" then + local tabname = myWindow.tabname + local tabwindow = Adjustable.TabWindow.allTabs[tabname] + local mytab = tabwindow[tabname] + local tempWindow = tabwindow:createTempWindow(mytab) + self:changeTabContainer(tab, tempWindow.tabWindow) + tempTimer(0, function() + tempWindow.tabWindow:activateTab(tab) + end) + tempWindow:raiseAll() + self[tab]:onRelease(self[tab].adjLabel, event) + Adjustable.TabWindow.currentWindow = tempWindow.tabWindow + end + + if event.button == "LeftButton" and not (Adjustable.TabWindow.currentWindow) and not floating then + self:transformTabContainer(tab) + self[tab]:onRelease(self[tab].adjLabel, event) + end + + if floating then + self[tab]:onRelease(self[tab].adjLabel, event) + end + + Adjustable.TabWindow.clicked = false + Adjustable.TabWindow.currentWindow = nil + if not (Adjustable.TabWindow.doubleClick) then + Adjustable.TabWindow.clickedTab = nil + end + tab_pos = nil +end + +-- change the text a tab displays +function Adjustable.TabWindow:setTabText(which, text) + assert(type(which) == "string" or type(which) == "number", + "setTabText: bad argument #1 type (tab name/position as string or number expected, got " .. type(which) .. "!)") + assert(type(text) == "string", + "setTabText: bad argument #2 type (tab text as string expected, got " .. type(text) .. "!)") + if not (type(which) == "number" and which <= #self.tabs) then + which = table.index_of(self.tabs, which) + end + + if which then + self[self.tabs[which]].tabText = text + self[self.tabs[which]]:setTitle(text) + self[self.tabs[which]].adjLabel:echo(text, nil, "c") + setTabToolTip(self[self.tabs[which]]) + return true + end + return nil, "setTabText: Couldn't find tab to set a new text" +end + +-- removes a tab (this won't be saved) +function Adjustable.TabWindow:removeTab(which) + assert(type(which) == "string" or type(which) == "number", + "removeTab: bad argument #1 type (tab name/position as string or number expected, got " .. type(which) .. "!)") + local index + if type(which) == "number" and which <= #self.tabs then + index = which + else + index = table.index_of(self.tabs, which) + end + if index then + local tabname = self.tabs[index] + self[tabname]:hide() + self.header:remove(self[tabname]) + self.header:organize() + table.remove(self.tabs, index) + self:activateTab(self.tabs[1]) + if self.temporary then + -- destroy empty tempTabWindow + if table.is_empty(self.tabs) then + self[tabname].tempWindow:changeContainer("main") + Adjustable.TabWindow.all[self.name] = nil + table.remove(Adjustable.TabWindow.all_windows, table.index_of(Adjustable.TabWindow.all_windows, self)) + self[tabname].tempWindow:detach() + self[tabname].tempWindow:disconnect() + self[tabname].tempWindow:hide() + -- delete all references to this tab to avoid it being sent to nirwana if restored + for k, v in pairs(Adjustable.TabWindow.allTabs) do + if v.name == self.name then + local styleOrigin = Adjustable.TabWindow.all[self.tempStyle] + Adjustable.TabWindow.allTabs[k] = styleOrigin + styleOrigin[k] = styleOrigin[k] or self[k] + styleOrigin[k .. "center"] = styleOrigin[k .. "center"] or self[k .. "center"] + styleOrigin[k].minimizeLabel:setClickCallback(function() + styleOrigin[k]:onMinimizeClick(k) + end) + styleOrigin[k].minLabel:setClickCallback(function() + styleOrigin[k]:onMinimizeClick(k) + end) + end + end + end + self[tabname].tempWindow = nil + self[tabname].tempTabWindow = nil + end + return true + end + return nil, "removeTab: Couldn't find tab to remove" +end + +-- adds a tab (this won't be saved) +function Adjustable.TabWindow:addTab(name, pos) + assert(type(name) == "string", + "addTab: bad argument #1 type (tab name as string expected, got " .. type(name) .. "!)") + pos = pos or #self.tabs + pos = pos > #self.tabs and #self.tabs or pos + assert(type(pos) == "number", + "addTab: bad argument #2 type (tab position as number expected, got " .. type(pos) .. "!)") + -- check if tabName exists already + local index = table.index_of(self.tabs, name) + -- check if postion is valid + if pos < 1 and #self.tabs ~= 0 then + return nil, "addTab: not a valid position" + end + + pos = index and pos > #self.tabs and #self.tabs or not (index) and pos == #self.tabs and pos + 1 or pos + + -- if tab exists and is at the same position already, do nothing + if index == pos then + self.header:organize() + return true + end + + -- if tab exists and position is different, then change the position + if index then + table.remove(self.tabs, index) + table.remove(self.header.windows, index) + end + table.insert(self.tabs, pos, name) + + -- if tab is new create a new Label + if not index then + self:createTabs() + end + + -- If the container isn't the right one change it (useful if removed in one adj tabwindow and added to another) + self[name .. "center"]:changeContainer(self.footer) + self[name]:changeContainer(self.header) + + local headername = self[name].name + -- if name is already in windows delete it to put it into the right position + local headerIndex = table.index_of(self.header.windows, headername) + if headerIndex then + table.remove(self.header.windows, headerIndex) + end + table.insert(self.header.windows, pos, headername) + self.header.windowList[headername] = self[name] + self[name]:show() + self.header:organize() + self:activateTab(name) + if self.temporary then + self[name].tempWindow = self.container.container + self[name].tempTabWindow = self + end + + -- put ToolTip on Label if TabText is to long to display + setTabToolTip(self[name]) + return true +end + +function Adjustable.TabWindow:addToTabWindow(container) + local name = container.name + self:addTab(name) + container:detach() + container:disconnect() + container:changeContainer(self[name .. "center"]) + container:resize("100%", "100%") + container:move(0, 0) + self[name].tabified = true + + if container.type == "adjustablecontainer" then + container:lockContainer("full") + if container.autoSave then + container:disableAutoSave() + end + local titleText = string.gsub(container.titleText, " ", "") + self:setTabText(name, titleText) + self:createTabs() + end +end + +-- transforms adjcontainer to a floating tab +function Adjustable.TabWindow:tabify(container) + local x, y, width, height = container:get_x(), container:get_y(), container:get_width(), container:get_height() + local parent = container.container + self:addToTabWindow(container) + self:transformTabContainer(container.name) + self[container.name]:move(x, y) + self[container.name]:resize(width, height) + self[container.name]:changeContainer(parent) + self:createTempWindow(self[container.name]) +end + +function Adjustable.TabWindow:addTabifyMenu(adjcontainer) + if adjcontainer.type ~= "adjustablecontainer" then + return "not an adjustable container" + end + adjcontainer:newCustomItem("Tabify", function() + self:tabify(adjcontainer) + end) +end + +--- saves your container settings +-- like tab position and some other variables in your Mudlet Profile Dir/ Adjustable.TabWindow +-- to be reliable it is important that every Adjustable.TabWindow has an unique 'name' +-- @see Adjustable.TabWindow:load +function Adjustable.TabWindow:save(slot, dir) + if type(self) ~= "table" then + dir = slot + slot = self + end + assert(slot == nil or type(slot) == "string" or type(slot) == "number", + "Adjustable.TabWindow.save: bad argument #1 type (slot as string or number expected, got " .. type(slot) .. "!)") + assert(dir == nil or type(dir) == "string", + "Adjustable.TabWindow.save: bad argument #2 type (directory as string expected, got " .. type(dir) .. "!)") + + dir = dir or self.defaultDir + slot = slot or "" + local saveDir = string.format("%s%s%s.lua", dir, "TabWindowTabs", slot) + + local mytable = {} + -- save fixed tabs + for k, v in pairs(Adjustable.TabWindow.all) do + mytable[k] = {} + mytable[k].tabs = v.tabs + mytable[k].current = v.current + mytable[k].temporary = v.temporary + end + -- save floating tabs, tempTabWindows and tabified containers + for k, v in pairs(Adjustable.TabWindow.allTabs) do + + -- floating tabs + if v[k].floating then + -- save the tabs adjustable container settings + v[k]:save(slot, dir) + -- get all floating tabs and their windownames + mytable[v.name].floatingTabs = mytable[v.name].floatingTabs or {} + mytable[v.name].floatingTabs[k] = "main" + if v[k].windowname ~= "main" then + mytable[v.name].floatingTabs[k] = v[k].windowname + end + end + + -- tempTabWindows + if v[k].tempWindow then + -- save tempWindow adjustable container settings + v[k].tempWindow:save(slot, dir) + mytable[v.name].windowname = v[k].tempWindow.windowname + -- save window where tempStyle came from + mytable[v.name].tempStyle = v[k].tempTabWindow.tempStyle + end + + -- tabified containers + if v[k].tabified then + mytable.tabifiedContainers = mytable.tabifiedContainers or {} + mytable.tabifiedContainers[#mytable.tabifiedContainers + 1] = k + end + end + + if not (io.exists(dir)) then + lfs.mkdir(dir) + end + table.save(saveDir, mytable) +end + +--- restores/loads the before saved settings +-- it is very important to load after all TabWindows are created +-- @see Adjustable.TabWindow:save +function Adjustable.TabWindow:load(slot, dir) + if type(self) ~= "table" then + dir = slot + slot = self + end + assert(slot == nil or type(slot) == "string" or type(slot) == "number", + "Adjustable.TabWindow.load: bad argument #1 type (slot as string or number expected, got " .. type(slot) .. "!)") + assert(dir == nil or type(dir) == "string", + "Adjustable.TabWindow.load: bad argument #2 type (directory as string expected, got " .. type(dir) .. "!)") + dir = dir or self.defaultDir + local slot = slot or "" + local loadDir = string.format("%s%s%s.lua", dir, "TabWindowTabs", slot) + local mytable = {} + if io.exists(loadDir) then + table.load(loadDir, mytable) + else + return "No saved settings found at: " .. loadDir + end + + -- find the tabified container by name + local function findWindow(cont, name) + cont = cont or Geyser + for k, v in pairs(cont.windowList) do + if name == v.name then + return v + end + if findWindow(v, name) then + return findWindow(v, name) + end + end + end + + -- create Tabified Windows + if mytable.tabifiedContainers then + for k, v in ipairs(mytable.tabifiedContainers) do + local container = findWindow(nil, v) + if not (Adjustable.TabWindow.allTabs[v]) then + Adjustable.TabWindow.all[Adjustable.TabWindow.all_windows[1]]:addToTabWindow(container) + end + end + mytable.tabifiedContainers = nil + end + -- create TempWindows and TempTabWindows + for k, v in pairs(mytable) do + if v.temporary then + if not Adjustable.TabWindow.all[k] then + local tempStyleWindow = Adjustable.TabWindow.all[v.tempStyle] + tempStyleWindow:createTempWindow(nil, k) + end + Adjustable.TabWindow.all[k].container.container:load(slot, dir) + if v.windowname ~= "main" then + Adjustable.TabWindow.all[k].container.container:changeContainer( + Geyser.windowList[v.windowname .. "Container"].windowList[v.windowname]) + end + end + end + + for k, v in pairs(mytable) do + -- load fixed Tabs + local myWindow = Adjustable.TabWindow.all[k] + for k1, v1 in ipairs(v.tabs) do + local myTabWindow = Adjustable.TabWindow.allTabs[v1] + if myTabWindow then + local myTab = myTabWindow[v1] + if myTab.floating then + myTabWindow:restoreTab(v1) + end + if not myWindow.header.windowList[v1] then + myTabWindow:changeTabContainer(v1, myWindow) + end + myWindow:addTab(v1, k1) + end + end + if myWindow then + myWindow:deactivateTab() + myWindow.current = v.current + tempTimer(0, function() + myWindow:activateTab(v.current) + end) + myWindow:raiseAll() + end + -- load floating Tabs + if v.floatingTabs then + for k1, v1 in pairs(v.floatingTabs) do + local myTabWindow = Adjustable.TabWindow.allTabs[k1] + local styleTabWindow = Adjustable.TabWindow.all[k] + if myTabWindow and styleTabWindow then + local myTab = myTabWindow[k1] + if myTabWindow ~= styleTabWindow then + myTabWindow:changeTabContainer(k1, styleTabWindow) + myTabWindow = styleTabWindow + end + myTabWindow:transformTabContainer(k1) + -- send my Tab to a UserWindow if saved there + if v1 ~= "main" then + myTab:changeContainer(Geyser.windowList[v1 .. "Container"].windowList[v1]) + end + -- load Adjustable Container settings + myTab:load(slot, dir) + end + end + end + end +end +string.format("%s/PRS/settings/", getMudletHomeDir()) +-- EMCO by demonnic https://github.com/demonnic/EMCO +function Adjustable.TabWindow:transferEMCO(emco) + local EMCO = EMCO or require("PRS.emco") + -- echo("EMCO Loaded") hide debug tracer + emco:hide() + local emco_tabs = emco.tabs + local emco_tabwindows = emco.consoles + local emco_windows = emco.mc + + -- xEcho override + local myXEcho = function(s, tabName, message, xtype, excludeAll) + s.currentTab = self.current + if s.blink and tabName ~= s.currentTab then + if not (s.allTabName == s.currentTab and not s.blinkFromAll) then + s.tabsToBlink[tabName] = true + end + end + EMCO.xEcho(s, tabName, message, xtype, excludeAll) + end + + -- Flash override + local myFlash = function(s) + Geyser.Container.flash(s) + raiseWindow(s.name .. "_dimensions_flash") + end + -- doBlink override + local myDoBlink = function(s) + s.currentTab = self.current + if s.blink then + if s.allTab and not s.blinkFromAll and + (s.currentTab == s.allTabName or self[s.allTabName .. "center"].hidden == false) then + s.tabsToBlink = {} + elseif s.tabsToBlink[s.currentTab] then + s.tabsToBlink[s.currentTab] = nil + end + end + for tab, _ in pairs(s.tabsToBlink) do + if not self[tab].floating and self[tab .. "center"].hidden then + s.tabs[tab]:flash() + else + s.tabsToBlink[tab] = nil + end + end + end + + -- function for transfering tab and console + local function transferTab(tabwindow) + emco_windows[tabwindow]:show() + emco_windows[tabwindow]:changeContainer(self[tabwindow .. "center"]) + emco_tabs[tabwindow]:changeContainer(self[tabwindow]) + emco_tabs[tabwindow]:move(0, 0) + emco_tabs[tabwindow]:resize("100%", "100%") + emco_tabs[tabwindow]:hide() + emco_tabs[tabwindow].flash = myFlash + if emco_tabs[tabwindow].font then + self[tabwindow].adjLabel:setFont(emco_tabs[tabwindow].font) + end + end + + -- addTab override + local myAddTab = function(s, tabName, position) + EMCO.addTab(s, tabName) + self:addTab(tabName, position) + transferTab(tabName) + self:activateTab(tabName) + end + + -- removeTab override + local myRemoveTab = function(s, tabName) + EMCO.removeTab(s, tabName) + if self[tabName].floating then + self:restoreTab(tabName) + end + Adjustable.TabWindow.allTabs[tabName]:removeTab(tabName) + end + + -- transfering process + self.tabs = table.n_union(self.tabs, emco_tabwindows) + self:createTabs() + for k, v in ipairs(emco_tabwindows) do + transferTab(v) + end + self:activateTab(emco.currentTab) + emco.reset = function() + end + emco.removeTab = myRemoveTab + emco.addTab = myAddTab + emco.xEcho = myXEcho + emco.doBlink = myDoBlink + emco.setGap = function(s, gap) + EMCO.setGap(s, gap) + self:setGap(math.max(2, gap) - 2) + end + emco.setTabHeight = function(s, height) + EMCO.setTabHeight(s, height) + self:setTabHeight(height + 2) + end + emco.setTabBoxColor = function(s, color) + EMCO.setTabBarColor(s, color) + self:setTabBarColor(color) + end + emco.setTabBoxCSS = function(s, css) + EMCO.setTabBoxCSS(s, css) + self:setTabBarCSS(css) + end + emco.setActiveTabBGColor = function(s, color) + self:setActiveTabBGColor(color) + EMCO.setActiveTabBGColor(s, color) + end + emco.setInactiveTabBGColor = function(s, color) + self:setInactiveTabBGColor(color) + EMCO.setInactiveTabBGColor(s, color) + end + emco.setActiveTabFGColor = function(s, color) + EMCO.setActiveTabFGColor(s, color) + self:setActiveTabFGColor(color) + end + emco.setInactiveTabFGColor = function(s, color) + EMCO.setInactiveTabFGColor(s, color) + self:setInactiveTabFGColor(color) + end + emco.setSingleTabFont = function(s, tab, font) + EMCO.setSingleTabFont(s, tab, font) + self:setSingleTabFont(tab, font) + end + emco.setTabFont = function(s, font) + EMCO.setTabFont(s, font) + self:setTabFont(font) + end + emco.save = function(s, slot, dir) + EMCO.save(s) + self:save(slot, dir) + end + emco.load = function(s, slot, dir) + EMCO.load(s) + self:load(slot, dir) + end +end + +-- EMCO by demonnic https://github.com/demonnic/EMCO +-- convert EMCO to Adjustable TabWindow +function Adjustable.TabWindow.convertEMCO(emco) + if emco.myTabWindow then + return + end + emco.myTabWindow = emco.myTabWindow or Adjustable.TabWindow:new({ + name = emco.name .. "TabWindow", + x = emco.x, + y = emco.y, + width = emco.width, + height = emco.height, + centerStyle = "background-color: rgba(0,0,0,0);", + footerStyle = "background-color: rgba(0,0,0,0);", + activeTabStyle = emco.activeTabCSS, + inactiveTabStyle = emco.inactiveTabCSS, + tabBarHeight = emco.tabHeight + 2, + gap = emco.gap - 2 + }, emco.container) + emco.myTabWindow:setActiveTabFGColor(emco.activeTabFGColor) + emco.myTabWindow:setInactiveTabFGColor(emco.inactiveTabFGColor) + emco.myTabWindow:setActiveTabBGColor(emco.activeTabBGColor) + emco.myTabWindow:setInactiveTabBGColor(emco.inactiveTabBGColor) + emco.myTabWindow:transferEMCO(emco) + emco.hide = function() + Geyser.Container.hide(emco.myTabWindow) + end + emco.show = function() + Geyser.Container.show(emco.myTabWindow) + end + emco:show() +end + +-- Save a reference to our parent constructor +Adjustable.TabWindow.parent = Geyser.Container +-- Create table to put every Adjustable.TabWindow in it +Adjustable.TabWindow.all = Adjustable.TabWindow.all or {} +Adjustable.TabWindow.all_windows = Adjustable.TabWindow.all_windows or {} +Adjustable.TabWindow.allTabs = Adjustable.TabWindow.allTabs or {} + +-- tabwindow constructor +function Adjustable.TabWindow:new(cons, container) + Geyser.HBox.organize = Geyser.HBox.organize or Geyser.HBox.reposition + local me = self.parent:new(cons, container) + cons = cons or {} + setmetatable(me, self) + self.__index = self + me.type = "adjustabletabwindow" + me.defaultDir = me.defaultDir or getMudletHomeDir() .. "/PRS/" + me.tabs = me.tabs or {} + me.tabTxtColor = me.tabTxtColor or "white" + me.tabPadding = me.tabPadding or 12 + me.color1 = me.color1 or "rgb(0,0,100)" + me.color2 = me.color2 or "rgb(0,0,70)" + me.activeTabBGColor = me.activeTabBGColor or me.color1 + me.inactiveTabBGColor = me.inactiveTabBGColor or me.color2 + me.tabBarHeight = me.tabBarHeight or "35" + me.gap = me.gap or 0 + me.footerStyle = me.footerStyle or [[ + background-color: ]] .. me.color1 .. [[; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; + ]] + + me.centerStyle = me.centerStyle or [[ + background-color: ]] .. me.color2 .. [[; + border-radius: 10px; + margin: 5px; + ]] + + me.inactiveTabStyle = me.inactiveTabStyle or [[QLabel::hover{ + background-color: ]] .. me.activeTabBGColor .. [[; + color: ]] .. me.tabTxtColor .. [[; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + margin-right: 1px; + margin-left: 1px; + qproperty-alignment: 'AlignVCenter'; + } + QLabel::!hover{ + background-color: ]] .. me.inactiveTabBGColor .. [[; + color: ]] .. me.tabTxtColor .. [[; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + margin-right: 1px; + margin-left: 1px; + qproperty-alignment: 'AlignVCenter'; + } + ]] + + me.activeTabStyle = me.activeTabStyle or [[ + background-color: ]] .. me.activeTabBGColor .. [[; + color: ]] .. me.tabTxtColor .. [[; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + margin-right: 1px; + margin-left: 1px; + qproperty-alignment: 'AlignVCenter'; + ]] + + me.chosenTabStyle = me.chosenTabStyle or [[ + background-color: rgba(255,30,0,60%); + border-top-left-radius: 10px; + border-top-right-radius: 10px; + margin-right: 1px; + margin-left: 1px; + color: ]] .. me.tabTxtColor .. [[; + + ]] + + me.overlayStyle = me.overlayStyle or [[ + background-color: rgba(0,0,0,0%); + border: 2px solid white;]] + + me.tabBarStyle = me.tabBarStyle or [[ + background-color: rgba(0,0,0,0%); + ]] + + me.tempWindowConf = me.tempWindowConf or { + buttonsize = "12", + buttonFontSize = "7", + padding = 9, + buttonstyle = [[ + QLabel{ border-radius: 4px; background-color: rgba(80,80,80,80%);} + QLabel::hover{ background-color: rgba(60,60,60,50%);} + ]], + adjLabelstyle = [[background-color: rgba(0,0,0,90%); border: 2px solid rgb(50,50,50);]] + } + + me:createBaseContainers() + me:createTabs() + + if me.tabBarColor then + me:setTabBarColor(me.tabBarColor) + else + me.tabBarColor = "black" + end + + local found = string.match(" " .. me.activeTabStyle, "(%scolor:).-(;)") + if not (found) then + me.activeTabFGColor = me.activeTabFGColor or me.tabTxtColor + end + + found = string.match(" " .. me.inactiveTabStyle, "(%scolor:).-(;)") + if not (found) then + me.inactiveTabFGColor = me.inactiveTabFGColor or me.tabTxtColor + end + + if me.activeTabFGColor then + me:setActiveTabFGColor(me.activeTabFGColor) + end + if me.inactiveTabFGColor then + me:setInactiveTabFGColor(me.inactiveTabFGColor) + end + + me.current = me.current or me.tabs[#me.tabs] + + if me.tabs[1] then + me:activateTab(me.tabs[1]) + end + tempTimer(0, function() + if me.tabs[1] then + me[me.tabs[#me.tabs] .. "center"]:hide() + end + end) + + if not Adjustable.TabWindow.all[me.name] then + Adjustable.TabWindow.all_windows[#Adjustable.TabWindow.all_windows + 1] = me.name + end + Adjustable.TabWindow.all[me.name] = me + + return me +end diff --git a/PRS.lua b/PRS.lua index e54b0a3..fe7bd7b 100644 --- a/PRS.lua +++ b/PRS.lua @@ -1,13 +1,13 @@ --- Procedural Realms Script (PRS) by Stack and Dalem -local version = "1.6.0" +-- Procedural Realms Script (PRS) for Mudlet +-- by Stack (https://ilpdev.com/prs) & Dalem + +local version = "1.7.0" -- check if the generic_mapper package is installed and, if so, uninstall it -if table.contains(getPackages(), "generic_mapper") then - uninstallPackage("generic_mapper") +if table.contains(getPackages(),"generic_mapper") then + uninstallPackage("generic_mapper") end --- Open the windows -PRSchat.tabs() registerAnonymousEventHandler("gmcp.Char.player", function() PRSstats.stats() end, true) @@ -21,4 +21,4 @@ setDiscordGame("Procedural Realms") local currentarea = getRoomArea(getPlayerRoom()) local areaname = getAreaTableSwap()[currentarea] setDiscordDetail(areaname) -setDiscordElapsedStartTime(os.time(os.date("*t"))) +setDiscordElapsedStartTime(os.time(os.date("*t"))) \ No newline at end of file diff --git a/README.md b/README.md index a168fc1..8d381d2 100644 --- a/README.md +++ b/README.md @@ -20,16 +20,16 @@

- Mudlet script for Procedural Realms MUD + Procedural Realms Script for Mudlet

-The Procedural Realms Script [PRS] project gives [Procedural Realms MUD](http://textdimension.com/) players improved access to the advanced features of the [Mudlet](https://www.mudlet.org) MUD client. By leveraging the specific "out of band" packets sent by Procedural Realms' server, PRS uses Mudlet's mapper to identifies rooms/exits, prevent creation of duplicate rooms/areas, manage instanced areas, and accurately track your character's location on the map as you move about the realm. Additional convenience features include speedwalking/pathfinding, autosetting map terrain colors, self-updating gauges for vitals, communication containers, and a user-adjustable UI layout. +The Procedural Realms Script [PRS] project gives [Procedural Realms MUD](http://textdimension.com/) players improved access to the advanced features of the [Mudlet](https://www.mudlet.org) MUD client. By leveraging the specific "out of band" packets sent by Procedural Realms' server, PRS uses Mudlet's mapper to identify rooms/exits, prevent creation of duplicate rooms/areas, manage instanced areas, and accurately track your character's location on the map as you move about the realm. Additional convenience features include speedwalking/pathfinding, autosetting map terrain colors, self-updating gauges for vitals and combat, communication containers, quick slot buttons/keybindings, and a user-adjustable UI layout. -Project Link: [https://github.com/iLPdev/prs]
-Mudlet Forum Topic: [https://forums.mudlet.org/viewtopic.php?f=6&t=23126] +**Project Link**: [https://github.com/iLPdev/prs]
+**Mudlet Forum Topic**: [https://forums.mudlet.org/viewtopic.php?f=6&t=23126] @@ -49,16 +49,16 @@ Mudlet Forum Topic: [https://forums.mudlet.org/viewtopic.php?f=6&t=23126] ## Background

- - - - + + +

### History #### Milestones +- v1.7.0 - GUI (Adjustable Containers & Tabbed Windows) and Stats Tab - v1.6.0 - Clickable URLs, EMCO Timestamps, and Revisionator Patching - v1.5.0 - Auto-Install, Auto-Update, and Discord Rich Presence Integration - v1.2.0 - EMCO Command Line Interface @@ -69,12 +69,14 @@ Mudlet Forum Topic: [https://forums.mudlet.org/viewtopic.php?f=6&t=23126] ### Features +- GUI with adjustable, dockable, and resizable tabbed windows. - Automatic GMCP mapping of Procedural Realms MUD, including instanced areas/zones. - Automatic GMCP room styling based on terrain to matches colors in PR's 'map' and 'look' quickmap. -- Tabbed Communications Channels with CLI -- Adjustable, dockable, resizable, and no conversations lost in scroll! +- Tabbed Communications Channels with CLI -- No conversations lost in scroll! - Self-Updating Gauges for character vitals, including Hit Points, Energy, Stamina, Rage, Combo, and eXperience Points. - Speedwalking and pathfinding - Efficiently get where you're going - and fast! -- Discord Rich Presence integration +- Slot Command Buttons & Keys - Carry out custom actions with the click of a button! +- Discord Rich Presence Integration - Clickable URLs ### Built With @@ -83,6 +85,7 @@ Mudlet Forum Topic: [https://forums.mudlet.org/viewtopic.php?f=6&t=23126] - [Edbee Library](https://github.com/edbee/edbee-lib) provides the text editor component for Mudlet - [Mudlet](https://github.com/Mudlet/Mudlet) is a cross-platform, open source, and super fast MUD client - [MDK](https://github.com/demonnic/MDK) is a collection of Lua 'classes' and modules by @demonnic +- [AdjustableTabWindow](https://github.com/Edru2/AdjustableTabWindow) by @edru2 provides drag and drop tab support. - [Git](https://git-scm.com) is the version-control system for tracking changes and project management - [ImgBot](https://github.com/dabutvin/Imgbot) provides GitHub-integrated image optimization @@ -98,7 +101,7 @@ Version numbering approximates the [Semantic Versioning](http://semver.org) appr - **Project State**: Procedural Realms Script is under active development. The application can be used, but may be unstable. We are in need of continued testing prior to moving forward with each new release. -- **Current Release**: v1.6.0 +- **Current Release**: v1.7.0 **[^Top](#table-of-contents)** @@ -128,14 +131,17 @@ To manually install PRS, just follow these steps: ### Initial Setup -Upon initial install and/or update, you may need to close and re-open your Procedural Realms profile in Mudlet. You will then typically need to connect to the game server, and resize the UI windows both horizontally and vertically to reveal their contents fully. See **[UI Configuration](#user-interface-configuration)** below. +Upon initial install and/or update, you may need to close and re-open your Procedural Realms profile and/or Mudlet. You will then typically need to connect to the game server, and configure the User Interface. See **[UI Configuration](#user-interface-configuration)** below. ### Dependencies Mudlet +Aside from Mudlet, all the required dependencies are included in the PRS release package, requiring no additional download/install by the user. + +- A modified [AdjustableTabWindows](https://github.com/Edru2/AdjustableTabWindow) is included for GUI management. - [Mudlet][mudlet-url] MUD Client application must obviously be installed on your operating system (Windows, MacOS, and Linux) -- [MDK](https://github.com/demonnic/MDK) provides EMCO, Revisionator, and SUG support. The required code is already included in the PRS release package, requiring no additional download/install by the user. +- Included [MDK](https://github.com/demonnic/MDK) modules provide EMCO, Revisionator, and SUG support. ### Getting the Source @@ -151,12 +157,18 @@ You can also clone the entire project directly with this command: `git clone git ### User Interface Configuration -There are two fully configurable UI elements that are currently included in PRS by default: the EMCO (Communications Tabs and Map) and the Vitals (character Stat guages) windows. The UI windows are docked on the right of mudlet's main display upon connection to the game server. The windows may be resized by dragging their borders, moved by click/dragging their window title/headings, as well as undocked or closed by clicking on their respective upper-right pop-out or close icons. +Upon initial intallation of PRS, there are six fully configurable *adustable container* 'windows' included by default: Four containers -- two attached to either side of the main display -- include various *adjustable tab windows*. The default tabs include the EMCO (communications tabs), Mudlet Mapper, Vitals (self-updating character status gauges), Statistics summarizing the in-game `score` command data, and a Combat tab with dynamic Combo and Rage gauges during battle. The remaining two windows are attached to the top and bottom of the main display. The default top window contains 12 buttons. Each button corresponds to the 12 in-game *quick slots*, and is bound to the `F1` through `F12` reflecting slots `1` through `0`, `-`, and `=`. See the in-game `help slot` command for details on quick slots. +

+ -1. **Resize Windows**: On initial usage, you will typically need to resize the windows both horizontally and vertically to reveal their contents fully. Note that the window configurations are preserved but not restored until connection to the game server has been established. -2. **Layout Preferences:** You can optionally drag, re-arrange, pop out, and otherwise move the two PRS windows to your liking. +1. **Arrange Windows & Tabs**: On initial usage, all six PRS windows are in their unlocked state as indicated by their bright green borders and titles. The adjustable containers and their tabs may be resized by dragging their borders, moved by click/dragging their window title/headings, as well as minimized or closed by clicking on their respective upper-right minimize/restore or close icons.* You may optionally drag, re-arrange, pop out, and otherwise move all PRS tabs and windows to your liking. The author has provided a brief video demonstration of the adjustable tab windows' functionality within adjustable containers below.
+
Adjustable Tab Windows Video +

+**_*Note_**: There is presently no quick way to reopen a window once closed. Rather, you may restore the initial default windows and layout settings by closing Mudlet, navigating to the Mudlet profile's directory on your computer, and then recursively deleting the `/PRS/settings` directory and the `TabWindowTabs.lua` file in the root `/PRS/` directory. + +2. **Lock Windows**: Once you have arranged the layout to your liking, you may *lock* each window in place using the menu displayed by right-clicking on the bright green container title area, and selecting `lock` or `lock style` --> `standard`. The window/tab layout configurations are preserved when the Mudlet profile is closed. ### Command Line Interface diff --git a/procrealms-2.png b/procrealms-2.png deleted file mode 100644 index e7f0b66..0000000 Binary files a/procrealms-2.png and /dev/null differ diff --git a/prs-chat.lua b/prs-chat.lua index b8faed1..268374c 100644 --- a/prs-chat.lua +++ b/prs-chat.lua @@ -1,125 +1,111 @@ +-- Procedural Realms Script (PRS) Communications for Mudlet +-- by Stack (https://ilpdev.com/prs) & Dalem PRSchat = PRSchat or {} PRSchat.triggers = PRSchat.triggers or {} local EMCO = require("PRS.emco") local rev = require("PRS.revisionator") -function PRSchat.tabs() - local title_text - if gmcp and gmcp.Char and gmcp.Char.player then - title_text = "Procedural Realms - " .. gmcp.Char.player.name - else - title_text = "Procedural Realms" - registerAnonymousEventHandler("gmcp.Char.player.name", function() - PRSchat.UW:setTitle("Procedural Realms - " .. gmcp.Char.player.name) - end, true) +PRSchat.EMCO = EMCO:new({ + name = "PRSchatTabs", + x = "0", + y = "0", + width = "100%", + height = "100%", + allTab = true, + allTabName = "All", + consoleContainerColor = "transparent", + gap = 2, + leftMargin = 10, + topMargin = 10, + rightMargin = 10, + bottomMargin = 10, + consoleColor = "#101014", + consoles = {"Chat", "Newbie", "Trade", "Local", "Tell", "All"}, + mapTab = false, + activeTabCSS = stylesheet, + inactiveTabCSS = istylesheet, + preserveBackground = false, + timestamp = true, + customTimestampColor = true, + timestampFGColor = "dim_gray", + timestampBGColor = "#101014" +}, tabwindow4) + +GUI.tabwindow4:transferEMCO(PRSchat.EMCO) + +local emcoRev = rev:new({ + name = "prsRevisionator" +}) + +emcoRev:addPatch(function() + --- patch for v1.6.0 + PRSchat.EMCO.tabBold = true + PRSchat.EMCO:setActiveTabFGColor("white") + PRSchat.EMCO:setinactiveTabFGColor("gray") + PRSchat.EMCO:enableTimeStamp() + PRSchat.EMCO:enableCustomTimestampColor() + PRSchat.EMCO:setTimestampFGColor("dim_gray") + --- patch for 1.7.0 + PRSchat.EMCO.leftMargin = 10 + PRSchat.EMCO.topMargin = 10 + PRSchat.EMCO.rightMargin = 10 + PRSchat.EMCO.bottomMargin = 10 + PRSchat.EMCO:disableMapTab() + PRSchat.EMCO:disablePreserveBackground() + PRSchat.EMCO:setConsoleContainerColor("transparent") + PRSchat.EMCO.setconsoleColor("#101014") + PRSchat.EMCO:setTimestampBGColor("#101014") +end) + +local function saver(eventName, packageName) + if eventName == "sysExitEvent" or packageName == "PRS" then + PRSchat.EMCO:save() end +end - PRSchat.UW = Geyser.UserWindow:new({ - name = "Chat", - titleText = title_text, - y = "50%", - docked = true, - width = "25%", - height = "75%" - }) - - local stylesheet = - [[background-color: rgb(80,80,80,255); border-width: 1px; border-style: solid; border-color: black; border-radius: 0px;]] - local istylesheet = - [[background-color: rgb(60,60,60,255); border-width: 1px; border-style: solid; border-color: black; border-radius: 0px;]] - - PRSchat.EMCO = EMCO:new({ - name = "PRSchatTabs", - x = "0", - y = "0", - width = "100%", - height = "100%", - allTab = true, - allTabName = "All", - gap = 2, - leftMargin = 2, - consoleColor = "black", - consoles = {"Chat", "Newbie", "Trade", "Local", "Tell", "All", "Map"}, - mapTabName = "Map", - mapTab = true, - tabBold = true, - activeTabFGColor = "white", - inactiveTabFGColor = "gray", - activeTabCSS = stylesheet, - inactiveTabCSS = istylesheet, - preserveBackground = true, - timestamp = true, - customTimestampColor = true, - timestampFGColor = "dim_gray", - timestampBGColor = "black" - }, PRSchat.UW) - - local emcoRev = rev:new({ - name = "prsRevisionator" - }) - - emcoRev:addPatch(function() - --- patch for v1.6.0 - PRSchat.EMCO.leftMargin = 2 - PRSchat.EMCO.tabBold = true - PRSchat.EMCO:setActiveTabFGColor("white") - PRSchat.EMCO:setinactiveTabFGColor("gray") - PRSchat.EMCO:enableTimeStamp() - PRSchat.EMCO:enableCustomTimestampColor() - PRSchat.EMCO:setTimestampFGColor("dim_gray") - PRSchat.EMCO:setTimestampBGColor("black") - end) - - local function saver(eventName, packageName) - if eventName == "sysExitEvent" or packageName == "PRS" then +local function loader(eventName, packageName) + if eventName == "sysLoadEvent" or packageName == "PRS" then + PRSchat.EMCO:load() + -- new stuff below here + local changed = emcoRev:migrate() + if changed then -- save the emco changes back to its own save file PRSchat.EMCO:save() end end +end - local function loader(eventName, packageName) - if eventName == "sysLoadEvent" or packageName == "PRS" then - PRSchat.EMCO:load() - -- new stuff below here - local changed = emcoRev:migrate() - if changed then -- save the emco changes back to its own save file - PRSchat.EMCO:save() - end - end +PRSchat.EMCO:setCmdAction("Chat", function(str) + send("chat " .. str) +end) +PRSchat.EMCO.mc["Chat"]:enableCommandLine() +PRSchat.EMCO:setCmdAction("Newbie", function(str) + send("newbie " .. str) +end) +PRSchat.EMCO.mc["Newbie"]:enableCommandLine() +PRSchat.EMCO:setCmdAction("Trade", function(str) + send("trade " .. str) +end) +PRSchat.EMCO.mc["Trade"]:enableCommandLine() +PRSchat.EMCO:setCmdAction("Local", function(str) + send("say " .. str) +end) +PRSchat.EMCO.mc["Local"]:enableCommandLine() +local tell_rex = rex.new("^@(?\\w+) (?.+)$") +PRSchat.EMCO:setCmdAction("Tell", function(str) + local _, _, matches = tell_rex:tfind(str) + if matches then + send(f "tell {matches.to} {matches.msg}") + else + send("reply " .. str) end +end) +PRSchat.EMCO.mc["Tell"]:enableCommandLine() - PRSchat.EMCO:setCmdAction("Chat", function(str) - send("chat " .. str) - end) - PRSchat.EMCO.mc["Chat"]:enableCommandLine() - PRSchat.EMCO:setCmdAction("Newbie", function(str) - send("newbie " .. str) - end) - PRSchat.EMCO.mc["Newbie"]:enableCommandLine() - PRSchat.EMCO:setCmdAction("Trade", function(str) - send("trade " .. str) - end) - PRSchat.EMCO.mc["Trade"]:enableCommandLine() - PRSchat.EMCO:setCmdAction("Local", function(str) - send("say " .. str) - end) - PRSchat.EMCO.mc["Local"]:enableCommandLine() - local tell_rex = rex.new("^@(?\\w+) (?.+)$") - PRSchat.EMCO:setCmdAction("Tell", function(str) - local _, _, matches = tell_rex:tfind(str) - if matches then - send(f "tell {matches.to} {matches.msg}") - else - send("reply " .. str) - end - end) - PRSchat.EMCO.mc["Tell"]:enableCommandLine() - - registerNamedEventHandler("PRS", "load", "sysLoadEvent", loader) - registerNamedEventHandler("PRS", "install", "sysInstall", loader) - registerNamedEventHandler("PRS", "exit", "sysExitEvent", saver) - registerNamedEventHandler("PRS", "uninstall", "sysUninstall", saver) -end +registerNamedEventHandler("PRS", "load", "sysLoadEvent", loader) +registerNamedEventHandler("PRS", "install", "sysInstall", loader) +registerNamedEventHandler("PRS", "exit", "sysExitEvent", saver) +registerNamedEventHandler("PRS", "uninstall", "sysUninstall", saver) function PRSchat.stop() for k, v in pairs(PRSchat.triggers) do @@ -141,7 +127,7 @@ function PRSchat.initialize() local concat_lines = table.concat(chat_lines) local result = concat_lines:sub(1, -2) .. "\n" - PRSchat.EMCO:decho("Chat", result, false) + PRSchat.EMCO:decho("Chat", result:gsub(":0,0,0>", ":16,16,20>"), false) killTrigger(PRSchat.triggers.chat_line_id) PRSchat.triggers.chat_line_id = nil else @@ -162,7 +148,7 @@ function PRSchat.initialize() local concat_lines = table.concat(chat_lines) local result = concat_lines:sub(1, -2) .. "\n" - PRSchat.EMCO:decho("Newbie", result, false) + PRSchat.EMCO:decho("Newbie", result:gsub(":0,0,0>", ":16,16,20>"), false) killTrigger(PRSchat.triggers.newbie_line_id) PRSchat.triggers.newbie_line_id = nil else @@ -183,7 +169,7 @@ function PRSchat.initialize() local concat_lines = table.concat(chat_lines) local result = concat_lines:sub(1, -2) .. "\n" - PRSchat.EMCO:decho("Trade", result, false) + PRSchat.EMCO:decho("Trade", result:gsub(":0,0,0>", ":16,16,20>"), false) killTrigger(PRSchat.triggers.trade_line_id) PRSchat.triggers.trade_line_id = nil else @@ -205,7 +191,7 @@ function PRSchat.initialize() local concat_lines = table.concat(chat_lines) local result = concat_lines:sub(1, -2) .. "\n" - PRSchat.EMCO:decho("Local", result, false) + PRSchat.EMCO:decho("Local", result:gsub(":0,0,0>", ":16,16,20>"), false) killTrigger(PRSchat.triggers.local_line_id) PRSchat.triggers.local_line_id = nil end @@ -226,7 +212,7 @@ function PRSchat.initialize() local concat_lines = table.concat(chat_lines) local result = concat_lines:sub(1, -2) .. "\n" - PRSchat.EMCO:decho("Tell", result, false) + PRSchat.EMCO:decho("Tell", result:gsub(":0,0,0>", ":16,16,20>"), false) killTrigger(PRSchat.triggers.tell_line_id) PRSchat.triggers.tell_line_id = nil end @@ -235,4 +221,4 @@ function PRSchat.initialize() end) end end -PRSchat.initialize() +PRSchat.initialize() \ No newline at end of file diff --git a/prs-core.lua b/prs-core.lua index f68acf4..4007cbb 100644 --- a/prs-core.lua +++ b/prs-core.lua @@ -1,3 +1,6 @@ +-- Procedural Realms Script (PRS) GMCP Events Core for Mudlet +-- by Dalem +-- https://ilpdev.com/prs core = core or {} core.events = core.events or {} diff --git a/prs-gui.lua b/prs-gui.lua new file mode 100644 index 0000000..feab295 --- /dev/null +++ b/prs-gui.lua @@ -0,0 +1,469 @@ +-- Procedural Realms Script (PRS) Graphical User Interface (GUI) for Mudlet +-- by Stack (https://ilpdev.com/prs) +GUI = GUI or {} + +-------[ Skin Mudlet Toolbar ]----------------------------- +setAppStyleSheet([[ +QToolBar { + background-color: rgb(24,24,28); +} + +QToolBar QToolButton:!hover { + color: white; +} +QToolBar QToolButton:hover { + color: black; +} +]]) + +require "PRS.AdjustableTabWindow" -- PR-specific version of edru's code + +-------[ Spawn the Adjustable Containers ]----------------------------- +GUI.top = Adjustable.Container:new({ + name = "top", + y = "0%", + height = "10%", + adjLabelstyle = "border: 1px solid green;", + defaultDir = string.format("%s/PRS/settings/", getMudletHomeDir()) +}) +GUI.bottom = Adjustable.Container:new({ + name = "bottom", + height = "10%", + y = "-10%", + adjLabelstyle = "border: 1px solid green;", + defaultDir = string.format("%s/PRS/settings/", getMudletHomeDir()) +}) +GUI.right_top = Adjustable.Container:new({ + name = "right_top", + x = "-20%", + y = "0%", + height = "50%", + width = "20%", + adjLabelstyle = "border: 1px solid green;", + defaultDir = string.format("%s/PRS/settings/", getMudletHomeDir()) +}) + +GUI.right_bottom = Adjustable.Container:new({ + name = "right_bottom", + x = "-20%", + y = "50%", + height = "50%", + width = "20%", + adjLabelstyle = "border: 1px solid green;", + defaultDir = string.format("%s/PRS/settings/", getMudletHomeDir()) +}) + +GUI.left_top = Adjustable.Container:new({ + name = "left_top", + x = "0%", + y = "0%", + height = "50%", + width = "20%", + adjLabelstyle = "border: 1px solid green;", + defaultDir = string.format("%s/PRS/settings/", getMudletHomeDir()) +}) + +GUI.left_bottom = Adjustable.Container:new({ + name = "left_bottom", + x = "0%", + y = "50%", + height = "50%", + width = "20%", + adjLabelstyle = "border: 1px solid green;", + defaultDir = string.format("%s/PRS/settings/", getMudletHomeDir()) +}) + +Adjustable.Container:doAll(function(self) -- add connect menu to all adjustable containers + self:addConnectMenu() +end) + +-------[ Attach and Connect Borders of Adjustable Containers ]----------------- +GUI.top:attachToBorder("top") +GUI.bottom:attachToBorder("bottom") +GUI.left_top:attachToBorder("left") +GUI.left_bottom:attachToBorder("left") +GUI.right_top:attachToBorder("right") +GUI.right_bottom:attachToBorder("right") + +GUI.top:connectToBorder("left") +GUI.top:connectToBorder("right") +GUI.bottom:connectToBorder("left") +GUI.bottom:connectToBorder("right") +GUI.left_top:connectToBorder("left") +GUI.left_bottom:connectToBorder("left") +GUI.right_top:connectToBorder("right") +GUI.right_bottom:connectToBorder("right") + +GUI.top:changeMenuStyle("dark") +GUI.bottom:changeMenuStyle("dark") +GUI.right_top:changeMenuStyle("dark") +GUI.right_bottom:changeMenuStyle("dark") +GUI.left_top:changeMenuStyle("dark") +GUI.left_bottom:changeMenuStyle("dark") + +-------[ Add TabWindows to Adjustable Containers ]----------------------------- +GUI.tabwindow1 = GUI.tabwindow1 or Adjustable.TabWindow:new({ + name = "tabwindow1", + x = 0, + y = 0, + width = "100%", + height = "100%", + tabBarHeight = "10%", + activeTabFGColor = "#DDDDDD", + inactiveTabFGColor = "#555555", + color1 = "rgb(24,24,28)", + color2 = "rgb(16,16,20)", + tabs = {"Vitals", "Stats"} +}, GUI.left_top) + +GUI.tabwindow2 = GUI.tabwindow2 or Adjustable.TabWindow:new({ + name = "tabwindow2", + x = 0, + y = 0, + width = "100%", + height = "100%", + tabBarHeight = "10%", + activeTabFGColor = "#DDDDDD", + inactiveTabFGColor = "#555555", + color1 = "rgb(24,24,28)", + color2 = "rgb(16,16,20)", + tabs = {"Combat"} +}, GUI.left_bottom) + +GUI.tabwindow3 = GUI.tabwindow3 or Adjustable.TabWindow:new({ + name = "tabwindow3", + x = 0, + y = 0, + width = "100%", + height = "100%", + tabBarHeight = "10%", + activeTabFGColor = "#DDDDDD", + inactiveTabFGColor = "#555555", + color1 = "rgb(24,24,28)", + color2 = "rgb(16,16,20)", + tabs = {"Map"} +}, GUI.right_top) + +GUI.tabwindow4 = GUI.tabwindow4 or Adjustable.TabWindow:new({ + name = "tabwindow4", + x = 0, + y = 0, + width = "100%", + height = "100%", + tabBarHeight = "10%", + activeTabFGColor = "#DDDDDD", + inactiveTabFGColor = "#555555", + color1 = "rgb(24,24,28)", + color2 = "rgb(16,16,20)", + tabs = {} +}, GUI.right_bottom) + +-------[ Buttons ]------------------------------------------------------------- +GUI.buttons = Geyser.HBox:new({ + name = "buttons", + height = "25", + width = "98%" +}, GUI.top) + +local button1 = Geyser.Label:new({ + name = "button1", + message = [[
1
]] +}, GUI.buttons) +button1:setClickCallback("slot1") +button1:setToolTip("[F1]", "10") +button1:setStyleSheet([[ + QLabel { + background-color: rgb(16,16,20); + border: 1px solid black; + border-radius: 3px; + } + QLabel::hover { + background-color: rgb(24,24,28); + border: 1px solid black; + border-radius: 3px; + } +]]) +function slot1() + send("1") +end + +local button2 = Geyser.Label:new({ + name = "button2", + message = [[
2
]] +}, GUI.buttons) +button2:setClickCallback("slot2") +button2:setToolTip("[F2]", "10") +button2:setStyleSheet([[ + QLabel { + background-color: rgb(16,16,20); + border: 1px solid black; + border-radius: 3px; + } + QLabel::hover { + background-color: rgb(24,24,28); + border: 1px solid black; + border-radius: 3px; + } +]]) +function slot2() + send("2") +end + +local button3 = Geyser.Label:new({ + name = "button3", + message = [[
3
]] +}, GUI.buttons) +button3:setClickCallback("slot3") +button3:setToolTip("[F3]", "10") +button3:setStyleSheet([[ + QLabel { + background-color: rgb(16,16,20); + border: 1px solid black; + border-radius: 3px; + } + QLabel::hover { + background-color: rgb(24,24,28); + border: 1px solid black; + border-radius: 3px; + } +]]) +function slot3() + send("3") +end + +local button4 = Geyser.Label:new({ + name = "button4", + message = [[
4
]] +}, GUI.buttons) +button4:setClickCallback("slot4") +button4:setToolTip("[F4]", "10") +button4:setStyleSheet([[ + QLabel { + background-color: rgb(16,16,20); + border: 1px solid black; + border-radius: 3px; + } + QLabel::hover { + background-color: rgb(24,24,28); + border: 1px solid black; + border-radius: 3px; + } +]]) +function slot4() + send("4") +end + +local button5 = Geyser.Label:new({ + name = "button5", + message = [[
5
]] +}, GUI.buttons) +button5:setClickCallback("slot5") +button5:setToolTip("[F5]", "10") +button5:setStyleSheet([[ + QLabel { + background-color: rgb(16,16,20); + border: 1px solid black; + border-radius: 3px; + } + QLabel::hover { + background-color: rgb(24,24,28); + border: 1px solid black; + border-radius: 3px; + } +]]) +function slot5() + send("5") +end + +local button6 = Geyser.Label:new({ + name = "button6", + message = [[
6
]] +}, GUI.buttons) +button6:setClickCallback("slot6") +button6:setToolTip("[F6]", "10") +button6:setStyleSheet([[ + QLabel { + background-color: rgb(16,16,20); + border: 1px solid black; + border-radius: 3px; + } + QLabel::hover { + background-color: rgb(24,24,28); + border: 1px solid black; + border-radius: 3px; + } +]]) +function slot6() + send("6") +end + +local button7 = Geyser.Label:new({ + name = "button7", + message = [[
7
]] +}, GUI.buttons) +button7:setClickCallback("slot7") +button7:setToolTip("[F7]", "10") +button7:setStyleSheet([[ + QLabel { + background-color: rgb(16,16,20); + border: 1px solid black; + border-radius: 3px; + } + QLabel::hover { + background-color: rgb(24,24,28); + border: 1px solid black; + border-radius: 3px; + } +]]) +function slot7() + send("7") +end + +local button8 = Geyser.Label:new({ + name = "button8", + message = [[
8
]] +}, GUI.buttons) +button8:setClickCallback("slot8") +button8:setToolTip("[F8]", "10") +button8:setStyleSheet([[ + QLabel { + background-color: rgb(16,16,20); + border: 1px solid black; + border-radius: 3px; + } + QLabel::hover { + background-color: rgb(24,24,28); + border: 1px solid black; + border-radius: 3px; + } +]]) +function slot8() + send("8") +end + +local button9 = Geyser.Label:new({ + name = "button9", + message = [[
9
]] +}, GUI.buttons) +button9:setClickCallback("slot9") +button9:setToolTip("[F9]", "10") +button9:setStyleSheet([[ + QLabel { + background-color: rgb(16,16,20); + border: 1px solid black; + border-radius: 3px; + } + QLabel::hover { + background-color: rgb(24,24,28); + border: 1px solid black; + border-radius: 3px; + } +]]) +function slot9() + send("9") +end + +local button10 = Geyser.Label:new({ + name = "button10", + message = [[
0
]] +}, GUI.buttons) +button10:setClickCallback("slot10") +button10:setToolTip("[F10]", "10") +button10:setStyleSheet([[ + QLabel { + background-color: rgb(16,16,20); + border: 1px solid black; + border-radius: 3px; + } + QLabel::hover { + background-color: rgb(24,24,28); + border: 1px solid black; + border-radius: 3px; + } +]]) +function slot10() + send("0") +end + +local button11 = Geyser.Label:new({ + name = "button11", + message = [[
-
]] +}, GUI.buttons) +button11:setClickCallback("slot11") +button11:setToolTip("[F11]", "10") +button11:setStyleSheet([[ + QLabel { + background-color: rgb(16,16,20); + border: 1px solid black; + border-radius: 3px; + } + QLabel::hover { + background-color: rgb(24,24,28); + border: 1px solid black; + border-radius: 3px; + } +]]) +function slot11() + send("-") +end + +local button12 = Geyser.Label:new({ + name = "button12", + message = [[
=
]] +}, GUI.buttons) +button12:setClickCallback("slot12") +button12:setToolTip("[F12]", "10") +button12:setStyleSheet([[ + QLabel { + background-color: rgb(16,16,20); + border: 1px solid black; + border-radius: 3px; + } + QLabel::hover { + background-color: rgb(24,24,28); + border: 1px solid black; + border-radius: 3px; + } +]]) +function slot12() + send("=") +end + +local button13 = Geyser.Label:new({ + name = "vote", + message = [[
Vote!
]] +}, GUI.buttons) +button13:setClickCallback("vote") +button13:setToolTip("Vote for PR daily!", "10") +button13:setStyleSheet([[ + QLabel { + background-color: rgb(16,16,20); + border: 1px solid black; + border-radius: 3px; + } + QLabel::hover { + background-color: rgb(24,24,28); + border: 1px solid black; + border-radius: 3px; + } +]]) +function vote() + openUrl("https://www.mudverse.com/vote/531") +end + +-------[ Spawn Mudlet Mapper ]--------------------------------- +GUI.mapper = GUI.mapper or Geyser.Mapper:new({ + name = "mapper", + x = 5, + y = 5, + width = "96%", + height = "97%" +}, GUI.tabwindow3.Mapcenter) + +-------[ Save/Load User Tab Prefs ]----------------------------- +GUI.tabwindow1:load(1, string.format("%s/PRS/settings/", getMudletHomeDir())) -- Load all tabs + +function SaveTabsOnExit() + GUI.tabwindow1:save(1, string.format("%s/PRS/settings/", getMudletHomeDir())) -- Save all tabs on exit +end +registerAnonymousEventHandler("sysExitEvent", SaveTabsOnExit) diff --git a/prs-mapper.lua b/prs-mapper.lua index 1d7f202..d00e10e 100644 --- a/prs-mapper.lua +++ b/prs-mapper.lua @@ -1,5 +1,5 @@ --- Procedural Realms Mapping Script --- by Stack (https://ilpdev.com/prs) based on generic GMCP mapping script +-- Procedural Realms Script (PRS) for Mudlet +-- by Stack (https://ilpdev.com/prs) and Dalem based on generic GMCP mapping script -- by Blizzard (https://worldofpa.in) based upon an MSDP script from the Mudlet -- forums in the generic mapper thread with pieces from Jor'Mox's generic mapper -- script and the mmpkg mapper by breakone9r. diff --git a/prs-screenshot-01.png b/prs-screenshot-01.png deleted file mode 100644 index 3d9b3ec..0000000 Binary files a/prs-screenshot-01.png and /dev/null differ diff --git a/prs-screenshot-02.png b/prs-screenshot-02.png deleted file mode 100644 index e6f3ae1..0000000 Binary files a/prs-screenshot-02.png and /dev/null differ diff --git a/prs-stats.lua b/prs-stats.lua index cec34a4..caf1f77 100644 --- a/prs-stats.lua +++ b/prs-stats.lua @@ -1,12 +1,731 @@ +-- Procedural Realms Script (PRS) Stats Gauges for Mudlet +-- by Stack (https://ilpdev.com/prs) & Dalem PRSstats = PRSstats or {} PRSstats.events = PRSstats.events or {} local SUG = require("PRS.sug") +local function vitalsHeader() + local header = Geyser.HBox:new({ + name = "header", + height = 25, + width = "93%" + }, GUI.tabwindow1.Vitalscenter) + local name = Geyser.Label:new({ + name = "name" + }, header) + name:setFontSize(12) + name:setColor(0, 0, 0, 0) + name:echo(gmcp.Char.player.name, "#f9f1a5", "l") + local class = Geyser.Label:new({ + name = "class" + }, header) + class:setFontSize(12) + class:setColor(0, 0, 0, 0) + class:echo(gmcp.Char.player.class, "#b4009e", "c") + if PRSstats.events.classChange_id then + killAnonymousEventHandler(PRSstats.events.classChange_id) + end + PRSstats.events.classChange_id = registerAnonymousEventHandler("gmcp.Char.player.class", function() + if gmcp.Char.player.class then + class:echo(gmcp.Char.player.class, "#b4009e", "c") + end + end) + local level = Geyser.Label:new({ + name = "level" + }, header) + level:setFontSize(12) + level:setColor(0, 0, 0, 0) + level:echo("Level " .. gmcp.Char.player.level, "#ababab", "r") + if PRSstats.events.levelChange_id then + killAnonymousEventHandler(PRSstats.events.levelChange_id) + end + PRSstats.events.levelChange_id = registerAnonymousEventHandler("gmcp.Char.player.level", function() + if gmcp.Char.player.level then + level:echo("Level " .. gmcp.Char.player.level, "#ababab", "r") + end + end) +end + +local function statsTab() + local statsVBox = Geyser.VBox:new({ + name = "statsVBox", + height = "95%", + width = "93%" + }, GUI.tabwindow1.Statscenter) + local abilitiesTitle = Geyser.Label:new({ + name = "abilitiesTitle", + height = 30 + }, statsVBox) + abilitiesTitle:setColor(0, 0, 0, 0) + abilitiesTitle:setFontSize(12) + abilitiesTitle:echo("Abilities", "#f2f2f2", "c") + -- Strength + local strengthHBox = Geyser.HBox:new({ + name = "strengthHBox", + width = "93%" + }, statsVBox) + local strengthTitle = Geyser.Label:new({ + name = "strengthTitle" + }, strengthHBox) + strengthTitle:setColor(0, 0, 0, 0) + strengthTitle:setFontSize(9) + strengthTitle:echo("Strength:", "#aaaaaa", "r") + local strength = Geyser.Label:new({ + name = "strength" + }, strengthHBox) + strength:setColor(0, 0, 0, 0) + strength:setFontSize(9) + strength:echo(gmcp.Char.player.strength, "#e74856", "c") + if PRSstats.events.strengthChange_id then + killAnonymousEventHandler(PRSstats.events.strengthChange_id) + end + PRSstats.events.strengthChange_id = registerAnonymousEventHandler("gmcp.Char.player.strength", function() + if gmcp.Char.player.strength then + strength:echo(gmcp.Char.player.strength, "#e74856", "c") + end + end) + local _strength = Geyser.Label:new({ + name = "_strength" + }, strengthHBox) + _strength:setColor(0, 0, 0, 0) + _strength:setFontSize(9) + _strength:echo("(" .. gmcp.Char.player._strength .. ")", "#c50f1f", "l") + if PRSstats.events._strengthChange_id then + killAnonymousEventHandler(PRSstats.events._strengthChange_id) + end + PRSstats.events._strengthChange_id = registerAnonymousEventHandler("gmcp.Char.player._strength", function() + if gmcp.Char.player._strength then + _strength:echo("(" .. gmcp.Char.player._strength .. ")", "#c50f1f", "l") + end + end) + -- Agility + local agilityHBox = Geyser.HBox:new({ + name = "agilityHBox", + width = "93%" + }, statsVBox) + local agilityTitle = Geyser.Label:new({ + name = "agilityTitle" + }, agilityHBox) + agilityTitle:setColor(0, 0, 0, 0) + agilityTitle:setFontSize(9) + agilityTitle:echo("Agility:", "#aaaaaa", "r") + local agility = Geyser.Label:new({ + name = "agility" + }, agilityHBox) + agility:setColor(0, 0, 0, 0) + agility:setFontSize(9) + agility:echo(gmcp.Char.player.agility, "#f9f1a5", "c") + if PRSstats.events.agilityChange_id then + killAnonymousEventHandler(PRSstats.events.agilityChange_id) + end + PRSstats.events.agilityChange_id = registerAnonymousEventHandler("gmcp.Char.player.agility", function() + if gmcp.Char.player.agility then + agility:echo(gmcp.Char.player.agility, "#f9f1a5", "c") + end + end) + local _agility = Geyser.Label:new({ + name = "_agility" + }, agilityHBox) + _agility:setColor(0, 0, 0, 0) + _agility:setFontSize(9) + _agility:echo("(" .. gmcp.Char.player._agility .. ")", "#c19c00", "l") + if PRSstats.events._agilityChange_id then + killAnonymousEventHandler(PRSstats.events._agilityChange_id) + end + PRSstats.events._agilityChange_id = registerAnonymousEventHandler("gmcp.Char.player._agility", function() + if gmcp.Char.player._agility then + _agility:echo("(" .. gmcp.Char.player._agility .. ")", "#c19c00", "l") + end + end) + -- Magic + local magicHBox = Geyser.HBox:new({ + name = "magicHBox", + width = "93%" + }, statsVBox) + local magicTitle = Geyser.Label:new({ + name = "magicTitle" + }, magicHBox) + magicTitle:setColor(0, 0, 0, 0) + magicTitle:setFontSize(9) + magicTitle:echo("Magic:", "#aaaaaa", "r") + local magic = Geyser.Label:new({ + name = "magic" + }, magicHBox) + magic:setColor(0, 0, 0, 0) + magic:setFontSize(9) + magic:echo(gmcp.Char.player.magic, "#61d6d6", "c") + if PRSstats.events.magicChange_id then + killAnonymousEventHandler(PRSstats.events.magicChange_id) + end + PRSstats.events.magicChange_id = registerAnonymousEventHandler("gmcp.Char.player.magic", function() + if gmcp.Char.player.magic then + magic:echo(gmcp.Char.player.magic, "#61d6d6", "c") + end + end) + local _magic = Geyser.Label:new({ + name = "_magic" + }, magicHBox) + _magic:setColor(0, 0, 0, 0) + _magic:setFontSize(9) + _magic:echo("(" .. gmcp.Char.player._magic .. ")", "#3a96dd", "l") + if PRSstats.events._magicChange_id then + killAnonymousEventHandler(PRSstats.events._magicChange_id) + end + PRSstats.events._magicChange_id = registerAnonymousEventHandler("gmcp.Char.player._magic", function() + if gmcp.Char.player._magic then + _magic:echo("(" .. gmcp.Char.player._magic .. ")", "#3a96dd", "l") + end + end) + -- Spirit + local spiritHBox = Geyser.HBox:new({ + name = "spiritHBox", + width = "93%" + }, statsVBox) + local spiritTitle = Geyser.Label:new({ + name = "spiritTitle" + }, spiritHBox) + spiritTitle:setColor(0, 0, 0, 0) + spiritTitle:setFontSize(9) + spiritTitle:echo("Spirit:", "#aaaaaa", "r") + local spirit = Geyser.Label:new({ + name = "spirit" + }, spiritHBox) + spirit:setColor(0, 0, 0, 0) + spirit:setFontSize(9) + spirit:echo(gmcp.Char.player.spirit, "#16c60c", "c") + if PRSstats.events.spiritChange_id then + killAnonymousEventHandler(PRSstats.events.spiritChange_id) + end + PRSstats.events.spiritChange_id = registerAnonymousEventHandler("gmcp.Char.player.spirit", function() + if gmcp.Char.player.spirit then + spirit:echo(gmcp.Char.player.spirit, "#16c60c", "c") + end + end) + local _spirit = Geyser.Label:new({ + name = "_spirit" + }, spiritHBox) + _spirit:setColor(0, 0, 0, 0) + _spirit:setFontSize(9) + _spirit:echo("(" .. gmcp.Char.player._spirit .. ")", "#13a10e", "l") + if PRSstats.events._spiritChange_id then + killAnonymousEventHandler(PRSstats.events._spiritChange_id) + end + PRSstats.events._spiritChange_id = registerAnonymousEventHandler("gmcp.Char.player._spirit", function() + if gmcp.Char.player._spirit then + _spirit:echo("(" .. gmcp.Char.player._spirit .. ")", "#13a10e", "l") + end + end) + + local combatTitle = Geyser.Label:new({ + name = "combatTitle", + height = 30 + }, statsVBox) + combatTitle:setColor(0, 0, 0, 0) + combatTitle:setFontSize(12) + combatTitle:echo("Combat", "#f2f2f2", "c") + -- Damage + local damageHBox = Geyser.HBox:new({ + name = "damageHBox", + width = "93%" + }, statsVBox) + local damageTitle = Geyser.Label:new({ + name = "damageTitle" + }, damageHBox) + damageTitle:setColor(0, 0, 0, 0) + damageTitle:setFontSize(9) + damageTitle:echo("Damage:", "#aaaaaa", "r") + local damage = Geyser.Label:new({ + name = "damage" + }, damageHBox) + damage:setColor(0, 0, 0, 0) + damage:setFontSize(9) + damage:echo("-", "#e74856", "c") + local dpr = Geyser.Label:new({ + name = "dpr" + }, damageHBox) + dpr:setColor(0, 0, 0, 0) + dpr:setFontSize(9) + dpr:echo(string.format("%0.1f", gmcp.Char.player.dpr) .. " dpr", "#c50f1f", "l") + if PRSstats.events.dprChange_id then + killAnonymousEventHandler(PRSstats.events.dprChange_id) + end + PRSstats.events.dprChange_id = registerAnonymousEventHandler("gmcp.Char.player.dpr", function() + if gmcp.Char.player.dpr then + damage:echo(string.format("%0.1f", gmcp.Char.player.dpr) .. " dpr", "#c50f1f", "l") + end + end) + -- Armor + local armorHBox = Geyser.HBox:new({ + name = "armorHBox", + width = "93%" + }, statsVBox) + local armorTitle = Geyser.Label:new({ + name = "armorTitle" + }, armorHBox) + armorTitle:setColor(0, 0, 0, 0) + armorTitle:setFontSize(9) + armorTitle:echo("Armor:", "#aaaaaa", "r") + local armor = Geyser.Label:new({ + name = "armor" + }, armorHBox) + armor:setColor(0, 0, 0, 0) + armor:setFontSize(9) + armor:echo(gmcp.Char.player.armor, "#f2f2f2", "c") + if PRSstats.events.armorChange_id then + killAnonymousEventHandler(PRSstats.events.armorChange_id) + end + PRSstats.events.armorChange_id = registerAnonymousEventHandler("gmcp.Char.player.armor", function() + if gmcp.Char.player.armor then + armor:echo(gmcp.Char.player.armor, "#f2f2f2", "c") + end + end) + local armorAbsorbtion = Geyser.Label:new({ + name = "armorAbsorbtion" + }, armorHBox) + armorAbsorbtion:setColor(0, 0, 0, 0) + armorAbsorbtion:setFontSize(9) + armorAbsorbtion:echo(gmcp.Char.player.armorAbsorbtion .. " absorb", "#f2f2f2", "l") + if PRSstats.events.armorAbsorbtionChange_id then + killAnonymousEventHandler(PRSstats.events.armorAbsorbtionChange_id) + end + PRSstats.events.armorAbsorbtionChange_id = registerAnonymousEventHandler("gmcp.Char.player.armorAbsorbtion", function() + if gmcp.Char.player.armorAbsorbtion then + armorAbsorbtion:echo(gmcp.Char.player.armorAbsorbtion .. " absorb", "#f2f2f2", "l") + end + end) + -- Speed + local speedHBox = Geyser.HBox:new({ + name = "speedHBox", + width = "93%" + }, statsVBox) + local speedTitle = Geyser.Label:new({ + name = "speedTitle" + }, speedHBox) + speedTitle:setColor(0, 0, 0, 0) + speedTitle:setFontSize(9) + speedTitle:echo("Speed:", "#aaaaaa", "r") + local speed = Geyser.Label:new({ + name = "speed" + }, speedHBox) + speed:setColor(0, 0, 0, 0) + speed:setFontSize(9) + speed:echo(gmcp.Char.player.speed, "#f9f1a5", "c") + if PRSstats.events.speedChange_id then + killAnonymousEventHandler(PRSstats.events.speedChange_id) + end + PRSstats.events.speedChange_id = registerAnonymousEventHandler("gmcp.Char.player.speed", function() + if gmcp.Char.player.speed then + speed:echo(gmcp.Char.player.speed, "#f9f1a5", "c") + end + end) + local apr = Geyser.Label:new({ + name = "apr" + }, speedHBox) + apr:setColor(0, 0, 0, 0) + apr:setFontSize(9) + apr:echo("- apr", "#f9f1a5", "l") + -- Critical + local criticalHBox = Geyser.HBox:new({ + name = "criticalHBox", + width = "93%" + }, statsVBox) + local criticalTitle = Geyser.Label:new({ + name = "criticalTitle" + }, criticalHBox) + criticalTitle:setColor(0, 0, 0, 0) + criticalTitle:setFontSize(9) + criticalTitle:echo("Critical:", "#aaaaaa", "r") + local criticalChance = Geyser.Label:new({ + name = "criticalChance" + }, criticalHBox) + criticalChance:setColor(0, 0, 0, 0) + criticalChance:setFontSize(9) + criticalChance:echo(string.format("%0.2f", gmcp.Char.player.criticalChance) .. "%", "#f9f1a5", "c") + if PRSstats.events.criticalChanceChange_id then + killAnonymousEventHandler(PRSstats.events.criticalChanceChange_id) + end + PRSstats.events.criticalChanceChange_id = registerAnonymousEventHandler("gmcp.Char.player.criticalChance", function() + if gmcp.Char.player.criticalChance then + criticalChance:echo(string.format("%0.2f", gmcp.Char.player.criticalChance) .. "%", "#f9f1a5", "c") + end + end) + local criticalMultiplier = Geyser.Label:new({ + name = "criticalMultiplier" + }, criticalHBox) + criticalMultiplier:setColor(0, 0, 0, 0) + criticalMultiplier:setFontSize(9) + criticalMultiplier:echo(string.format("%0.2f", gmcp.Char.player.criticalMultiplier) .. "x", "#e74856", "l") + if PRSstats.events.criticalMultiplierChange_id then + killAnonymousEventHandler(PRSstats.events.criticalMultiplierChange_id) + end + PRSstats.events.criticalMultiplierChange_id = registerAnonymousEventHandler("gmcp.Char.player.criticalMultiplier", function() + if gmcp.Char.player.criticalMultiplier then + criticalMultiplier:echo(string.format("%0.2f", gmcp.Char.player.criticalMultiplier) .. "x", "#e74856", "l") + end + end) + -- Magic Damage & Casting + local magicDamageHBox = Geyser.HBox:new({ + name = "magicDamageHBox", + width = "93%" + }, statsVBox) + local magicDamageBonusTitle = Geyser.Label:new({ + name = "magicDamageBonusTitle" + }, magicDamageHBox) + magicDamageBonusTitle:setColor(0, 0, 0, 0) + magicDamageBonusTitle:setFontSize(9) + magicDamageBonusTitle:echo("Magic:", "#aaaaaa", "r") + local magicDamageBonus = Geyser.Label:new({ + name = "magicDamageBonus" + }, magicDamageHBox) + magicDamageBonus:setColor(0, 0, 0, 0) + magicDamageBonus:setFontSize(9) + magicDamageBonus:echo("+" .. gmcp.Char.player.magicDamageBonus, "#b4009e", "c") + if PRSstats.events.magicDamageBonusChange_id then + killAnonymousEventHandler(PRSstats.events.magicDamageBonusChange_id) + end + PRSstats.events.magicDamageBonusChange_id = registerAnonymousEventHandler("gmcp.Char.player.magicDamageBonus", function() + if gmcp.Char.player.magicDamageBonus then + magicDamageBonus:echo("+" .. gmcp.Char.player.magicDamageBonus, "#b4009e", "c") + end + end) + local magicCasting = Geyser.Label:new({ + name = "magicCasting" + }, magicDamageHBox) + magicCasting:setColor(0, 0, 0, 0) + magicCasting:setFontSize(9) + magicCasting:echo("cast " .. string.format("%0.2f", gmcp.Char.player.magicCastingTimeBonus) .. "s", "#61d6d6", "l") + if PRSstats.events.magicCastingChange_id then + killAnonymousEventHandler(PRSstats.events.magicCastingChange_id) + end + PRSstats.events.magicCastingChange_id = registerAnonymousEventHandler("gmcp.Char.player.magicCastingTimeBonus", function() + if gmcp.Char.player.magicCasting then + magicCasting:echo("cast " .. string.format("%0.2f", gmcp.Char.player.magicCastingTimeBonus) .. "s", "#61d6d6", "l") + end + end) + -- Focus + local focusHBox = Geyser.HBox:new({ + name = "focusHBox", + width = "93%" + }, statsVBox) + local focusTitle = Geyser.Label:new({ + name = "focusTitle" + }, focusHBox) + focusTitle:setColor(0, 0, 0, 0) + focusTitle:setFontSize(9) + focusTitle:echo("Focus:", "#aaaaaa", "r") + local focus = Geyser.Label:new({ + name = "focus" + }, focusHBox) + focus:setColor(0, 0, 0, 0) + focus:setFontSize(9) + focus:echo(gmcp.Char.player.focus, "#3b78ff", "c") + if PRSstats.events.focusChange_id then + killAnonymousEventHandler(PRSstats.events.focusChange_id) + end + PRSstats.events.focusChange_id = registerAnonymousEventHandler("gmcp.Char.player.focus", function() + if gmcp.Char.player.focus then + focus:echo(gmcp.Char.player.focus, "#3b78ff", "c") + end + end) + local focusChance = Geyser.Label:new({ + name = "focusChance" + }, focusHBox) + focusChance:setColor(0, 0, 0, 0) + focusChance:setFontSize(9) + focusChance:echo(string.format("%0.2f", gmcp.Char.player.focusChance) .. "%", "#3b78ff", "l") + if PRSstats.events.focusChanceChange_id then + killAnonymousEventHandler(PRSstats.events.focusChanceChange_id) + end + PRSstats.events.focusChanceChange_id = registerAnonymousEventHandler("gmcp.Char.player.focusChance", function() + if gmcp.Char.player.focusChance then + focusChance:echo(string.format("%0.2f", gmcp.Char.player.focusChance) .. "%", "#3b78ff", "l") + end + end) + local resistancesTitle = Geyser.Label:new({ + name = "resistancesTitle", + height = 30 + }, statsVBox) + resistancesTitle:setColor(0, 0, 0, 0) + resistancesTitle:setFontSize(12) + resistancesTitle:echo("Resistances", "#f2f2f2", "c") + -- Bludgeon & Arcane + local resist1HBox = Geyser.HBox:new({ + name = "resist1HBox", + width = "93%" + }, statsVBox) + local resistBludgeoningTitle = Geyser.Label:new({ + name = "resistBludgeoningTitle" + }, resist1HBox) + resistBludgeoningTitle:setColor(0, 0, 0, 0) + resistBludgeoningTitle:setFontSize(9) + resistBludgeoningTitle:echo("Bludgeon: ", "#aaaaaa", "r") + local resistBludgeoning = Geyser.Label:new({ + name = "resistBludgeoning" + }, resist1HBox) + resistBludgeoning:setColor(0, 0, 0, 0) + resistBludgeoning:setFontSize(9) + resistBludgeoning:echo(gmcp.Char.player.resistBludgeoning, "#c19c00", "l") + if PRSstats.events.resistBludgeoningChange_id then + killAnonymousEventHandler(PRSstats.events.resistBludgeoningChange_id) + end + PRSstats.events.resistBludgeoningChange_id = registerAnonymousEventHandler("gmcp.Char.player.resistBludgeoning", function() + if gmcp.Char.player.resistBludgeoning then + focus:echo(gmcp.Char.player.resistBludgeoning, "#c19c00", "l") + end + end) + local arcaneTitle = Geyser.Label:new({ + name = "arcaneTitle" + }, resist1HBox) + arcaneTitle:setColor(0, 0, 0, 0) + arcaneTitle:setFontSize(9) + arcaneTitle:echo("Arcane: ", "#aaaaaa", "r") + local resistArcane = Geyser.Label:new({ + name = "arcane" + }, resist1HBox) + resistArcane:setColor(0, 0, 0, 0) + resistArcane:setFontSize(9) + resistArcane:echo(gmcp.Char.player.resistArcane, "#61d6d6", "l") + if PRSstats.events.resistArcaneChange_id then + killAnonymousEventHandler(PRSstats.events.resistArcaneChange_id) + end + PRSstats.events.resistArcaneChange_id = registerAnonymousEventHandler("gmcp.Char.player.resistArcane", function() + if gmcp.Char.player.resistArcane then + resistArcane:echo(gmcp.Char.player.resistArcane, "#61d6d6", "l") + end + end) + -- Slash & Electric + local resist2HBox = Geyser.HBox:new({ + name = "resist2HBox", + width = "93%" + }, statsVBox) + local resistSlashingTitle = Geyser.Label:new({ + name = "resistSlashingTitle" + }, resist2HBox) + resistSlashingTitle:setColor(0, 0, 0, 0) + resistSlashingTitle:setFontSize(9) + resistSlashingTitle:echo("Slash: ", "#aaaaaa", "r") + local resistSlashing = Geyser.Label:new({ + name = "resistSlashing" + }, resist2HBox) + resistSlashing:setColor(0, 0, 0, 0) + resistSlashing:setFontSize(9) + resistSlashing:echo(gmcp.Char.player.resistSlashing, "#e74856", "l") + if PRSstats.events.resistSlashingChange_id then + killAnonymousEventHandler(PRSstats.events.resistSlashingChange_id) + end + PRSstats.events.resistSlashingChange_id = registerAnonymousEventHandler("gmcp.Char.player.resistSlashing", function() + if gmcp.Char.player.resistSlashing then + focus:echo(gmcp.Char.player.resistSlashing, "#e74856", "l") + end + end) + local resistElectricTitle = Geyser.Label:new({ + name = "resistElectricTitle" + }, resist2HBox) + resistElectricTitle:setColor(0, 0, 0, 0) + resistElectricTitle:setFontSize(9) + resistElectricTitle:echo("Electric: ", "#aaaaaa", "r") + local resistElectric = Geyser.Label:new({ + name = "Electric" + }, resist2HBox) + resistElectric:setColor(0, 0, 0, 0) + resistElectric:setFontSize(9) + resistElectric:echo(gmcp.Char.player.resistElectric, "#f9f1a5", "l") + if PRSstats.events.resistElectricChange_id then + killAnonymousEventHandler(PRSstats.events.resistElectricChange_id) + end + PRSstats.events.resistElectricChange_id = registerAnonymousEventHandler("gmcp.Char.player.resistElectric", function() + if gmcp.Char.player.resistElectric then + resistElectric:echo(gmcp.Char.player.resistElectric, "#f9f1a5", "l") + end + end) + -- Pierce & Fire + local resist3HBox = Geyser.HBox:new({ + name = "resist3HBox", + width = "93%" + }, statsVBox) + local resistPiercingTitle = Geyser.Label:new({ + name = "resistPiercingTitle" + }, resist3HBox) + resistPiercingTitle:setColor(0, 0, 0, 0) + resistPiercingTitle:setFontSize(9) + resistPiercingTitle:echo("Pierce: ", "#aaaaaa", "r") + local resistPiercing = Geyser.Label:new({ + name = "resistPiercing" + }, resist3HBox) + resistPiercing:setColor(0, 0, 0, 0) + resistPiercing:setFontSize(9) + resistPiercing:echo(gmcp.Char.player.resistPiercing, "#c50f1f", "l") + if PRSstats.events.resistPiercingChange_id then + killAnonymousEventHandler(PRSstats.events.resistPiercingChange_id) + end + PRSstats.events.resistPiercingChange_id = registerAnonymousEventHandler("gmcp.Char.player.resistPiercing", function() + if gmcp.Char.player.resistPiercing then + focus:echo(gmcp.Char.player.resistPiercing, "#c50f1f", "l") + end + end) + local resistFireTitle = Geyser.Label:new({ + name = "resistFireTitle" + }, resist3HBox) + resistFireTitle:setColor(0, 0, 0, 0) + resistFireTitle:setFontSize(9) + resistFireTitle:echo("Fire: ", "#aaaaaa", "r") + local resistFire = Geyser.Label:new({ + name = "Fire" + }, resist3HBox) + resistFire:setColor(0, 0, 0, 0) + resistFire:setFontSize(9) + resistFire:echo(gmcp.Char.player.resistFire, "#e74856", "l") + if PRSstats.events.resistFireChange_id then + killAnonymousEventHandler(PRSstats.events.resistFireChange_id) + end + PRSstats.events.resistFireChange_id = registerAnonymousEventHandler("gmcp.Char.player.resistFire", function() + if gmcp.Char.player.resistFire then + resistFire:echo(gmcp.Char.player.resistFire, "#e74856", "l") + end + end) + -- Poison & Ice + local resist4HBox = Geyser.HBox:new({ + name = "resist4HBox", + width = "93%" + }, statsVBox) + local resistPoisonTitle = Geyser.Label:new({ + name = "resistPoisonTitle" + }, resist4HBox) + resistPoisonTitle:setColor(0, 0, 0, 0) + resistPoisonTitle:setFontSize(9) + resistPoisonTitle:echo("Poison: ", "#aaaaaa", "r") + local resistPoison = Geyser.Label:new({ + name = "resistPoison" + }, resist4HBox) + resistPoison:setColor(0, 0, 0, 0) + resistPoison:setFontSize(9) + resistPoison:echo(gmcp.Char.player.resistPoison, "#13a10e", "l") + if PRSstats.events.resistPoisonChange_id then + killAnonymousEventHandler(PRSstats.events.resistPoisonChange_id) + end + PRSstats.events.resistPoisonChange_id = registerAnonymousEventHandler("gmcp.Char.player.resistPoison", function() + if gmcp.Char.player.resistPoison then + focus:echo(gmcp.Char.player.resistPoison, "#13a10e", "l") + end + end) + local resistIceTitle = Geyser.Label:new({ + name = "resistIceTitle" + }, resist4HBox) + resistIceTitle:setColor(0, 0, 0, 0) + resistIceTitle:setFontSize(9) + resistIceTitle:echo("Ice: ", "#aaaaaa", "r") + local resistIce = Geyser.Label:new({ + name = "Ice" + }, resist4HBox) + resistIce:setColor(0, 0, 0, 0) + resistIce:setFontSize(9) + resistIce:echo(gmcp.Char.player.resistIce, "#3b78ff", "l") + if PRSstats.events.resistIceChange_id then + killAnonymousEventHandler(PRSstats.events.resistIceChange_id) + end + PRSstats.events.resistIceChange_id = registerAnonymousEventHandler("gmcp.Char.player.resistIce", function() + if gmcp.Char.player.resistIce then + resistIce:echo(gmcp.Char.player.resistIce, "#3b78ff", "l") + end + end) + -- Pierce & Fire + local resist3HBox = Geyser.HBox:new({ + name = "resist3HBox", + width = "93%" + }, statsVBox) + local resistPiercingTitle = Geyser.Label:new({ + name = "resistPiercingTitle" + }, resist3HBox) + resistPiercingTitle:setColor(0, 0, 0, 0) + resistPiercingTitle:setFontSize(9) + resistPiercingTitle:echo("Pierce: ", "#aaaaaa", "r") + local resistPiercing = Geyser.Label:new({ + name = "resistPiercing" + }, resist3HBox) + resistPiercing:setColor(0, 0, 0, 0) + resistPiercing:setFontSize(9) + resistPiercing:echo(gmcp.Char.player.resistPiercing, "#c50f1f", "l") + if PRSstats.events.resistPiercingChange_id then + killAnonymousEventHandler(PRSstats.events.resistPiercingChange_id) + end + PRSstats.events.resistPiercingChange_id = registerAnonymousEventHandler("gmcp.Char.player.resistPiercing", function() + if gmcp.Char.player.resistPiercing then + focus:echo(gmcp.Char.player.resistPiercing, "#c50f1f", "l") + end + end) + local resistFireTitle = Geyser.Label:new({ + name = "resistFireTitle" + }, resist3HBox) + resistFireTitle:setColor(0, 0, 0, 0) + resistFireTitle:setFontSize(9) + resistFireTitle:echo("Fire: ", "#aaaaaa", "r") + local resistFire = Geyser.Label:new({ + name = "Fire" + }, resist3HBox) + resistFire:setColor(0, 0, 0, 0) + resistFire:setFontSize(9) + resistFire:echo(gmcp.Char.player.resistFire, "#e74856", "l") + if PRSstats.events.resistFireChange_id then + killAnonymousEventHandler(PRSstats.events.resistFireChange_id) + end + PRSstats.events.resistFireChange_id = registerAnonymousEventHandler("gmcp.Char.player.resistFire", function() + if gmcp.Char.player.resistFire then + resistFire:echo(gmcp.Char.player.resistFire, "#e74856", "l") + end + end) + -- Acid & Holy + local resist5HBox = Geyser.HBox:new({ + name = "resist5HBox", + width = "93%" + }, statsVBox) + local resistAcidTitle = Geyser.Label:new({ + name = "resistAcidTitle" + }, resist5HBox) + resistAcidTitle:setColor(0, 0, 0, 0) + resistAcidTitle:setFontSize(9) + resistAcidTitle:echo("Acid: ", "#aaaaaa", "r") + local resistAcid = Geyser.Label:new({ + name = "resistAcid" + }, resist5HBox) + resistAcid:setColor(0, 0, 0, 0) + resistAcid:setFontSize(9) + resistAcid:echo(gmcp.Char.player.resistAcid, "#16c60c", "l") + if PRSstats.events.resistAcidChange_id then + killAnonymousEventHandler(PRSstats.events.resistAcidChange_id) + end + PRSstats.events.resistAcidChange_id = registerAnonymousEventHandler("gmcp.Char.player.resistAcid", function() + if gmcp.Char.player.resistAcid then + focus:echo(gmcp.Char.player.resistAcid, "#16c60c", "l") + end + end) + local resistHolyTitle = Geyser.Label:new({ + name = "resistHolyTitle" + }, resist5HBox) + resistHolyTitle:setColor(0, 0, 0, 0) + resistHolyTitle:setFontSize(9) + resistHolyTitle:echo("Holy: ", "#aaaaaa", "r") + local resistHoly = Geyser.Label:new({ + name = "Holy" + }, resist5HBox) + resistHoly:setColor(0, 0, 0, 0) + resistHoly:setFontSize(9) + resistHoly:echo(gmcp.Char.player.resistHoly, "#f2f2f2", "l") + if PRSstats.events.resistHolyChange_id then + killAnonymousEventHandler(PRSstats.events.resistHolyChange_id) + end + PRSstats.events.resistHolyChange_id = registerAnonymousEventHandler("gmcp.Char.player.resistHoly", function() + if gmcp.Char.player.resistHoly then + resistHoly:echo(gmcp.Char.player.resistHoly, "#f2f2f2", "l") + end + end) +end + local function add_gauges() -- Hit Points Gauge HPbar = SUG:new({ name = "HP", + y = 80, height = 25, width = "95%", -- everything up to here is standard Geyser.Gauge updateTime = 0, @@ -14,32 +733,31 @@ local function add_gauges() textTemplate = "HP: |c / |m (|p%)", -- gauge will show "HP: 500/1000 (50%)" as the text if you had 500 current and 1000 max hp currentVariable = "gmcp.Char.player.hp", -- if gmcp.Char.Vitals.hp is nil or unreachable, it will use the defaultCurrent of 50 maxVariable = "gmcp.Char.player.maxHp" -- if gmcp.Char.Vitals.maxhp is nil or unreachable, it will use the defaultMax of 100 - }, PRSstats.UW) - HPbar.front:setStyleSheet( - [[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #98f041, stop: 0.1 #8cf029, stop: 0.49 #66cc00, stop: 0.5 #52a300, stop: 1 #66cc00); + }, GUI.tabwindow1.Vitalscenter) + HPbar.front:setStyleSheet([[background-color: #63e2b7; border-top: 1px black solid; border-left: 1px black solid; border-bottom: 1px black solid; - border-radius: 7; + border-radius: 10; + margin-right: 5px; padding: 3px; ]]) - HPbar.back:setStyleSheet( - [[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #78bd33, stop: 0.1 #6ebd20, stop: 0.49 #4c9900, stop: 0.5 #387000, stop: 1 #4c9900); - border-width: 1px; + HPbar.back:setStyleSheet([[background-color: #303030; + border-width: 0px; border-color: black; border-style: solid; - border-radius: 7; + border-radius: 10; + margin-right: 5px; padding: 3px; ]]) HPbar.text:setStyleSheet([[ - font-weight: bold; padding-left: 5px; ]]) -- Energy Points Gauge ENbar = SUG:new({ name = "EN", - y = 45, + y = 115, height = 25, width = "95%", updateTime = 0, @@ -47,32 +765,31 @@ local function add_gauges() textTemplate = "EN: |c / |m (|p%)", currentVariable = "gmcp.Char.player.energy", maxVariable = "gmcp.Char.player.maxEnergy" - }, PRSstats.UW) - ENbar.front:setStyleSheet( - [[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 0.1 #eeeeee, stop: 0.49 #cccccc, stop: 0.5 #aaaaaa, stop: 1 #cccccc); + }, GUI.tabwindow1.Vitalscenter) + ENbar.front:setStyleSheet([[background-color: #cccccc; border-top: 1px black solid; border-left: 1px black solid; border-bottom: 1px black solid; - border-radius: 7; + border-radius: 10; + margin-right: 5px; padding: 3px; ]]) - ENbar.back:setStyleSheet( - [[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #dddddd, stop: 0.1 #cccccc, stop: 0.49 #aaaaaa, stop: 0.5 #888888, stop: 1 #aaaaaa); - border-width: 1px; + ENbar.back:setStyleSheet([[background-color: #303030; + border-width: 0px; border-color: black; border-style: solid; - border-radius: 7; + border-radius: 10; + margin-right: 5px; padding: 3px; ]]) ENbar.text:setStyleSheet([[ - font-weight: bold; padding-left: 5px; ]]) -- Stamina Points Gauge STbar = SUG:new({ name = "ST", - y = 80, + y = 150, height = 25, width = "95%", updateTime = 0, @@ -80,30 +797,29 @@ local function add_gauges() textTemplate = "ST: |c / |m (|p%)", currentVariable = "gmcp.Char.player.stamina", maxVariable = "gmcp.Char.player.maxStamina" - }, PRSstats.UW) - STbar.front:setStyleSheet( - [[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffff50, stop: 0.1 #ffe200, stop: 0.49 #c1c100, stop: 0.5 #a4a40c, stop: 1 #c1c100); + }, GUI.tabwindow1.Vitalscenter) + STbar.front:setStyleSheet([[background-color: #f2c97d; border-top: 1px black solid; border-left: 1px black solid; border-bottom: 1px black solid; - border-radius: 7; + border-radius: 10; + margin-right: 5px; padding: 3px;]]) - STbar.back:setStyleSheet( - [[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #dddd20, stop: 0.1 #ddc200, stop: 0.49 #a1a100, stop: 0.5 #94840c, stop: 1 #a1a100); - border-width: 1px; + STbar.back:setStyleSheet([[background-color: #303030; + border-width: 0px; border-color: black; border-style: solid; - border-radius: 7; + border-radius: 10; + margin-right: 5px; padding: 3px;]]) STbar.text:setStyleSheet([[ - font-weight: bold; padding-left: 5px; ]]) -- Food Points Gauge - HPbar = SUG:new({ + FPbar = SUG:new({ name = "FP", - y = 115, + y = 185, height = 25, width = "95%", updateTime = 0, @@ -111,32 +827,30 @@ local function add_gauges() textTemplate = "Food: |c / |m (|p%)", currentVariable = "gmcp.Char.player.food", maxVariable = "gmcp.Char.player.maxFood" - }, PRSstats.UW) - HPbar.front:setStyleSheet( - [[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #98f041, stop: 0.1 #8cf029, stop: 0.49 #66cc00, stop: 0.5 #52a300, stop: 1 #66cc00); + }, GUI.tabwindow1.Vitalscenter) + FPbar.front:setStyleSheet([[background-color: #63e2b7; border-top: 1px black solid; border-left: 1px black solid; border-bottom: 1px black solid; - border-radius: 7; + border-radius: 10; + margin-right: 5px; padding: 3px; ]]) - HPbar.back:setStyleSheet( - [[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #78bd33, stop: 0.1 #6ebd20, stop: 0.49 #4c9900, stop: 0.5 #387000, stop: 1 #4c9900); - border-width: 1px; + FPbar.back:setStyleSheet([[background-color: #303030; + border-width: 0px; border-color: black; border-style: solid; - border-radius: 7; + border-radius: 10; + margin-right: 5px; padding: 3px; ]]) - HPbar.text:setStyleSheet([[ - font-weight: bold; + FPbar.text:setStyleSheet([[ padding-left: 5px; ]]) -- Rage Points Gauge RPbar = SUG:new({ name = "RP", - y = 150, height = 25, width = "95%", updateTime = 0, @@ -144,30 +858,29 @@ local function add_gauges() textTemplate = "Rage: |c", currentVariable = "gmcp.Char.player.rage", maxVariable = "gmcp.Char.player.maxRage" - }, PRSstats.UW) - RPbar.front:setStyleSheet( - [[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #f04141, stop: 0.1 #ef2929, stop: 0.49 #cc0000, stop: 0.5 #a40000, stop: 1 #cc0000); + }, GUI.tabwindow2.Combatcenter) + RPbar.front:setStyleSheet([[background-color: #e74856; border-top: 1px black solid; border-left: 1px black solid; border-bottom: 1px black solid; - border-radius: 7; + border-radius: 10; + margin-right: 5px; padding: 3px;]]) - RPbar.back:setStyleSheet( - [[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #bd3333, stop: 0.1 #bd2020, stop: 0.49 #990000, stop: 0.5 #700000, stop: 1 #990000); - border-width: 1px; + RPbar.back:setStyleSheet([[background-color: #303030; + border-width: 0px; border-color: black; border-style: solid; - border-radius: 7; + border-radius: 10; + margin-right: 5px; padding: 3px;]]) RPbar.text:setStyleSheet([[ - font-weight: bold; padding-left: 5px; ]]) -- Combo Points Gauge CPbar = SUG:new({ name = "CP", - y = 185, + y = 45, height = 25, width = "95%", updateTime = 0, @@ -175,27 +888,58 @@ local function add_gauges() textTemplate = "Combo: |c", currentVariable = "gmcp.Char.player.combo", maxVariable = "gmcp.Char.player.maxCombo" - }, PRSstats.UW) - CPbar.front:setStyleSheet( - [[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #f04141, stop: 0.1 #ef2929, stop: 0.49 #cc0000, stop: 0.5 #a40000, stop: 1 #cc0000); + }, GUI.tabwindow2.Combatcenter) + CPbar.front:setStyleSheet([[background-color: #e74856; border-top: 1px black solid; border-left: 1px black solid; border-bottom: 1px black solid; - border-radius: 7; + border-radius: 10; + margin-right: 5px; padding: 3px;]]) - CPbar.back:setStyleSheet( - [[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #bd3333, stop: 0.1 #bd2020, stop: 0.49 #990000, stop: 0.5 #700000, stop: 1 #990000); - border-width: 1px; + CPbar.back:setStyleSheet([[background-color: #303030; + border-width: 0px; border-color: black; border-style: solid; - border-radius: 7; + border-radius: 10; + margin-right: 5px; padding: 3px;]]) CPbar.text:setStyleSheet([[ - font-weight: bold; padding-left: 5px; ]]) -- Experience Points Gauge + XPbar = SUG:new({ + name = "XP", + y = 45, + height = 25, + width = "95%", + updateTime = 0, + updateEvent = "gmcp.Char.player", + textTemplate = "Hero" + }, GUI.tabwindow1.Vitalscenter) + XPbar.front:setStyleSheet([[background-color: #70c0e8; + border-top: 1px black solid; + border-left: 1px black solid; + border-bottom: 1px black solid; + border-radius: 10; + margin-right: 5px; + padding: 3px; + textTemplate = "Hero", + currentVariable = "PRSstats.xp.current", + maxVariable = "PRSstats.xp.current" + ]]) + XPbar.back:setStyleSheet([[background-color: #70c0e8; + border-width: 0px; + border-color: black; + border-style: solid; + border-radius: 10; + margin-right: 5px; + padding: 3px; + ]]) + XPbar.text:setStyleSheet([[ + padding-left: 5px; + ]]) + if gmcp.Char.player.xpForNextLevel then PRSstats.xp = PRSstats.xp or {} @@ -204,7 +948,7 @@ local function add_gauges() XPbar = SUG:new({ name = "XP", - y = 220, + y = 45, height = 25, width = "95%", updateTime = 0, @@ -212,25 +956,24 @@ local function add_gauges() textTemplate = "XP: |c / |m (|p%)", currentVariable = "PRSstats.xp.current", maxVariable = "PRSstats.xp.tnl" - }, PRSstats.UW) - XPbar.front:setStyleSheet( - [[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #3399ff, stop: 0.1 #0080ff, stop: 0.49 #0000ff, stop: 0.5 #0000cc, stop: 1 #0000ff); + }, GUI.tabwindow1.Vitalscenter) + XPbar.front:setStyleSheet([[background-color: #70c0e8; border-top: 1px black solid; border-left: 1px black solid; border-bottom: 1px black solid; - border-radius: 7; + border-radius: 10; + margin-right: 5px; padding: 3px; ]]) - XPbar.back:setStyleSheet( - [[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #0066cc, stop: 0.1 #004c99, stop: 0.49 #000099, stop: 0.5 #000066, stop: 1 #000099); - border-width: 1px; + XPbar.back:setStyleSheet([[background-color: #303030; + border-width: 0px; border-color: black; border-style: solid; - border-radius: 7; + border-radius: 10; + margin-right: 5px; padding: 3px; ]]) XPbar.text:setStyleSheet([[ - font-weight: bold; padding-left: 5px; ]]) @@ -262,25 +1005,15 @@ local function add_gauges() end function PRSstats.stats() - PRSstats.UW = Geyser.UserWindow:new({ - name = "Stats", - titleText = "Vitals", - x = "75%", - y = "75%", - height = "25%", - width = "25%", - docked = true, - restoreLayout = true - }) - if gmcp and gmcp.Char and gmcp.Char.player then - PRSstats.UW:setTitle("Vitals - " .. gmcp.Char.player.name .. " (Level " .. gmcp.Char.player.level .. ")") + vitalsHeader() + statsTab() add_gauges() else local initialize_ev_handler = registerAnonymousEventHandler("gmcp.Char.player", function() if gmcp and gmcp.Char and gmcp.Char.player and gmcp.Char.player.name then - PRSstats.UW:setTitle("Vitals - " .. gmcp.Char.player.name .. " (Level " .. gmcp.Char.player.level .. - ")") + vitalsHeader() + statsTab() add_gauges() end end, true)