From bda4750871c709abcd18621494fe4ece23d0228f Mon Sep 17 00:00:00 2001 From: Cooldude2606 Date: Thu, 23 May 2019 22:13:07 +0100 Subject: [PATCH] Added progress bar --- expcore/Gui/buttons.lua | 1 - expcore/Gui/center.lua | 1 + expcore/Gui/left.lua | 2 + expcore/Gui/progress-bar.lua | 336 +++++++++++++++++++++++++++++++++++ expcore/Gui/test.lua | 48 +++++ expcore/gui.lua | 26 +++ 6 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 expcore/Gui/progress-bar.lua diff --git a/expcore/Gui/buttons.lua b/expcore/Gui/buttons.lua index 46a67ec8..9e3ae887 100644 --- a/expcore/Gui/buttons.lua +++ b/expcore/Gui/buttons.lua @@ -17,7 +17,6 @@ local mod_gui = require 'mod-gui' local Gui = require 'expcore.gui.core' local Button = { - config={}, _prototype=Gui._prototype_factory{ on_click = Gui._event_factory('on_click'), on_left_click = Gui._event_factory('on_left_click'), diff --git a/expcore/Gui/center.lua b/expcore/Gui/center.lua index 9e836409..b849075a 100644 --- a/expcore/Gui/center.lua +++ b/expcore/Gui/center.lua @@ -8,6 +8,7 @@ CenterFrames.toggle_frame(player,name,state) --- Toggles if the frame is currently open or not, will open if closed and close if open CenterFrames.new_frame(permision_name) --- Sets the frame to be the current active gui when opened and closes all other frames + CenterFrames._prototype:on_draw(player,frame) --- Use to draw your elements onto the new frame CenterFrames._prototype:set_auto_focus(state) --- Sets the frame to be the current active gui when opened and closes all other frames CenterFrames._prototype:draw_frame(player) --- Draws this frame to the player, if already open does nothing (will call on_draw to draw to the frame) CenterFrames._prototype:redraw_frame(player) --- Draws this frame to the player, if already open it will remove it and redraw it (will call on_draw to draw to the frame) diff --git a/expcore/Gui/left.lua b/expcore/Gui/left.lua index b3d431f3..45fb3bad 100644 --- a/expcore/Gui/left.lua +++ b/expcore/Gui/left.lua @@ -42,6 +42,8 @@ LeftFrames._prototype:redraw(player) --- Redraws the frame by calling on_draw, will always clear the frame LeftFrames._prototype:redraw_all(update_offline) --- Redraws the frame for all players, see redraw + LeftFrames._prototype:on_draw(player,frame) --- Use to draw your elements to the new frame + LeftFrames._prototype:on_update(player,frame) --- Use to edit your frame when there is no need to redraw it LeftFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add ]] local Gui = require 'expcore.gui.core' diff --git a/expcore/Gui/progress-bar.lua b/expcore/Gui/progress-bar.lua new file mode 100644 index 00000000..f5799fb4 --- /dev/null +++ b/expcore/Gui/progress-bar.lua @@ -0,0 +1,336 @@ +--- Gui element define for progess bars +--[[ +>>>> Functions + ProgressBar.set_maximum(element,amount,start_full) --- Sets the maximum value that represents the end value of the progress bar + ProgressBar.increment(element,amount) --- Increases the value of the progressbar, if a define is given all of its instances are incremented + ProgressBar.decrement(element,amount) --- Decreases the value of the progressbar, if a define is given all of its instances are decresed + + ProgressBar.new_progressbar(name) --- Creates a new progressbar element define + ProgressBar._prototype:set_maximum(amount,start_full) --- Sets the maximum value that represents the end value of the progress bar + ProgressBar._prototype:increment(amount,category) --- Increases the value of the progressbar + ProgressBar._prototype:decrement(amount,category) --- Decreases the value of the progressbar + ProgressBar._prototype:add_element(element) --- Adds an element into the list of instances that will are waiting to complete, does not work with store + ProgressBar._prototype:reset_element(element) --- Resets an element, or its store, to be back at the start, either 1 or 0 + + ProgressBar._prototype:on_complete() --- Triggers when a progress bar element compeltes (hits 0 or 1) + ProgressBar._prototype:on_complete() --- Triggers when a store value completes (hits 0 or 1) + ProgressBar._prototype:event_counter() --- Event handler factory that counts up by 1 every time the event triggeres + ProgressBar._prototype:event_countdown() --- Event handler factory that counts down by 1 every time the event triggeres +]] +local Gui = require 'expcore.gui.core' +local Global = require 'utils.global' +local Game = require 'utils.game' + +--- Event call for when the value is outside the range 0-1 +-- @tparam define table the define that this is acting on +-- @tparam element LuaGuiElement the element that triggered the event +local function event_call(define,element) + local player = Game.get_player_by_index(element.player_index) + + if define.events.on_complete then + define.events.on_complete(player,element,function() + define:add_element(element) + define:reset_element(element) + end) + end +end + +--- Store call for store update +-- @tparam define table the define that this is acting on +-- @tparam element LuaGuiElement the element that triggered the event +local function store_call(define,element,value) + element.value = value + if define.start_full and value <= 0 or not define.start_full and value >= 1 then + event_call(define,element) + end +end + +local ProgressBar = { + unregistered={}, + independent={}, + _prototype=Gui._prototype_factory{ + -- note both events will recive a reset function that can be used to reset the progress of the element/store + on_complete = Gui._event_factory('on_complete'), + on_store_complete = Gui._event_factory('on_store_complete'), + add_store = Gui._store_factory(store_call), + add_sync_store = Gui._sync_store_factory(store_call) + } +} +Global.register({ + ProgressBar.unregistered, + ProgressBar.independent +},function(tbl) + ProgressBar.unregistered = tbl[1] + ProgressBar.independent = tbl[2] +end) + +--- Gets the define data, cant use Gui.get_define as it would error +-- @tparam define ?table|string the define to get +-- @treturn table the define or nil +local function get_define(define) + if type(define) == 'table' then + if define.name and Gui.defines[define.name] then + return Gui.defines[define.name] + end + end + + return Gui.defines[define] +end + +--- Gets the element data, used when there is no define +-- @tparam element LuaGuiElement +-- @treturn table the element data simialr to define +local function get_element(element) + if not element.valid then return end + local name = element.player_index..':'..element.index + + if ProgressBar.unregistered[name] then + return ProgressBar.unregistered[name] + + else + ProgressBar.unregistered[name] = { + element=element, + maximum=1 + } + return ProgressBar.unregistered[name] + + end +end + +--- Sets the maximum value that represents the end value of the progress bar +-- @tparam element ?LuaGuiElement|string either a gui element or a registered define +-- @tparam amount number the amount to have set as the maximum +-- @tparam[opt=false] start_full boolean when true the bar will start filled, to be used with decrease +function ProgressBar.set_maximum(element,amount,start_full) + amount = amount > 0 and amount or error('amount must be greater than 0') + + local define = get_define(element) + if define then + define:set_maximum(amount,start_full) + + else + local element_data = get_element(element) + + if element_data then + element_data.maximum = amount + if start_full then + element.value = 1 + end + end + + end +end + +--- Increases the value of the progressbar, if a define is given all of its instances are incremented +-- @tapram element ?LuaGuiElement|string either a gui element or a registered define +-- @tparam[opt=1] amount number the amount to increase the progressbar by +function ProgressBar.increment(element,amount) + amount = type(amount) == 'number' and amount or 1 + + local define = get_define(element) + if define then + define:increment(amount) + + else + local element_data = get_element(element) + + if element_data then + local max = element_data.maximum > 0 and element_data.maximum or 1 + local real_amount = amount/max + element.value = element.value + real_amount + + if element.value >= 1 then + return true + end + end + + end +end + +--- Decreases the value of the progressbar, if a define is given all of its instances are decresed +-- @tapram element ?LuaGuiElement|string either a gui element or a registered define +-- @tparam[opt=1] amount number the amount to decrease the progressbar by +function ProgressBar.decrement(element,amount) + amount = type(amount) == 'number' and amount or 1 + + local define = get_define(element) + if define then + define:decrement(amount) + + else + local element_data = get_element(element) + + if element_data then + local max = element_data.maximum > 0 and element_data.maximum or 1 + local real_amount = amount/max + element.value = element.value - real_amount + + if element.value <= 0 then + return true + end + end + + end +end + +--- Creates a new progressbar element define +-- @tparam[opt] name string the optional debug name that can be added +-- @treturn table the new progressbar elemente define +function ProgressBar.new_progressbar(name) + local self = Gui._define_factory(ProgressBar._prototype) + self.draw_data.type = 'progressbar' + + if name then + self:debug_name(name) + end + + self.post_draw = function(element) + if self.store then + local category = self.categorize and self.categorize(element) or nil + local value = self:get_store(category) + if not value then + value = self.start_full and 1 or 0 + self:set_store(category,value) + end + element.value = value + + else + if self.start_full then + self.value = 1 + end + + if not ProgressBar.independent[self.name] then + ProgressBar.independent[self.name] = {} + end + + table.insert(ProgressBar.independent[self.name],element) + + end + + end + + return self +end + +--- Sets the maximum value that represents the end value of the progress bar +-- @tparam amount number the amount to have set as the maximum +-- @tparam[opt=false] start_full boolean when true the bar will start filled, to be used with decrease +function ProgressBar._prototype:set_maximum(amount,start_full) + amount = amount > 0 and amount or error('amount must be greater than 0') + self.maximum = amount + if start_full then + self.start_full = true + else + self.start_full = false + end + return self +end + +--- Main logic for changing the value of a progress bar, this only applies when its a registered define +-- @tparam self table the define that is being changed +-- @tparam amount number the amount which it is being changed by, may be negative +-- @tparam[opt] category string the category to use with store +local function change_value_prototype(self,amount,category) + + local function reset_store() + local value = self.start_full and 1 or 0 + local _category = category or value + self:set_store(_category,value) + end + + if self.store then + local value = self:get_store(category) or self.start_full and 1 or 0 + local new_value = value + amount + + if self.start_full and value <= 0 or not self.start_full and value >= 1 then + self:set_store(category) + if self.events.on_store_complete then + category = category or reset_store + self.events.on_store_complete(category,reset_store) + end + end + + category = category or new_value + self:set_store(category,new_value) + end + + if ProgressBar.independent[self.name] then + for key,element in pairs(ProgressBar.independent[self.name]) do + if not element or not element.valid then + ProgressBar.independent[self.name][key] = nil + else + element.value = element.value + amount + + if self.start_full and element.value <= 0 or not self.start_full and element.value >= 1 then + ProgressBar.independent[self.name][key] = nil + event_call(self,element) + end + end + end + end + +end + +--- Increases the value of the progressbar +-- @tparam[opt=1] amount number the amount to increase the progressbar by +-- @tparam[opt] category string the category that is used with a store +function ProgressBar._prototype:increment(amount,category) + amount = type(amount) == 'number' and amount or 1 + local max = self.maximum > 0 and self.maximum or 1 + local real_amount = amount/max + + change_value_prototype(self,real_amount,category) +end + +--- Decreases the value of the progressbar +-- @tparam[opt=1] amount number the amount to decrease the progressbar by +-- @tparam[opt] category string the category that is used with a store +function ProgressBar._prototype:decrement(amount,category) + amount = type(amount) == 'number' and amount or 1 + local max = self.maximum > 0 and self.maximum or 1 + local real_amount = amount/max + + change_value_prototype(self,-real_amount,category) +end + +--- Adds an element into the list of instances that will are waiting to complete, does not work with store +-- note use store if you want persistent data, this only stores the elements not the values which they have +-- @tparam element LuaGuiElement the element that you want to add into the waiting to complete list +function ProgressBar._prototype:add_element(element) + if self.store then return end + if not ProgressBar.independent[self.name] then + ProgressBar.independent[self.name] = {} + end + table.insert(ProgressBar.independent[self.name],element) +end + +--- Resets an element, or its store, to be back at the start, either 1 or 0 +-- @tparam element LuaGuiElement the element that you want to reset the progress of +function ProgressBar._prototype:reset_element(element) + if not element or not element.valid then return end + local value = self.start_full and 1 or 0 + if self.store then + local category = self.categorize and self.categorize(element) or value + self:set_store(category,value) + else + element.value = value + end +end + +--- Event handler factory that counts up by 1 every time the event triggeres +-- @treturn function the event handler +function ProgressBar._prototype:event_counter() + return function() + self:increment() + end +end + +--- Event handler factory that counts down by 1 every time the event triggeres +-- @treturn function the event handler +function ProgressBar._prototype:event_countdown() + return function() + self:decrement() + end +end + +return ProgressBar \ No newline at end of file diff --git a/expcore/Gui/test.lua b/expcore/Gui/test.lua index 31b289f2..d227d10c 100644 --- a/expcore/Gui/test.lua +++ b/expcore/Gui/test.lua @@ -5,6 +5,7 @@ local Gui = require 'expcore.gui' local format_chat_colour,table_keys = ext_require('expcore.common','format_chat_colour','table_keys') local Colors = require 'resources.color_presets' local Event = require 'utils.event' +local Store = require 'expcore.store' local tests = {} @@ -572,4 +573,51 @@ tests["Elem Buttons"] = { ['Default']=elem_default, ['Function']=elem_function, ['Store']=elem_store +} + +--[[ + Progress bar tests + > Simple -- Progress bar that fills every 2 seconds + > Store -- Progress bar that fills every 5 seconds with synced value + > Reverce -- Progress bar that decreases every 2 seconds +]] + +local progressbar_one = +Gui.new_progressbar('test-prog-one') +:set_maximum(120) +:on_complete(function(player,element,reset_element) + reset_element() +end) + +local progressbar_two = +Gui.new_progressbar('test-prog-one') +:set_maximum(300) +:add_store(Gui.force_store) +:on_complete(function(player,element,reset_element) + reset_element() +end) +:on_store_complete(function(category,reset_store) + reset_store() +end) + +local progressbar_three = +Gui.new_progressbar('test-prog-one') +:set_maximum(120,true) +:on_complete(function(player,element,reset_element) + reset_element() +end) + +Event.add(defines.events.on_tick,function() + progressbar_one:increment() + progressbar_three:decrement() + local categories = Store.get_children(progressbar_two.store) + for category,_ in pairs(categories) do + progressbar_two:increment(1,category) + end +end) + +tests["Progress Bars"] = { + ['Simple']=progressbar_one, + ['Store']=progressbar_two, + ['Reverce']=progressbar_three } \ No newline at end of file diff --git a/expcore/gui.lua b/expcore/gui.lua index 6568e744..09363b24 100644 --- a/expcore/gui.lua +++ b/expcore/gui.lua @@ -143,6 +143,29 @@ Gui.classes.elem_button = ElemButton ElemButton._prototype:set_default(value) --- Sets the default value for the elem button, this may be a function or a string ]] +local ProgressBar = require 'expcore.gui.progress-bar' +Gui.new_progressbar = ProgressBar.new_progressbar +Gui.set_progressbar_maximum = ProgressBar.set_maximum +Gui.increment_progressbar = ProgressBar.increment +Gui.decrement_progressbar = ProgressBar.decrement +--[[ + ProgressBar.set_maximum(element,amount,start_full) --- Sets the maximum value that represents the end value of the progress bar + ProgressBar.increment(element,amount) --- Increases the value of the progressbar, if a define is given all of its instances are incremented + ProgressBar.decrement(element,amount) --- Decreases the value of the progressbar, if a define is given all of its instances are decresed + + ProgressBar.new_progressbar(name) --- Creates a new progressbar element define + ProgressBar._prototype:set_maximum(amount,start_full) --- Sets the maximum value that represents the end value of the progress bar + ProgressBar._prototype:increment(amount,category) --- Increases the value of the progressbar + ProgressBar._prototype:decrement(amount,category) --- Decreases the value of the progressbar + ProgressBar._prototype:add_element(element) --- Adds an element into the list of instances that will are waiting to complete, does not work with store + ProgressBar._prototype:reset_element(element) --- Resets an element, or its store, to be back at the start, either 1 or 0 + + ProgressBar._prototype:on_complete() --- Triggers when a progress bar element compeltes (hits 0 or 1) + ProgressBar._prototype:on_complete() --- Triggers when a store value completes (hits 0 or 1) + ProgressBar._prototype:event_counter() --- Event handler factory that counts up by 1 every time the event triggeres + ProgressBar._prototype:event_countdown() --- Event handler factory that counts down by 1 every time the event triggeres +]] + local Toolbar = require 'expcore.gui.toolbar' Gui.new_toolbar_button = Toolbar.new_button Gui.add_button_to_toolbar = Toolbar.add_button @@ -176,6 +199,8 @@ Gui.classes.left_frames = LeftFrames LeftFrames._prototype:redraw(player) --- Redraws the frame by calling on_draw, will always clear the frame LeftFrames._prototype:redraw_all(update_offline) --- Redraws the frame for all players, see redraw + LeftFrames._prototype:on_draw(player,frame) --- Use to draw your elements to the new frame + LeftFrames._prototype:on_update(player,frame) --- Use to edit your frame when there is no need to redraw it LeftFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add ]] @@ -194,6 +219,7 @@ Gui.classes.center_frames = CenterFrames CenterFrames.toggle_frame(player,name,state) --- Toggles if the frame is currently open or not, will open if closed and close if open CenterFrames.new_frame(permision_name) --- Sets the frame to be the current active gui when opened and closes all other frames + CenterFrames._prototype:on_draw(player,frame) --- Use to draw your elements onto the new frame CenterFrames._prototype:set_auto_focus(state) --- Sets the frame to be the current active gui when opened and closes all other frames CenterFrames._prototype:draw_frame(player) --- Draws this frame to the player, if already open does nothing (will call on_draw to draw to the frame) CenterFrames._prototype:redraw_frame(player) --- Draws this frame to the player, if already open it will remove it and redraw it (will call on_draw to draw to the frame)