Change object syntax to user get_ and set_ prefix instead of get_map/set_map mappers (issue #15)

This commit is contained in:
Emmanuel Lepage Vallee 2014-03-05 00:12:48 -05:00
parent b8ba760a1f
commit 5255cca803
12 changed files with 187 additions and 91 deletions

View File

@ -308,3 +308,101 @@ allow masks such as desaturation, tinting, invert or some matrix to be applied
on the pixmap before it is being drawn. This function take the path/surface as
only parameter and return the transformed surface.
## Extending Radical
Radical is not designed to be used "as is". Every menus are different. While
common ones can be created without extending Radical capabilities, more advanced
one most likely will. Good news, this is what Radical have been designed for.
The previous generations proved to me that any lack or native extensibility
will cause the code to bloat when it come to adding a feature. Radical horizontal
design allow to add more modules and properties without having to touch the "core"
files.
### Object model
The Radical object model is similar to the Awesome one. Each objects have a set
of signals developers can listen to to have changes notification. The big
difference is that Radical object model automatically generate the properties
themselves. If one desire to add a new one, it is possible to listen to `item::added`
to apply it on the item or apply it directly on the menu itself depending if the
property is for the menu or for an item. Here is an example how it work:
```lua
local menu = radical.context{}
-- Create the setter
menu.set_foo = function(m,value)
print("Setting value to:",value)
m._foo_real = value
end
-- Create the getter
menu.get_foo = function(m)
print("Getter called, returning",m._foo_real)
end
-- The property is now created, this will call the setter:
menu.foo = "my foo value"
-- This will call the getter:
print(menu.foo)
-- The signals will be automatically generated
data:connect_signal("foo::changed",function(m,value)
print("foo changed:",value)
end)
-- New signals don't need to be registered and can be called right away
data:connect_signal("my_new_signal::action_name",function(m,value1,value2,value3)
print("Callback",m,value1,value2,value3)
end)
-- Manually emiting a signal
menu:emit_signal("my_new_signal::action_name",value1,value2,value3)
```
### State model
Radical support multiple states per item at once. The "current state" is the one
with the smallest ID. A state ID is an integer from -inf to inf. More important
states, like `urgent` versus `checked` can be implemented by using an
appropriate ordering. The default set of states is subject to changes, so it
is wiser to use a completely different range if someone want to replace the
currents one. Each states can be assigned a background and foreground color
using the `radical.theme.register_color(id, radical_name, beautiful_name, true )`
method. Toggling a state can be done using the `item.state[]` meta table:
```lua
local my_state_name = 9999 -- <== The ID
local menu = radical.context{}
local item = menu:add_item{text="text"}
-- Activate a state
item.state[my_state_name] = true
-- Desactivate a state
item.state[my_state_name] = nil
```
Radical will take care of choosing the current state and redraw the item with
the right background and foreground colors.
### Layout
TODO
### Style
TODO
### Item layout
TODO
### Item style
TODO

16
bar.lua
View File

@ -35,7 +35,7 @@ end
local function setup_drawable(data)
local internal = data._internal
local get_map,set_map,private_data = internal.get_map,internal.set_map,internal.private_data
local private_data = internal.private_data
--Init
internal.margin = wibox.layout.margin()
@ -46,13 +46,13 @@ local function setup_drawable(data)
internal.margin:set_widget(internal.layout)
--Getters
get_map.x = function() return 0 end
get_map.y = function() return 0 end
get_map.width = function() return internal.margin.fix(internal.margin,9999,99) end
get_map.height = function() return beautiful.default_height end
get_map.visible = function() return true end
get_map.direction = function() return "left" end
get_map.margins = function() return {left=0,right=0,top=0,bottom=0} end
data.get_x = function() return 0 end
data.get_y = function() return 0 end
data.get_width = function() return internal.margin.fix(internal.margin,9999,99) end
data.get_height = function() return beautiful.default_height end
data.get_visible = function() return true end
data.get_direction = function() return "left" end
data.get_margins = function() return {left=0,right=0,top=0,bottom=0} end
-- This widget do not use wibox, so setup correct widget interface
data.fit = internal.margin.fit

View File

@ -166,6 +166,7 @@ local function add_item(data,args)
item.selected = true
end
item.index = data.rowcount
data:emit_signal("item::added",item)
return item
end
@ -179,7 +180,7 @@ local function add_widget(data,widget,args)
return args.width or w,args.height or h
end
local item,set_map,get_map,private_data = object({
local item,private_data = object({
private_data = {
widget = widget,
selected = false,
@ -188,15 +189,13 @@ local function add_widget(data,widget,args)
visible = true,
selected = true,
},
get_map = {
y = function() return (args.y and args.y >= 0) and args.y or data.height - (data.margins.top or data.border_width) - data.item_height end, --Hack around missing :fit call for last item
},
autogen_getmap = true,
autogen_setmap = true,
autogen_signals = true,
})
item._private_data = private_data
item._internal = {get_map=get_map,set_map=set_map}
item._internal = {}
item.get_y = function() return (args.y and args.y >= 0) and args.y or data.height - (data.margins.top or data.border_width) - data.item_height end --Hack around missing :fit call for last item
data._internal.widgets[#data._internal.widgets+1] = item
data._internal.items[#data._internal.items+1] = {item}
@ -228,7 +227,7 @@ local function new(args)
if not internal.widgets then internal.widgets = {} end
-- All the magic in the universe
local data,set_map,get_map,private_data = object({
local data,private_data = object({
private_data = {
-- Default settings
bg = args.bg or beautiful.menu_bg_normal or beautiful.bg_normal or "#000000",
@ -280,16 +279,6 @@ local function new(args)
opacity = args.opacity or beautiful.menu_opacity or 1,
icon_transformation = args.icon_transformation or nil,
},
get_map = {
is_menu = function() return true end,
margin = function() return {left=0,bottom=0,right=0,left=0} end,
items = function() return internal.items end,
rowcount = function() return #internal.items end,
columncount = function() return (#internal.items > 0) and #(internal.items[1]) or 0 end,
},
set_map = {
auto_resize = function(val) private_data[""] = val end,
},
force_private = {
parent = true,
visible = true,
@ -302,10 +291,20 @@ local function new(args)
autogen_setmap = true,
autogen_signals = true,
})
internal.get_map,internal.set_map,internal.private_data = get_map,set_map,private_data
internal.private_data = private_data
data.add_item,data.add_widget,data.add_embeded_menu,data._internal,data.add_key_binding = add_item,add_widget,add_embeded_menu,internal,add_key_binding
theme.setup_colors(data,args)
set_map.parent_geometry = function(value)
-- Getters
data.get_is_menu = function(_) return true end
data.get_margin = function(_) return {left=0,bottom=0,right=0,left=0} end
data.get_items = function(_) return internal.items end
data.get_rowcount = function(_) return #internal.items end
data.get_columncount = function(_) return (#internal.items > 0) and #(internal.items[1]) or 0 end
-- Setters
data.set_auto_resize = function(_,val) private_data[""] = val end
data.set_parent_geometry = function(_,value)
private_data.parent_geometry = value
if data._internal.get_direction then
data.direction = data._internal.get_direction(data)
@ -315,7 +314,7 @@ local function new(args)
end
end
set_map.visible = function(value)
data.set_visible = function(_,value)
private_data.visible = value
if value then
local fit_w,fit_h = data._internal.layout:fit(9999,9999)
@ -342,8 +341,8 @@ local function new(args)
capi.keygrabber.stop()
end
end
set_map.layout = function(value)
data.set_layout = function(_,value)
if value then
value:setup_key_hooks(data)
end
@ -356,7 +355,7 @@ local function new(args)
-- end
-- end
get_map.current_index = function()
data.get_current_index = function(_)
if data._current_item then
for k,v in ipairs(internal.items) do --rows
for k2,v2 in ipairs(v) do --columns
@ -368,14 +367,14 @@ local function new(args)
end
end
get_map.previous_item = function()
data.get_previous_item = function(_)
local candidate,idx = internal.items[(data.current_index or 0)-1],(data.current_index or 0)-1
while candidate and (candidate[1]._hidden or candidate[1]._filter_out) and idx > 0 do
candidate,idx = internal.items[idx - 1],idx-1
end
return (candidate or internal.items[data.rowcount])[1]
end
get_map.next_item = function()
data.get_next_item = function(_)
local candidate,idx = internal.items[(data.current_index or 0)+1],(data.current_index or 0)+1
while candidate and (candidate[1]._hidden or candidate[1]._filter_out) and idx <= data.rowcount do
candidate,idx = internal.items[idx + 1],idx+1

View File

@ -100,7 +100,7 @@ end
local function setup_drawable(data)
local internal = data._internal
local get_map,set_map,private_data = internal.get_map,internal.set_map,internal.private_data
local private_data = internal.private_data
--Init
internal.w = wibox({})
@ -117,14 +117,14 @@ local function setup_drawable(data)
internal.w.opacity = data.opacity
--Getters
get_map.wibox = function() return internal.w end
get_map.x = function() return internal.w.x end
get_map.y = function() return internal.w.y end
get_map.width = function() return internal.w.width end
get_map.height = function() return internal.w.height end
get_map.visible = function() return private_data.visible end
get_map.direction = function() return private_data.direction end
get_map.margins = function()
data.get_wibox = function() return internal.w end
data.get_x = function() return internal.w.x end
data.get_y = function() return internal.w.y end
data.get_width = function() return internal.w.width end
data.get_height = function() return internal.w.height end
data.get_visible = function() return private_data.visible end
data.get_direction = function() return private_data.direction end
data.get_margins = function()
local ret = {left=data.border_width,right=data.border_width,top=data.style.margins.TOP,bottom=data.style.margins.BOTTOM}
if data.arrow_type ~= base.arrow_type.NONE then
ret[data.direction] = ret[data.direction]+13
@ -133,7 +133,7 @@ local function setup_drawable(data)
end
--Setters
set_map.direction = function(value)
data.set_direction = function(_,value)
if private_data.direction ~= value and (value == "top" or value == "bottom" or value == "left" or value == "right") then
private_data.direction = value
local fit_w,fit_h = internal.layout:fit()
@ -141,9 +141,9 @@ local function setup_drawable(data)
data.width = fit_w
end
end
set_map.x = function(value) internal.w.x = value end
set_map.y = function(value) internal.w.y = value end
set_map.width = function(value)
data.set_x = function(_,value) internal.w.x = value end
data.set_y = function(_,value) internal.w.y = value end
data.set_width = function(_,value)
local need_update = internal.w.width == (value + 2*data.border_width)
local margins = data.margins
internal.w.width = value + data.margins.left + data.margins.right
@ -151,7 +151,7 @@ local function setup_drawable(data)
data.style(data)
end
end
set_map.height = function(value)
data.set_height = function(_,value)
local margins = data.margins
local need_update = (internal.w.height ~= (value + margins.top + margins.bottom))
local new_height = (value + margins.top + margins.bottom) or 1

View File

@ -19,16 +19,16 @@ local capi,module = { mouse = mouse , screen = screen , keygrabber = keygrabber
local function setup_drawable(data)
local internal = data._internal
local get_map,set_map,private_data = internal.get_map,internal.set_map,internal.private_data
local private_data = internal.private_data
-- An embeded menu can only be visible if the parent is
get_map.visible = function() return data._embeded_parent and data._embeded_parent.visible or false end --Let the parent handle that
set_map.visible = function(v) if data._embeded_parent then data._embeded_parent.visible = v end end
data.get_visible = function() return data._embeded_parent and data._embeded_parent.visible or false end --Let the parent handle that
data.set_visible = function(_,v) if data._embeded_parent then data._embeded_parent.visible = v end end
-- Enumate geometry --BUG this is fake, but better than nothing
get_map.width = function() return data._embeded_parent and data._embeded_parent.width end
get_map.y = function() return data._embeded_parent and data._embeded_parent.y end
get_map.x = function() return data._embeded_parent and data._embeded_parent.x end
data.get_width = function() return data._embeded_parent and data._embeded_parent.width end
data.get_y = function() return data._embeded_parent and data._embeded_parent.y end
data.get_x = function() return data._embeded_parent and data._embeded_parent.x end
if not data.layout then
data.layout = layout.vertical
end

View File

@ -75,7 +75,7 @@ end
local function new_item(data,args)
local args = args or {}
local item,set_map,get_map,private_data = object({
local item,private_data = object({
private_data = {
text = args.text or "" ,
height = args.height or data.item_height or beautiful.menu_height or 30 ,
@ -103,16 +103,14 @@ local function new_item(data,args)
selected = true,
index = true,
},
get_map = {
y = function() return (args.y and args.y >= 0) and args.y or data.height - (data.margins.top or data.border_width) - data.item_height end, --Hack around missing :fit call for last item
},
autogen_getmap = true,
autogen_setmap = true,
autogen_signals = true,
})
item._private_data = private_data
item._internal = {get_map=get_map,set_map=set_map}
item._internal = {}
theme.setup_item_colors(data,item,args)
item.get_y = function() return (args.y and args.y >= 0) and args.y or data.height - (data.margins.top or data.border_width) - data.item_height end --Hack around missing :fit call for last item
item.get_bg = function()
return data.bg
end
@ -138,7 +136,7 @@ local function new_item(data,args)
data._internal.items[#data._internal.items][1] = item
-- Setters
set_map.selected = function(value)
item.set_selected = function(_,value)
private_data.selected = value
if value == false then
data.item_style(item,{})

View File

@ -12,7 +12,7 @@ local module = {}
-- Add [F1], [F2] ... to items
function module:setup_fkey(item,data)
item._internal.set_map.f_key = function(value)
item.set_f_key = function(_,value)
item._internal.has_changed = true
item._internal.f_key = value
data:remove_key_hook("F"..value)
@ -21,7 +21,7 @@ function module:setup_fkey(item,data)
data.visible = false
end)
end
item._internal.get_map.f_key = function() return item._internal.f_key end
item.get_f_key = function() return item._internal.f_key end
end
-- Like an overlay, but under
@ -55,7 +55,7 @@ function module:setup_icon(item,data)
icon:set_image(item.icon)
end
item._internal.set_map.icon = function (value)
item.set_icon = function (_,value)
icon:set_image(value)
end
return icon
@ -64,7 +64,7 @@ end
-- Show the checkbox
function module:setup_checked(item,data)
if item.checkable then
item._internal.get_map.checked = function()
item.get_checked = function()
if type(item._private_data.checked) == "function" then
return item._private_data.checked()
else
@ -73,7 +73,7 @@ function module:setup_checked(item,data)
end
local ck = wibox.widget.imagebox()
ck:set_image(item.checked and checkbox.checked() or checkbox.unchecked())
item._internal.set_map.checked = function (value)
item.set_checked = function (_,value)
item._private_data.checked = value
ck:set_image(item.checked and checkbox.checked() or checkbox.unchecked())
item._internal.has_changed = true
@ -84,7 +84,7 @@ end
-- Setup hover
function module:setup_hover(item,data)
item._internal.set_map.hover = function(value)
item.set_hover = function(_,value)
local item_style = item.item_style or data.item_style
item.state[5] = value and true or nil
item_style(item,{})
@ -197,7 +197,7 @@ local function create_item(item,data,args)
wibox.widget.textbox.draw(self,w, cr, width, height)
end
tb:set_text(item.text)
item._internal.set_map.text = function (value)
item.set_text = function (_,value)
if data.disable_markup then
tb:set_text(value)
else
@ -245,7 +245,7 @@ local function create_item(item,data,args)
item.widget:set_tooltip(item.tooltip)
-- Overlay
item._internal.set_map.overlay = function(value)
item.set_overlay = function(_,value)
item._private_data.overlay = value
item.widget:emit_signal("widget::updated")
end

View File

@ -74,7 +74,7 @@ local function create_item(item,data,args)
end
end
if item.checkable then
item._internal.get_map.checked = function()
item.get_checked = function()
if type(item._private_data.checked) == "function" then
return item._private_data.checked()
else
@ -84,7 +84,7 @@ local function create_item(item,data,args)
local ck = wibox.widget.imagebox()
ck:set_image(item.checked and checkbox.checked() or checkbox.unchecked())
lr:add(ck)
item._internal.set_map.checked = function (value)
item.set_checked = function (_,value)
item._private_data.checked = value
ck:set_image(item.checked and checkbox.checked() or checkbox.unchecked())
end

View File

@ -98,7 +98,7 @@ function module:setup_item(data,item,args)
local icon_w = item._internal.icon_w
-- Setup text
item._internal.set_map.text = function (value)
item.set_text = function (_,value)
if data.disable_markup then
text_w:set_text(value)
else
@ -114,10 +114,10 @@ function module:setup_item(data,item,args)
end
end
end
item._internal.set_map.icon = function (value)
item.set_icon = function (_,value)
icon_w:set_image(value)
end
item._internal.set_map.text(item._private_data.text)
item:set_text(item._private_data.text)
-- Setup tooltip
bg:set_tooltip(item.tooltip)

View File

@ -92,7 +92,7 @@ function module:setup_text(item,data,text_w)
end
text_w.fit = function(self,width,height) return width,height end
item._internal.set_map.text = function (value)
item.set_text = function (_,value)
if data.disable_markup then
text_w:set_text(value)
else
@ -114,7 +114,7 @@ function module:setup_text(item,data,text_w)
-- end
end
end
item._internal.set_map.text(item._private_data.text)
item:set_text(item._private_data.text)
return text_w
end

View File

@ -6,14 +6,14 @@ local pairs = pairs
local function setup_object(args)
local data,args,private_data,signals = {},args or {},private_data or {},{}
local get_map,set_map,private_data = args.get_map or {},args.set_map or {},args.private_data or {}
local private_data = args.private_data or {}
function data:connect_signal(name,func)
signals[name] = signals[name] or {}
table.insert(signals[name],func)
end
function data:remove_signal(name,func)
function data:disconnect_signal(name,func)
for k,v in pairs(signals[name] or {}) do
if v == func then
signals[name][k] = nil
@ -33,8 +33,8 @@ local function setup_object(args)
end
local function return_data(tab, key)
if get_map[key] ~= nil then
return get_map[key]()
if rawget(tab,"get_"..key) then
return rawget(tab,"get_"..key)(tab)
elseif args.autogen_getmap == true and private_data[key] ~= nil then
return private_data[key]
elseif args.other_get_callback then
@ -51,15 +51,16 @@ local function setup_object(args)
end
local function catch_changes(tab, key,value)
if set_map[key] == false then
local setter = rawget(tab,"set_"..key)
if setter == false then
--print("This is not a setter",debug.traceback()) --In some case, it may be called "normally", having this print is only good for debug
elseif (data[key] ~= value or (args.always_handle ~= nil and args.always_handle[key] == true)) and set_map[key] ~= nil then
set_map[key](value)
elseif (data[key] ~= value or (args.always_handle ~= nil and args.always_handle[key] == true)) and setter then
setter(tab,value)
auto_signal(key)
elseif (args.force_private or {})[key] == true or (args.autogen_setmap and (private_data[key] ~= nil)) then
private_data[key] = value
auto_signal(key)
elseif set_map[key] == nil then
elseif setter == nil then
rawset(data,key,value)
end
if args.auto_signal_changed == true then
@ -68,6 +69,6 @@ local function setup_object(args)
end
setmetatable(data, { __index = return_data, __newindex = catch_changes, __len = function() return #data + #private_data end, })
return data,set_map,get_map,private_data
return data,private_data
end
return setmetatable({}, { __call = function(_, ...) return setup_object(...) end })

View File

@ -276,7 +276,7 @@ end
local function setup_drawable(data)
local internal = data._internal
local get_map,set_map,private_data = internal.get_map,internal.set_map,internal.private_data
local private_data = internal.private_data
--Init
-- internal.w = wibox({})
@ -288,14 +288,14 @@ local function setup_drawable(data)
internal.margin:set_widget(internal.layout)
--Getters
get_map.wibox = function() return nil end -- Will this break?
get_map.x = function() return 0 end
get_map.y = function() return 0 end
get_map.width = function() return 500 end
get_map.height = function() return 40 end
get_map.visible = function() return private_data.visible end
get_map.direction = function() return private_data.direction end
get_map.margins = function()
data.get_wibox = function() return nil end -- Will this break?
data.get_x = function() return 0 end
data.get_y = function() return 0 end
data.get_width = function() return 500 end
data.get_height = function() return 40 end
data.get_visible = function() return private_data.visible end
data.get_direction = function() return private_data.direction end
data.get_margins = function()
local ret = {left=data.border_width,right=data.border_width,top=data.style.margins.TOP,bottom=data.style.margins.BOTTOM}
if data.arrow_type ~= base.arrow_type.NONE then
ret[data.direction] = ret[data.direction]+13