mirror of
https://github.com/Insality/druid.git
synced 2025-06-27 10:27:47 +02:00
Add class component and druid_instance
This commit is contained in:
parent
8c011dcc27
commit
be8869951a
24
README.md
24
README.md
@ -1,4 +1,4 @@
|
||||

|
||||
[](https://AGulev.github.io/druid/)
|
||||
_travis/release bages_
|
||||
|
||||
**Druid** - powerful defold component UI library. Use standart components or make your own game-specific to make amazing GUI in your games.
|
||||
@ -102,7 +102,7 @@ Basic custom component template looks like this:
|
||||
local const = require("druid.const")
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("amazing_component", { const.ON_INPUT })
|
||||
local M = component.create("amazing_component", { const.ON_INPUT })
|
||||
|
||||
function M.init(self, ...)
|
||||
-- Component constructor
|
||||
@ -139,7 +139,7 @@ On each component recomended describe component schema in next way:
|
||||
local helper = require("druid.helper")
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("new_component")
|
||||
local M = component.create("new_component")
|
||||
|
||||
local SCHEME = {
|
||||
ROOT = "/root",
|
||||
@ -172,8 +172,25 @@ end
|
||||
You can check our example here
|
||||
_TODO_
|
||||
|
||||
## Reserver componeney keywords
|
||||
- initialize
|
||||
- init
|
||||
- update
|
||||
- on_input
|
||||
- on_message
|
||||
- on_swipe
|
||||
- setup_component
|
||||
- get_style
|
||||
- set_style
|
||||
- set_template
|
||||
- set_nodes
|
||||
- get_context
|
||||
- set_context
|
||||
- get_druid
|
||||
|
||||
## API
|
||||
_Link to ldoc_
|
||||
[API](https://AGulev.github.io/druid/)
|
||||
|
||||
## Internal
|
||||
Generate with `ldoc .` with `config.ld` file. [Instructions](https://github.com/stevedonovan/LDoc)
|
||||
@ -183,6 +200,7 @@ _TODO_
|
||||
|
||||
|
||||
## License
|
||||
Using [middleclass by kikito](https://github.com/kikito/middleclass)
|
||||
MIT License
|
||||
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
local const = require("druid.const")
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("back_handler", { const.ON_INPUT })
|
||||
local M = component.create("back_handler", { const.ON_INPUT })
|
||||
|
||||
|
||||
--- Component init function
|
||||
|
@ -5,7 +5,7 @@ local const = require("druid.const")
|
||||
local helper = require("druid.helper")
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("blocker", { const.ON_SWIPE })
|
||||
local M = component.create("blocker", { const.ON_SWIPE })
|
||||
|
||||
|
||||
function M.init(self, node)
|
||||
|
@ -9,7 +9,8 @@ local const = require("druid.const")
|
||||
local helper = require("druid.helper")
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("button", { const.ON_INPUT })
|
||||
local M = component.create("button", { const.ON_INPUT })
|
||||
|
||||
|
||||
--- Component init function
|
||||
-- @function button:init
|
||||
@ -21,6 +22,7 @@ local M = component.new("button", { const.ON_INPUT })
|
||||
-- @tparam[opt] string event Button react event, const.ACTION_TOUCH by default
|
||||
function M.init(self, node, callback, params, anim_node, event)
|
||||
assert(callback, "Button should have callback. To block input on zone use blocker component")
|
||||
|
||||
self.style = self:get_style()
|
||||
self.node = helper.get_node(node)
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
local helper = require("druid.helper")
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("checkbox")
|
||||
local M = component.create("checkbox")
|
||||
|
||||
|
||||
function M.set_state(self, state, is_silence)
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("checkbox_group")
|
||||
local M = component.create("checkbox_group")
|
||||
|
||||
|
||||
local function on_checkbox_click(self, index)
|
||||
|
@ -5,7 +5,7 @@
|
||||
local helper = require("druid.helper")
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("grid")
|
||||
local M = component.create("grid")
|
||||
|
||||
|
||||
function M.init(self, parent, element, in_row)
|
||||
|
@ -6,7 +6,7 @@ local const = require("druid.const")
|
||||
local settings = require("druid.system.settings")
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("locale", { const.ON_CHANGE_LANGUAGE })
|
||||
local M = component.create("locale", { const.ON_CHANGE_LANGUAGE })
|
||||
|
||||
|
||||
function M.init(self, node, lang_id, no_adjust)
|
||||
|
@ -5,7 +5,7 @@ local const = require("druid.const")
|
||||
local helper = require("druid.helper")
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("progress", { const.ON_UPDATE })
|
||||
local M = component.create("progress", { const.ON_UPDATE })
|
||||
|
||||
|
||||
--- Component init function
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("radio_group")
|
||||
local M = component.create("radio_group")
|
||||
|
||||
|
||||
local function on_checkbox_click(self, index)
|
||||
|
@ -5,7 +5,7 @@ local helper = require("druid.helper")
|
||||
local const = require("druid.const")
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("scroll", { const.ON_UPDATE, const.ON_SWIPE })
|
||||
local M = component.create("scroll", { const.ON_UPDATE, const.ON_SWIPE })
|
||||
|
||||
|
||||
-- Global on all scrolls
|
||||
|
@ -5,7 +5,7 @@ local helper = require("druid.helper")
|
||||
local const = require("druid.const")
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("slider", { const.ON_SWIPE })
|
||||
local M = component.create("slider", { const.ON_SWIPE })
|
||||
|
||||
|
||||
local function on_change_value(self)
|
||||
|
@ -6,7 +6,7 @@ local const = require("druid.const")
|
||||
local helper = require("druid.helper")
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("text")
|
||||
local M = component.create("text")
|
||||
|
||||
|
||||
function M.init(self, node, value, no_adjust)
|
||||
|
@ -6,7 +6,7 @@ local formats = require("druid.helper.formats")
|
||||
local helper = require("druid.helper")
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("timer", { const.ON_UPDATE })
|
||||
local M = component.create("timer", { const.ON_UPDATE })
|
||||
|
||||
|
||||
function M.init(self, node, seconds_from, seconds_to, callback)
|
||||
|
@ -29,7 +29,14 @@ M.components = {
|
||||
checkbox_group = require("druid.base.checkbox_group"),
|
||||
radio_group = require("druid.base.radio_group"),
|
||||
|
||||
-- TODO:
|
||||
-- input - text input
|
||||
-- infinity_scroll -- to handle big data scroll
|
||||
|
||||
progress_rich = require("druid.rich.progress_rich"),
|
||||
|
||||
-- TODO: Examples:
|
||||
-- Slider menu like clash royale
|
||||
}
|
||||
|
||||
|
||||
@ -52,8 +59,9 @@ function M.register(name, module)
|
||||
-- Possibly: druid.new(druid.BUTTON, etc?)
|
||||
-- Current way is very implicit
|
||||
druid_instance["new_" .. name] = function(self, ...)
|
||||
return druid_instance.new(self, module, ...)
|
||||
return druid_instance.create(self, module, ...)
|
||||
end
|
||||
|
||||
log("Register component", name)
|
||||
end
|
||||
|
||||
@ -65,20 +73,8 @@ function M.new(context, style)
|
||||
register_basic_components()
|
||||
register_basic_components = false
|
||||
end
|
||||
local druid = setmetatable({}, { __index = druid_instance })
|
||||
|
||||
-- Druid context here (who created druid)
|
||||
-- Usually gui_script, but can be component from self:get_druid()
|
||||
druid._context = context
|
||||
druid._style = style or settings.default_style
|
||||
|
||||
-- TODO: Find the better way to handle components
|
||||
-- All component list
|
||||
druid.all_components = {}
|
||||
-- Map: interest: {components}
|
||||
druid.components = {}
|
||||
|
||||
return druid
|
||||
return druid_instance(context, style)
|
||||
end
|
||||
|
||||
|
||||
@ -90,6 +86,7 @@ end
|
||||
function M.set_text_function(callback)
|
||||
settings.get_text = callback or const.EMPTY_FUNCTION
|
||||
-- TODO: Update all localized text
|
||||
-- TOOD: Need to store all current druid instances?
|
||||
end
|
||||
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
local component = require("druid.system.component")
|
||||
|
||||
local M = component.new("progress_rich")
|
||||
local M = component.create("progress_rich")
|
||||
|
||||
|
||||
function M.init(self, name, red, green, key)
|
||||
|
@ -2,52 +2,12 @@
|
||||
--@class component
|
||||
|
||||
local const = require("druid.const")
|
||||
local class = require("druid.system.middleclass")
|
||||
|
||||
local M = {}
|
||||
local instance = {}
|
||||
local Component = class("druid.component")
|
||||
|
||||
|
||||
function instance.get_style(self)
|
||||
if not self._meta.style then
|
||||
return const.EMPTY_TABLE
|
||||
end
|
||||
|
||||
return self._meta.style[self._component.name] or const.EMPTY_TABLE
|
||||
end
|
||||
|
||||
|
||||
function instance.set_style(self, druid_style)
|
||||
self._meta.style = druid_style
|
||||
end
|
||||
|
||||
|
||||
function instance.set_template(self, template)
|
||||
self._meta.template = template
|
||||
end
|
||||
|
||||
|
||||
function instance.set_nodes(self, nodes)
|
||||
self._meta.nodes = nodes
|
||||
end
|
||||
|
||||
|
||||
function instance.get_context(self, context)
|
||||
return self._meta.context
|
||||
end
|
||||
|
||||
|
||||
function instance.set_context(self, context)
|
||||
self._meta.context = context
|
||||
end
|
||||
|
||||
|
||||
function instance.get_druid(self)
|
||||
local context = { _context = self }
|
||||
return setmetatable(context, { __index = self:get_context().druid })
|
||||
end
|
||||
|
||||
|
||||
function instance.setup_component(self, context, style)
|
||||
function Component.setup_component(self, context, style)
|
||||
self._meta = {
|
||||
template = nil,
|
||||
context = nil,
|
||||
@ -62,17 +22,99 @@ function instance.setup_component(self, context, style)
|
||||
end
|
||||
|
||||
|
||||
function M.new(name, interest)
|
||||
local mt = {
|
||||
_component = {
|
||||
name = name,
|
||||
interest = interest
|
||||
}
|
||||
}
|
||||
local component = setmetatable(mt, { __index = instance })
|
||||
function Component.get_style(self)
|
||||
if not self._meta.style then
|
||||
return const.EMPTY_TABLE
|
||||
end
|
||||
|
||||
return component
|
||||
return self._meta.style[self._component.name] or const.EMPTY_TABLE
|
||||
end
|
||||
|
||||
|
||||
return M
|
||||
function Component.set_style(self, druid_style)
|
||||
self._meta.style = druid_style
|
||||
end
|
||||
|
||||
|
||||
function Component.get_template(self)
|
||||
return self._meta.template
|
||||
end
|
||||
|
||||
|
||||
function Component.set_template(self, template)
|
||||
self._meta.template = template
|
||||
end
|
||||
|
||||
|
||||
function Component.get_nodes(self)
|
||||
return self._meta.nodes
|
||||
end
|
||||
|
||||
|
||||
function Component.set_nodes(self, nodes)
|
||||
self._meta.nodes = nodes
|
||||
end
|
||||
|
||||
|
||||
function Component.get_context(self, context)
|
||||
return self._meta.context
|
||||
end
|
||||
|
||||
|
||||
function Component.set_context(self, context)
|
||||
self._meta.context = context
|
||||
end
|
||||
|
||||
|
||||
function Component.get_interests(self)
|
||||
return self._component.interest
|
||||
end
|
||||
|
||||
|
||||
-- TODO: Определиться с get_node и node
|
||||
-- get_node - берет ноду по ноде или строке
|
||||
-- node - может брать ноду у компонента по схеме (если есть
|
||||
-- template или таблица нод после gui.clone_tree)
|
||||
function Component.get_node(self, node_or_name)
|
||||
local template_name = self:get_template() or const.EMPTY_STRING
|
||||
local nodes = self:get_nodes()
|
||||
|
||||
if nodes then
|
||||
return nodes[template_name .. node_or_name]
|
||||
else
|
||||
if type(node_or_name) == const.STRING then
|
||||
return gui.get_node(template_name .. node_or_name)
|
||||
else
|
||||
return node_or_name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function Component.get_druid(self)
|
||||
local context = { _context = self }
|
||||
return setmetatable(context, { __index = self:get_context().druid })
|
||||
end
|
||||
|
||||
|
||||
function Component.initialize(self, name, interest)
|
||||
self._component = {
|
||||
name = name,
|
||||
interest = interest
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
function Component.static.create(name, interest)
|
||||
-- Yea, inheritance here
|
||||
local new_class = class(name, Component)
|
||||
|
||||
new_class.initialize = function(self)
|
||||
Component.initialize(self, name, interest)
|
||||
end
|
||||
|
||||
return new_class
|
||||
end
|
||||
|
||||
|
||||
return Component
|
||||
|
@ -1,8 +1,9 @@
|
||||
local const = require("druid.const")
|
||||
local druid_input = require("druid.helper.druid_input")
|
||||
local settings = require("druid.system.settings")
|
||||
local class = require("druid.system.middleclass")
|
||||
|
||||
local M = {}
|
||||
local Druid = class("druid.druid_instance")
|
||||
|
||||
|
||||
local function input_init(self)
|
||||
@ -19,16 +20,15 @@ end
|
||||
|
||||
|
||||
-- Create the component
|
||||
local function create(self, module)
|
||||
local function create(self, instance_class)
|
||||
---@class component
|
||||
local instance = setmetatable({}, { __index = module })
|
||||
local instance = instance_class()
|
||||
|
||||
-- Component context, self from component creation
|
||||
instance:setup_component(self._context, self._style)
|
||||
|
||||
table.insert(self.all_components, instance)
|
||||
|
||||
local register_to = module._component.interest
|
||||
local register_to = instance:get_interests()
|
||||
if register_to then
|
||||
for i = 1, #register_to do
|
||||
local interest = register_to[i]
|
||||
@ -47,51 +47,6 @@ local function create(self, module)
|
||||
end
|
||||
|
||||
|
||||
function M.new(self, module, ...)
|
||||
local instance = create(self, module)
|
||||
|
||||
if instance.init then
|
||||
instance:init(...)
|
||||
end
|
||||
|
||||
return instance
|
||||
end
|
||||
|
||||
|
||||
function M.remove(self, instance)
|
||||
for i = #self.all_components, 1, -1 do
|
||||
if self.all_components[i] == instance then
|
||||
table.remove(self, i)
|
||||
end
|
||||
end
|
||||
|
||||
local interests = instance._component.interest
|
||||
if interests then
|
||||
for i = 1, #interests do
|
||||
local interest = interests[i]
|
||||
local array = self.components[interest]
|
||||
for j = #array, 1, -1 do
|
||||
if array[j] == instance then
|
||||
table.remove(array, j)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Druid instance update function
|
||||
-- @function druid:update(dt)
|
||||
function M.update(self, dt)
|
||||
local array = self.components[const.ON_UPDATE]
|
||||
if array then
|
||||
for i = 1, #array do
|
||||
array[i]:update(dt)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function notify_input_on_swipe(self)
|
||||
if self.components[const.ON_INPUT] then
|
||||
local len = #self.components[const.ON_INPUT]
|
||||
@ -118,17 +73,76 @@ local function match_event(action_id, events)
|
||||
end
|
||||
|
||||
|
||||
--- Druid constructor
|
||||
function Druid.initialize(self, context, style)
|
||||
self._context = context
|
||||
self._style = style or settings.default_style
|
||||
self.all_components = {}
|
||||
self.components = {}
|
||||
end
|
||||
|
||||
|
||||
--- Create new component inside druid instance
|
||||
function Druid.create(self, instance_class, ...)
|
||||
local instance = create(self, instance_class)
|
||||
|
||||
if instance.init then
|
||||
instance:init(...)
|
||||
end
|
||||
|
||||
return instance
|
||||
end
|
||||
|
||||
|
||||
--- Remove component from druid instance
|
||||
-- It will call on_remove on component, if exist
|
||||
function Druid.remove(self, component)
|
||||
for i = #self.all_components, 1, -1 do
|
||||
if self.all_components[i] == component then
|
||||
if component.on_remove then
|
||||
component:on_remove()
|
||||
end
|
||||
table.remove(self, i)
|
||||
end
|
||||
end
|
||||
|
||||
local interests = component:get_interests()
|
||||
if interests then
|
||||
for i = 1, #interests do
|
||||
local interest = interests[i]
|
||||
local array = self.components[interest]
|
||||
for j = #array, 1, -1 do
|
||||
if array[j] == component then
|
||||
table.remove(array, j)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Druid instance update function
|
||||
-- @function druid:update(dt)
|
||||
function Druid.update(self, dt)
|
||||
local array = self.components[const.ON_UPDATE]
|
||||
if array then
|
||||
for i = 1, #array do
|
||||
array[i]:update(dt)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Druid instance on_input function
|
||||
-- @function druid:on_input(action_id, action)
|
||||
function M.on_input(self, action_id, action)
|
||||
function Druid.on_input(self, action_id, action)
|
||||
-- TODO: расписать отличия ON_SWIPE и ON_INPUT
|
||||
-- Почему-то некоторые используют ON_SWIPE, а логичнее ON_INPUT? (blocker, slider)
|
||||
local array = self.components[const.ON_SWIPE]
|
||||
if array then
|
||||
local v, result
|
||||
local len = #array
|
||||
for i = len, 1, -1 do
|
||||
v = array[i]
|
||||
local result
|
||||
for i = #array, 1, -1 do
|
||||
local v = array[i]
|
||||
result = result or v:on_input(action_id, action)
|
||||
end
|
||||
if result then
|
||||
@ -139,42 +153,38 @@ function M.on_input(self, action_id, action)
|
||||
|
||||
array = self.components[const.ON_INPUT]
|
||||
if array then
|
||||
local v
|
||||
local len = #array
|
||||
for i = len, 1, -1 do
|
||||
v = array[i]
|
||||
for i = #array, 1, -1 do
|
||||
local v = array[i]
|
||||
if match_event(action_id, v.event) and v:on_input(action_id, action) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
--- Druid instance on_message function
|
||||
-- @function druid:on_message(message_id, message, sender)
|
||||
function M.on_message(self, message_id, message, sender)
|
||||
function Druid.on_message(self, message_id, message, sender)
|
||||
local specific_ui_message = const.SPECIFIC_UI_MESSAGES[message_id]
|
||||
if specific_ui_message then
|
||||
local array = self.components[message_id]
|
||||
if array then
|
||||
local item
|
||||
for i = 1, #array do
|
||||
item = array[i]
|
||||
local item = array[i]
|
||||
item[specific_ui_message](item, message, sender)
|
||||
end
|
||||
end
|
||||
else
|
||||
local array = self.components[const.ON_MESSAGE]
|
||||
if array then
|
||||
for i = 1, #array do
|
||||
array[i]:on_message(message_id, message, sender)
|
||||
end
|
||||
local array = self.components[const.ON_MESSAGE] or const.EMPTY_TABLE
|
||||
for i = 1, #array do
|
||||
array[i]:on_message(message_id, message, sender)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return M
|
||||
return Druid
|
||||
|
183
druid/system/middleclass.lua
Normal file
183
druid/system/middleclass.lua
Normal file
@ -0,0 +1,183 @@
|
||||
local middleclass = {
|
||||
_VERSION = 'middleclass v4.1.1',
|
||||
_DESCRIPTION = 'Object Orientation for Lua',
|
||||
_URL = 'https://github.com/kikito/middleclass',
|
||||
_LICENSE = [[
|
||||
MIT LICENSE
|
||||
|
||||
Copyright (c) 2011 Enrique García Cota
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
]]
|
||||
}
|
||||
|
||||
local function _createIndexWrapper(aClass, f)
|
||||
if f == nil then
|
||||
return aClass.__instanceDict
|
||||
else
|
||||
return function(self, name)
|
||||
local value = aClass.__instanceDict[name]
|
||||
|
||||
if value ~= nil then
|
||||
return value
|
||||
elseif type(f) == "function" then
|
||||
return (f(self, name))
|
||||
else
|
||||
return f[name]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function _propagateInstanceMethod(aClass, name, f)
|
||||
f = name == "__index" and _createIndexWrapper(aClass, f) or f
|
||||
aClass.__instanceDict[name] = f
|
||||
|
||||
for subclass in pairs(aClass.subclasses) do
|
||||
if rawget(subclass.__declaredMethods, name) == nil then
|
||||
_propagateInstanceMethod(subclass, name, f)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function _declareInstanceMethod(aClass, name, f)
|
||||
aClass.__declaredMethods[name] = f
|
||||
|
||||
if f == nil and aClass.super then
|
||||
f = aClass.super.__instanceDict[name]
|
||||
end
|
||||
|
||||
_propagateInstanceMethod(aClass, name, f)
|
||||
end
|
||||
|
||||
local function _tostring(self) return "class " .. self.name end
|
||||
local function _call(self, ...) return self:new(...) end
|
||||
|
||||
local function _createClass(name, super)
|
||||
local dict = {}
|
||||
dict.__index = dict
|
||||
|
||||
local aClass = { name = name, super = super, static = {},
|
||||
__instanceDict = dict, __declaredMethods = {},
|
||||
subclasses = setmetatable({}, {__mode='k'}) }
|
||||
|
||||
if super then
|
||||
setmetatable(aClass.static, {
|
||||
__index = function(_,k)
|
||||
local result = rawget(dict,k)
|
||||
if result == nil then
|
||||
return super.static[k]
|
||||
end
|
||||
return result
|
||||
end
|
||||
})
|
||||
else
|
||||
setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) end })
|
||||
end
|
||||
|
||||
setmetatable(aClass, { __index = aClass.static, __tostring = _tostring,
|
||||
__call = _call, __newindex = _declareInstanceMethod })
|
||||
|
||||
return aClass
|
||||
end
|
||||
|
||||
local function _includeMixin(aClass, mixin)
|
||||
assert(type(mixin) == 'table', "mixin must be a table")
|
||||
|
||||
for name,method in pairs(mixin) do
|
||||
if name ~= "included" and name ~= "static" then aClass[name] = method end
|
||||
end
|
||||
|
||||
for name,method in pairs(mixin.static or {}) do
|
||||
aClass.static[name] = method
|
||||
end
|
||||
|
||||
if type(mixin.included)=="function" then mixin:included(aClass) end
|
||||
return aClass
|
||||
end
|
||||
|
||||
local DefaultMixin = {
|
||||
__tostring = function(self) return "instance of " .. tostring(self.class) end,
|
||||
|
||||
initialize = function(self, ...) end,
|
||||
|
||||
isInstanceOf = function(self, aClass)
|
||||
return type(aClass) == 'table'
|
||||
and type(self) == 'table'
|
||||
and (self.class == aClass
|
||||
or type(self.class) == 'table'
|
||||
and type(self.class.isSubclassOf) == 'function'
|
||||
and self.class:isSubclassOf(aClass))
|
||||
end,
|
||||
|
||||
static = {
|
||||
allocate = function(self)
|
||||
assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
|
||||
return setmetatable({ class = self }, self.__instanceDict)
|
||||
end,
|
||||
|
||||
new = function(self, ...)
|
||||
assert(type(self) == 'table', "Make sure that you are using 'Class:new' instead of 'Class.new'")
|
||||
local instance = self:allocate()
|
||||
instance:initialize(...)
|
||||
return instance
|
||||
end,
|
||||
|
||||
subclass = function(self, name)
|
||||
assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'")
|
||||
assert(type(name) == "string", "You must provide a name(string) for your class")
|
||||
|
||||
local subclass = _createClass(name, self)
|
||||
|
||||
for methodName, f in pairs(self.__instanceDict) do
|
||||
_propagateInstanceMethod(subclass, methodName, f)
|
||||
end
|
||||
subclass.initialize = function(instance, ...) return self.initialize(instance, ...) end
|
||||
|
||||
self.subclasses[subclass] = true
|
||||
self:subclassed(subclass)
|
||||
|
||||
return subclass
|
||||
end,
|
||||
|
||||
subclassed = function(self, other) end,
|
||||
|
||||
isSubclassOf = function(self, other)
|
||||
return type(other) == 'table' and
|
||||
type(self.super) == 'table' and
|
||||
( self.super == other or self.super:isSubclassOf(other) )
|
||||
end,
|
||||
|
||||
include = function(self, ...)
|
||||
assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'")
|
||||
for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end
|
||||
return self
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
function middleclass.class(name, super)
|
||||
assert(type(name) == 'string', "A name (string) is needed for the new class")
|
||||
return super and super:subclass(name) or _includeMixin(_createClass(name), DefaultMixin)
|
||||
end
|
||||
|
||||
setmetatable(middleclass, { __call = function(_, ...) return middleclass.class(...) end })
|
||||
|
||||
return middleclass
|
@ -9,13 +9,11 @@ M.auto_focus_gain = true
|
||||
|
||||
|
||||
function M.get_text(name)
|
||||
-- override to get text for localized text
|
||||
return "[Druid]: locales not inited"
|
||||
end
|
||||
|
||||
|
||||
function M.play_sound(name)
|
||||
-- override to play sound with name
|
||||
end
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user