Rewrite the view layer
Radical is a model-view framework. There is a common API to set data, then view modules to display it. Those modules have been rewritten on top of new APIs. Not all features are yet re-integrated, most are. Future commits will address the various regressions and missing features. This time, the code should be maintainable. The whole separation of concerns analysis has been re-done. Allowing code de-duplication and generalization. The API remain the same, only `set_menu` has changed a little to allow merging the 2 sub-menu code paths.
This commit is contained in:
parent
1711d28dcd
commit
f239ee9a24
167
bar.lua
167
bar.lua
|
@ -3,54 +3,17 @@ local base = require( "radical.base" )
|
||||||
local color = require( "gears.color" )
|
local color = require( "gears.color" )
|
||||||
local wibox = require( "wibox" )
|
local wibox = require( "wibox" )
|
||||||
local beautiful = require( "beautiful" )
|
local beautiful = require( "beautiful" )
|
||||||
local cairo = require( "lgi" ).cairo
|
|
||||||
local awful = require( "awful" )
|
|
||||||
local util = require( "awful.util" )
|
|
||||||
local fkey = require( "radical.widgets.fkey" )
|
|
||||||
local button = require( "awful.button" )
|
|
||||||
local checkbox = require( "radical.widgets.checkbox" )
|
|
||||||
local item_style = require( "radical.item.style.arrow_single" )
|
local item_style = require( "radical.item.style.arrow_single" )
|
||||||
-- local vertical = require( "radical.layout.vertical" )
|
|
||||||
local item_layout= require( "radical.item.layout.horizontal" )
|
local item_layout= require( "radical.item.layout.horizontal" )
|
||||||
local margins2 = require("radical.margins" )
|
local common = require( "radical.common" )
|
||||||
|
|
||||||
local capi,module = { mouse = mouse , screen = screen, keygrabber = keygrabber },{}
|
local module = {}
|
||||||
|
|
||||||
local function get_direction(data)
|
|
||||||
return "left" -- Nothing to do
|
|
||||||
end
|
|
||||||
|
|
||||||
local function set_position(self)
|
|
||||||
return --Nothing to do
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Draw the menu background
|
|
||||||
local function bg_draw(self, context, cr, width, height)--w, cr, width, height)
|
|
||||||
cr:save()
|
|
||||||
cr:set_source(color(self._data.bg))
|
|
||||||
cr:rectangle(0,0,width,height)
|
|
||||||
cr:fill()
|
|
||||||
cr:restore()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function proxy_draw(_,...)
|
|
||||||
local l = _._internal and _._internal.layout or _
|
|
||||||
return wibox.layout.fixed.draw(l,...)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function proxy_fit(_,...)
|
|
||||||
local l = _._internal and _._internal.layout or _
|
|
||||||
return wibox.layout.fixed.fit(l,...)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function setup_drawable(data)
|
local function setup_drawable(data)
|
||||||
local internal = data._internal
|
local internal = data._internal
|
||||||
local private_data = internal.private_data
|
|
||||||
|
|
||||||
internal.layout = internal.layout_func or wibox.layout.fixed.horizontal()
|
internal.layout = internal.layout_func or wibox.layout.fixed.horizontal()
|
||||||
|
internal.margin = wibox.layout.margin(internal.layout)
|
||||||
--internal.layout.draw = bg_draw --TODO Dead code?
|
|
||||||
|
|
||||||
internal.layout._data = data
|
internal.layout._data = data
|
||||||
|
|
||||||
if internal.layout.set_spacing and data.spacing then
|
if internal.layout.set_spacing and data.spacing then
|
||||||
|
@ -58,134 +21,27 @@ local function setup_drawable(data)
|
||||||
end
|
end
|
||||||
|
|
||||||
--Getters
|
--Getters
|
||||||
data.get_x = function() return 0 end
|
|
||||||
data.get_y = function() return 0 end
|
|
||||||
data.get_width = function() return internal.layout:get_preferred_size() end
|
|
||||||
data.get_height = function() return beautiful.default_height end
|
|
||||||
data.get_visible = function() return true end
|
data.get_visible = function() return true end
|
||||||
data.get_direction = function() return "left" end
|
data.get_margins = common.get_margins
|
||||||
|
|
||||||
-- Setup the margins
|
|
||||||
local m = wibox.layout.margin()
|
|
||||||
m:set_widget(internal.layout)
|
|
||||||
internal.margin = m
|
|
||||||
local mrgns = margins2(m,data.default_margins or {})
|
|
||||||
data._internal.mrgns = mrgns
|
|
||||||
data.get_margins = function()
|
|
||||||
return data._internal.mrgns or {}
|
|
||||||
end
|
|
||||||
|
|
||||||
if data.style then
|
if data.style then
|
||||||
data.style(data)
|
data.style(data)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- This widget do not use wibox, so setup correct widget interface
|
common.setup_item_move_events(data)
|
||||||
data.fit = internal.layout
|
|
||||||
data.draw = internal.layout
|
|
||||||
|
|
||||||
-- Swap / Move / Remove
|
|
||||||
data:connect_signal("item::swapped",function(_,item1,item2,index1,index2)
|
|
||||||
internal.layout.widgets[index1],internal.layout.widgets[index2] = internal.layout.widgets[index2],internal.layout.widgets[index1]
|
|
||||||
internal.layout:emit_signal("widget::updated")
|
|
||||||
end)
|
|
||||||
data:connect_signal("item::moved",function(_,item,new_idx,old_idx)
|
|
||||||
table.insert(internal.layout.widgets,new_idx,table.remove(internal.layout.widgets,old_idx))
|
|
||||||
internal.layout:emit_signal("widget::updated")
|
|
||||||
end)
|
|
||||||
data:connect_signal("item::removed",function(_,item,old_idx)
|
|
||||||
table.remove(internal.layout.widgets,old_idx)
|
|
||||||
if internal.layout._emit_updated then
|
|
||||||
item.widget:disconnect_signal("widget::updated", internal.layout._emit_updated)
|
|
||||||
end
|
|
||||||
internal.layout:emit_signal("widget::updated")
|
|
||||||
end)
|
|
||||||
data:connect_signal("item::appended",function(_,item)
|
|
||||||
internal.layout:add(item.widget)
|
|
||||||
internal.layout:emit_signal("widget::updated")
|
|
||||||
end)
|
|
||||||
data:connect_signal("widget::added",function(_,item,widget)
|
|
||||||
internal.layout:add(widget)
|
|
||||||
internal.layout:emit_signal("widget::updated")
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function setup_buttons(data,item,args)
|
|
||||||
local buttons = {}
|
|
||||||
for i=1,10 do
|
|
||||||
if args["button"..i] then
|
|
||||||
buttons[i] = args["button"..i]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Setup sub_menu
|
|
||||||
if (item.sub_menu_m or item.sub_menu_f) and data.sub_menu_on >= base.event.BUTTON1 and data.sub_menu_on <= base.event.BUTTON3 then
|
|
||||||
item.widget:set_menu(item.sub_menu_m or item.sub_menu_f,data.sub_menu_on)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Scrool up
|
|
||||||
if not buttons[4] then
|
|
||||||
buttons[4] = function()
|
|
||||||
data:scroll_up()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Scroll down
|
|
||||||
if not buttons[5] then
|
|
||||||
buttons[5] = function()
|
|
||||||
data:scroll_down()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
item:connect_signal("button::release",function(_m,_i,button_id,mods,geo)
|
|
||||||
if #mods == 0 and buttons[button_id] then
|
|
||||||
buttons[button_id](_m,_i,mods,geo)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function setup_item(data,item,args)
|
|
||||||
-- Add widgets
|
|
||||||
data._internal.layout:add(data.item_layout(item,data,args))
|
|
||||||
if data.select_on == base.event.HOVER then
|
|
||||||
item.widget:connect_signal("mouse::enter", function() item.selected = true end)
|
|
||||||
item.widget:connect_signal("mouse::leave", function() item.selected = false end)
|
|
||||||
else
|
|
||||||
item.widget:connect_signal("mouse::enter", function() item.hover = true end)
|
|
||||||
item.widget:connect_signal("mouse::leave", function() item.hover = false end)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Setup buttons
|
|
||||||
setup_buttons(data,item,args)
|
|
||||||
|
|
||||||
-- Tooltip
|
|
||||||
item.widget:set_tooltip(item.tooltip)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function new(args)
|
local function new(args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
args.internal = args.internal or {}
|
args.internal = args.internal or {}
|
||||||
args.internal.get_direction = args.internal.get_direction or get_direction
|
|
||||||
args.internal.set_position = args.internal.set_position or set_position
|
|
||||||
args.internal.setup_drawable = args.internal.setup_drawable or setup_drawable
|
args.internal.setup_drawable = args.internal.setup_drawable or setup_drawable
|
||||||
args.internal.setup_item = args.internal.setup_item or setup_item
|
args.internal.setup_item = args.internal.setup_item or common.setup_item
|
||||||
args.item_style = args.item_style or item_style
|
args.item_style = args.item_style or item_style
|
||||||
args.item_layout = args.item_layout or item_layout
|
args.item_layout = args.item_layout or item_layout
|
||||||
args.sub_menu_on = args.sub_menu_on or base.event.BUTTON1
|
args.sub_menu_on = args.sub_menu_on or base.event.BUTTON1
|
||||||
local ret = base(args)
|
|
||||||
ret:connect_signal("clear::menu",function(_,vis)
|
|
||||||
ret._internal.layout:reset()
|
|
||||||
end)
|
|
||||||
ret:connect_signal("_hidden::changed",function(_,item)
|
|
||||||
item.widget:emit_signal("widget::updated")
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- rawset(ret,"fit", proxy_fit)
|
local ret = base(args)
|
||||||
-- rawset(ret,"draw", proxy_draw)
|
|
||||||
-- rawset(ret,"_fit_geometry_cache", ret._internal.layout._fit_geometry_cache)
|
|
||||||
-- rawset(ret,"add_signal", function()end)
|
|
||||||
-- ret._internal.layout:connect_signal("widget::updated",function()
|
|
||||||
-- ret:emit_signal("widget::updated")
|
|
||||||
-- end)
|
|
||||||
return ret,ret._internal.margin
|
return ret,ret._internal.margin
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -193,10 +49,13 @@ function module.flex(args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
args.internal = args.internal or {}
|
args.internal = args.internal or {}
|
||||||
args.internal.layout_func = wibox.layout.flex.horizontal()
|
args.internal.layout_func = wibox.layout.flex.horizontal()
|
||||||
|
|
||||||
local data = new(args)
|
local data = new(args)
|
||||||
data._internal.text_fit = function(self,width,height) return width,height end
|
|
||||||
|
function data._internal.text_fit(self,width,height) return width,height end
|
||||||
|
|
||||||
return data,data._internal.margin
|
return data,data._internal.margin
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(module, { __call = function(_, ...) return new(...) end })
|
return setmetatable(module, { __call = function(_, ...) return new(...) end })
|
||||||
-- kate: space-indent on; indent-width 2; replace-tabs on;
|
-- kate: space-indent on; indent-width 4; replace-tabs on;
|
||||||
|
|
82
base.lua
82
base.lua
|
@ -10,6 +10,7 @@ local object = require( "radical.object" )
|
||||||
local vertical = require( "radical.layout.vertical" )
|
local vertical = require( "radical.layout.vertical" )
|
||||||
local theme = require( "radical.theme" )
|
local theme = require( "radical.theme" )
|
||||||
local item_mod = require( "radical.item" )
|
local item_mod = require( "radical.item" )
|
||||||
|
local common = require( "radical.common" )
|
||||||
|
|
||||||
local capi = { mouse = mouse, screen = screen , keygrabber = keygrabber, root=root, }
|
local capi = { mouse = mouse, screen = screen , keygrabber = keygrabber, root=root, }
|
||||||
|
|
||||||
|
@ -97,7 +98,7 @@ local function filter(data)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
data._total_item_height = visible_counter
|
data._total_item_height = visible_counter
|
||||||
local w,h = data._internal.layout:fit()
|
|
||||||
-- Make sure to select an item
|
-- Make sure to select an item
|
||||||
if data._current_item and data._current_item._filter_out then
|
if data._current_item and data._current_item._filter_out then
|
||||||
local n = data.next_item
|
local n = data.next_item
|
||||||
|
@ -105,7 +106,7 @@ local function filter(data)
|
||||||
n.selected = true
|
n.selected = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
data.height = h
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -163,10 +164,8 @@ local function activateKeyboard(data)
|
||||||
end
|
end
|
||||||
|
|
||||||
if (key == 'Return') and data._current_item and data._current_item.button1 then
|
if (key == 'Return') and data._current_item and data._current_item.button1 then
|
||||||
if data.sub_menu_on == module.event.BUTTON1 then
|
|
||||||
item_mod.execute_sub_menu(data,data._current_item)
|
|
||||||
else
|
|
||||||
data._current_item.button1(data,data._current_item)
|
data._current_item.button1(data,data._current_item)
|
||||||
|
if data.sub_menu_on ~= module.event.BUTTON1 then
|
||||||
data.visible = false
|
data.visible = false
|
||||||
end
|
end
|
||||||
elseif key == 'Escape' or (key == 'Tab' and data.filter_string == "") then
|
elseif key == 'Escape' or (key == 'Tab' and data.filter_string == "") then
|
||||||
|
@ -187,7 +186,6 @@ local function activateKeyboard(data)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
---------------------------------ITEM HANDLING----------------------------------
|
---------------------------------ITEM HANDLING----------------------------------
|
||||||
local function add_item(data,args)
|
local function add_item(data,args)
|
||||||
local item = item_mod(data,args)
|
local item = item_mod(data,args)
|
||||||
|
@ -195,6 +193,32 @@ local function add_item(data,args)
|
||||||
if args.selected == true then
|
if args.selected == true then
|
||||||
item.selected = true
|
item.selected = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Show sub-menu
|
||||||
|
if item._private_data.sub_menu_f or item._private_data.sub_menu_m then
|
||||||
|
if data.sub_menu_on == module.event.SELECTED then
|
||||||
|
item.widget:set_menu(
|
||||||
|
function()
|
||||||
|
local sub_menu = item._private_data.sub_menu_m
|
||||||
|
|
||||||
|
if not sub_menu and item._private_data.sub_menu_f then
|
||||||
|
sub_menu = item._private_data.sub_menu_f(item.widget)
|
||||||
|
end
|
||||||
|
|
||||||
|
if sub_menu and (item._private_data.sub_menu_f or sub_menu.rowcount > 0) then
|
||||||
|
sub_menu.arrow_type = module.arrow_type.NONE
|
||||||
|
sub_menu.parent_item = item
|
||||||
|
item._tmp_menu = sub_menu
|
||||||
|
data._tmp_menu = sub_menu
|
||||||
|
end
|
||||||
|
|
||||||
|
return sub_menu
|
||||||
|
end,
|
||||||
|
"mouse::enter"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
item.index = data.rowcount
|
item.index = data.rowcount
|
||||||
data:emit_signal("item::added",item)
|
data:emit_signal("item::added",item)
|
||||||
return item
|
return item
|
||||||
|
@ -233,16 +257,10 @@ local function add_widget(data,widget,args)
|
||||||
})
|
})
|
||||||
item._private_data = private_data
|
item._private_data = private_data
|
||||||
item._internal = {}
|
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.widgets[#data._internal.widgets+1] = item
|
||||||
data._internal.items[#data._internal.items+1] = item
|
data._internal.items[#data._internal.items+1] = item
|
||||||
data:emit_signal("widget::added",item,widget)
|
data:emit_signal("widget::added",item,widget)
|
||||||
if data.visible then
|
|
||||||
local fit_w,fit_h = data._internal.layout:get_preferred_size()
|
|
||||||
data.width = data._internal.width or fit_w
|
|
||||||
data.height = fit_h
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function add_widgets(data,widgets)
|
local function add_widgets(data,widgets)
|
||||||
|
@ -360,8 +378,8 @@ local function new(args)
|
||||||
overlay = args.overlay or nil,
|
overlay = args.overlay or nil,
|
||||||
overlay_draw = args.overlay_draw or nil,
|
overlay_draw = args.overlay_draw or nil,
|
||||||
opacity = args.opacity or beautiful.menu_opacity or 1,
|
opacity = args.opacity or beautiful.menu_opacity or 1,
|
||||||
spacing = args.spacing or nil, --TODO add to README once merged upstream
|
spacing = args.spacing or nil,
|
||||||
default_margins = args.default_margins or {},
|
default_margins = args.default_margins or beautiful.menu_default_margins or {},
|
||||||
icon_per_state = args.icon_per_state or false,
|
icon_per_state = args.icon_per_state or false,
|
||||||
default_item_margins = args.default_item_margins or {},
|
default_item_margins = args.default_item_margins or {},
|
||||||
icon_transformation = args.icon_transformation or nil,
|
icon_transformation = args.icon_transformation or nil,
|
||||||
|
@ -407,33 +425,21 @@ local function new(args)
|
||||||
-- Setters
|
-- Setters
|
||||||
data.set_auto_resize = function(_,val) private_data[""] = val end
|
data.set_auto_resize = function(_,val) private_data[""] = val end
|
||||||
data.set_parent_geometry = function(_,value)
|
data.set_parent_geometry = function(_,value)
|
||||||
private_data.parent_geometry = value
|
private_data.parent_geometry = value --TODO delete
|
||||||
if data._internal.get_direction then
|
|
||||||
data.direction = data._internal.get_direction(data)
|
|
||||||
end
|
|
||||||
if data._internal.set_position then
|
|
||||||
data._internal.set_position(data)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
data.set_visible = function(_,value)
|
data.set_visible = function(_,value)
|
||||||
private_data.visible = value
|
private_data.visible = value
|
||||||
if value then
|
if data._tmp_menu and data._current_item then
|
||||||
local fit_w,fit_h = data._internal.layout:get_preferred_size()
|
|
||||||
data.width = internal.width or fit_w
|
|
||||||
data.height = fit_h
|
|
||||||
elseif data._tmp_menu and data._current_item then
|
|
||||||
-- data._tmp_menu = nil
|
|
||||||
data._current_item._tmp_menu = nil
|
data._current_item._tmp_menu = nil
|
||||||
-- data._current_item.selected = false
|
|
||||||
data.item_style(data._current_item,{})
|
data.item_style(data._current_item,{})
|
||||||
end
|
end
|
||||||
if internal.has_changed and data.style then
|
if internal.has_changed and data.style then
|
||||||
data.style(data,{arrow_x=20,margin=internal.margin})
|
data.style(data,{arrow_x=20,margin=internal.margin})
|
||||||
end
|
end
|
||||||
-- if not internal.parent_geometry and data._internal.set_position then
|
if internal.set_position then
|
||||||
internal.set_position(data)
|
internal.set_position(data)
|
||||||
-- end
|
end
|
||||||
if internal.set_visible then
|
if internal.set_visible then
|
||||||
internal:set_visible(value)
|
internal:set_visible(value)
|
||||||
end
|
end
|
||||||
|
@ -442,6 +448,11 @@ local function new(args)
|
||||||
elseif data.parent_geometry and not data.parent_geometry.is_menu and data.enable_keyboard then
|
elseif data.parent_geometry and not data.parent_geometry.is_menu and data.enable_keyboard then
|
||||||
capi.keygrabber.stop()
|
capi.keygrabber.stop()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Hide the sub menus when hiding
|
||||||
|
if data._tmp_menu and not value then
|
||||||
|
data._tmp_menu.visible = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
data.add_colors_group = function(data,section)
|
data.add_colors_group = function(data,section)
|
||||||
|
@ -450,7 +461,8 @@ local function new(args)
|
||||||
|
|
||||||
data.set_layout = function(_,value)
|
data.set_layout = function(_,value)
|
||||||
if value then
|
if value then
|
||||||
value:setup_key_hooks(data)
|
local f = value.setup_key_hooks or common.setup_key_hooks
|
||||||
|
f(value, data)
|
||||||
end
|
end
|
||||||
private_data.layout = value
|
private_data.layout = value
|
||||||
end
|
end
|
||||||
|
@ -637,8 +649,9 @@ local function new(args)
|
||||||
|
|
||||||
function data:hide()
|
function data:hide()
|
||||||
data.visible = false
|
data.visible = false
|
||||||
if data.parent_geometry and data.parent_geometry.is_menu then
|
|
||||||
local parent = data.parent_geometry
|
if data.parent_geometry and data.parent_geometry.parent_menu then
|
||||||
|
local parent = data.parent_geometry.parent_menu
|
||||||
while parent do
|
while parent do
|
||||||
parent.visible = false
|
parent.visible = false
|
||||||
parent = parent.parent_geometry and parent.parent_geometry.is_menu and parent.parent_geometry
|
parent = parent.parent_geometry and parent.parent_geometry.is_menu and parent.parent_geometry
|
||||||
|
@ -647,7 +660,8 @@ local function new(args)
|
||||||
end
|
end
|
||||||
|
|
||||||
if private_data.layout then
|
if private_data.layout then
|
||||||
private_data.layout:setup_key_hooks(data)
|
local f = private_data.layout.setup_key_hooks or common.setup_key_hooks
|
||||||
|
f(value, data)
|
||||||
end
|
end
|
||||||
|
|
||||||
data._internal.setup_drawable(data)
|
data._internal.setup_drawable(data)
|
||||||
|
|
21
box.lua
21
box.lua
|
@ -1,22 +1,21 @@
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
local context = require( "radical.context" )
|
local context = require( "radical.context" )
|
||||||
local base = require( "radical.base" )
|
local base = require( "radical.base" )
|
||||||
local capi = { mouse = mouse, screen = screen }
|
local shape = require( "gears.shape" )
|
||||||
|
local placement = require( "awful.placement" )
|
||||||
local function set_position(data)
|
|
||||||
local s = data.screen or capi.mouse.screen
|
|
||||||
s = s > capi.screen.count() and 1 or s
|
|
||||||
local geom = capi.screen[s].geometry
|
|
||||||
data.wibox.x = math.ceil(geom.x + (geom.width/2) - data.width/2)
|
|
||||||
data.wibox.y = math.ceil(geom.y + (geom.height/2) - data.height/2)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function new(args)
|
local function new(args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
args.internal = args.internal or {}
|
args.internal = args.internal or {}
|
||||||
args.arrow_type = base.arrow_type.NONE
|
args.arrow_type = base.arrow_type.NONE
|
||||||
args.internal.set_position = args.internal.set_position or set_position
|
|
||||||
return context(args)
|
local ret = context(args)
|
||||||
|
-- placement.centered (ret.wibox)
|
||||||
|
-- ret.wibox:set_valign("center")
|
||||||
|
-- ret.wibox:set_halign("center")
|
||||||
|
ret.wibox:set_shape (shape.rounded_rect, 10)
|
||||||
|
|
||||||
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable({}, { __call = function(_, ...) return new(...) end })
|
return setmetatable({}, { __call = function(_, ...) return new(...) end })
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
-- Gather common code that can be shared between multiple sub-systems to widgets
|
||||||
|
local item_mod = require( "radical.item" )
|
||||||
|
local wibox = require( "wibox" )
|
||||||
|
local horizontal_item_layout = require( "radical.item.layout.horizontal" )
|
||||||
|
local margins2 = require( "radical.margins" )
|
||||||
|
|
||||||
|
local module = {}
|
||||||
|
|
||||||
|
local function left(data)
|
||||||
|
if data._current_item._tmp_menu then
|
||||||
|
data = data._current_item._tmp_menu
|
||||||
|
data.items[1].selected = true
|
||||||
|
return true,data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function right(data)
|
||||||
|
if data.parent_geometry and data.parent_geometry.is_menu then
|
||||||
|
for k,v in ipairs(data.items) do
|
||||||
|
if v._tmp_menu == data or v.sub_menu_m == data then
|
||||||
|
v.selected = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
data.visible = false
|
||||||
|
data = data.parent_geometry
|
||||||
|
return true,data
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function up(data)
|
||||||
|
if not data.previous_item then return end
|
||||||
|
data.previous_item.selected = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function down(data)
|
||||||
|
if not data.next_item then return end
|
||||||
|
data.next_item.selected = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function module:setup_key_hooks(data)
|
||||||
|
data:add_key_hook({}, "Up" , "press", up )
|
||||||
|
data:add_key_hook({}, "Down" , "press", down )
|
||||||
|
data:add_key_hook({}, "Left" , "press", right )
|
||||||
|
data:add_key_hook({}, "Right" , "press", left )
|
||||||
|
end
|
||||||
|
|
||||||
|
function module.get_margins(data)
|
||||||
|
local internal = data._internal
|
||||||
|
|
||||||
|
if not internal._margins then
|
||||||
|
local ret = {
|
||||||
|
left = data.border_width+(data.default_margins.left
|
||||||
|
or (data.style and data.style.margins.LEFT ) or 0),
|
||||||
|
right = data.border_width+(data.default_margins.right
|
||||||
|
or (data.style and data.style.margins.RIGHT ) or 0),
|
||||||
|
top = data.border_width+(data.default_margins.top
|
||||||
|
or (data.style and data.style.margins.TOP ) or 0),
|
||||||
|
bottom = data.border_width+(data.default_margins.bottom
|
||||||
|
or (data.style and data.style.margins.BOTTOM ) or 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
local m = margins2(internal.margin,ret)
|
||||||
|
rawset(m,"_reset",m.reset)
|
||||||
|
|
||||||
|
function m.reset(margins)
|
||||||
|
m.defaults = ret
|
||||||
|
m:_reset()
|
||||||
|
end
|
||||||
|
|
||||||
|
internal._margins = m
|
||||||
|
end
|
||||||
|
|
||||||
|
return internal._margins
|
||||||
|
end
|
||||||
|
|
||||||
|
function module.setup_buttons(data,item,args)
|
||||||
|
local buttons = {}
|
||||||
|
for i=1,10 do
|
||||||
|
if args["button"..i] then
|
||||||
|
buttons[i] = args["button"..i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Setup sub_menu
|
||||||
|
if (item.sub_menu_m or item.sub_menu_f) and data.sub_menu_on >= item_mod.event.BUTTON1 and data.sub_menu_on <= item_mod.event.BUTTON3 then
|
||||||
|
item.widget:set_menu(item.sub_menu_m or item.sub_menu_f,"button::pressed",data.sub_menu_on)
|
||||||
|
end
|
||||||
|
|
||||||
|
--Hide on right click
|
||||||
|
if not buttons[3] then
|
||||||
|
buttons[3] = function()
|
||||||
|
data:hide()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Scroll up
|
||||||
|
if not buttons[4] then
|
||||||
|
buttons[4] = function()
|
||||||
|
data:scroll_up()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Scroll down
|
||||||
|
if not buttons[5] then
|
||||||
|
buttons[5] = function()
|
||||||
|
data:scroll_down()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
item:connect_signal("button::release",function(_m,_i,button_id,mods,geo)
|
||||||
|
if #mods == 0 and buttons[button_id] then
|
||||||
|
buttons[button_id](_m,_i,mods,geo)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function module.setup_item_move_events(data)
|
||||||
|
local internal = data._internal
|
||||||
|
local l = internal.content_layout or internal.layout
|
||||||
|
|
||||||
|
--SWAP / MOVE / REMOVE
|
||||||
|
data:connect_signal("item::swapped",function(_,item1,item2,index1,index2)
|
||||||
|
l:swap(index1, index2)
|
||||||
|
end)
|
||||||
|
|
||||||
|
data:connect_signal("item::moved",function(_,item,new_idx,old_idx)
|
||||||
|
local w = l:get_children()[old_idx]
|
||||||
|
l:remove(old_idx)
|
||||||
|
l:insert(new_idx, w)
|
||||||
|
end)
|
||||||
|
|
||||||
|
data:connect_signal("item::removed",function(_,item,old_idx)
|
||||||
|
l:remove(old_idx)
|
||||||
|
end)
|
||||||
|
|
||||||
|
data:connect_signal("item::appended",function(_,item)
|
||||||
|
l:add(item.widget)
|
||||||
|
end)
|
||||||
|
|
||||||
|
data:connect_signal("item::added", function(_,item)
|
||||||
|
l:add(item.widget)
|
||||||
|
end)
|
||||||
|
|
||||||
|
data:connect_signal("widget::added",function(_,item,widget)
|
||||||
|
wibox.layout.fixed.add(l,item.widget)
|
||||||
|
l:emit_signal("widget::updated")
|
||||||
|
end)
|
||||||
|
|
||||||
|
data:connect_signal("prefix_widget::added",function(_,widget,args)
|
||||||
|
data._internal.pref_l:insert(1,widget)
|
||||||
|
end)
|
||||||
|
|
||||||
|
data:connect_signal("suffix_widget::added",function(_,widget,args)
|
||||||
|
data._internal.suf_l:add(widget)
|
||||||
|
end)
|
||||||
|
|
||||||
|
data._internal.text_fit = function(self, context, width, height)
|
||||||
|
return width,height
|
||||||
|
end
|
||||||
|
|
||||||
|
data:connect_signal("clear::menu",function(_,vis)
|
||||||
|
l:reset()
|
||||||
|
end)
|
||||||
|
|
||||||
|
data:connect_signal("_hidden::changed",function(_,item)
|
||||||
|
item.widget:emit_signal("widget::updated")
|
||||||
|
end)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function module.setup_state_events(data, item)
|
||||||
|
if data.select_on == item_mod.event.HOVER then
|
||||||
|
item.widget:connect_signal("mouse::enter", function() item.selected = true end)
|
||||||
|
item.widget:connect_signal("mouse::leave", function() item.selected = false end)
|
||||||
|
else
|
||||||
|
item.widget:connect_signal("mouse::enter", function() item.hover = true end)
|
||||||
|
item.widget:connect_signal("mouse::leave", function() item.hover = false end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function module.setup_item(data,item,args)
|
||||||
|
--Create the background
|
||||||
|
local item_layout = item.layout or data.item_layout or horizontal_item_layout
|
||||||
|
item_layout(item,data,args)
|
||||||
|
|
||||||
|
-- Layout
|
||||||
|
if data._internal.layout.setup_item then
|
||||||
|
data._internal.layout.setup_item(data._internal.layout,data,item,args)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Buttons
|
||||||
|
module.setup_buttons(data,item,args)
|
||||||
|
|
||||||
|
-- Tooltip
|
||||||
|
item.widget:set_tooltip(item.tooltip)
|
||||||
|
|
||||||
|
-- Set the correct item state
|
||||||
|
module.setup_state_events(data, item)
|
||||||
|
|
||||||
|
-- Setup tooltip
|
||||||
|
item.widget:set_tooltip(item.tooltip)
|
||||||
|
|
||||||
|
-- Apply item style
|
||||||
|
local item_style = item.item_style or data.item_style
|
||||||
|
item_style(item,{})
|
||||||
|
|
||||||
|
-- Enable scrollbar (if necessary)
|
||||||
|
if data._internal.scroll_w and data.rowcount > data.max_items then
|
||||||
|
data._internal.scroll_w.visible = true
|
||||||
|
data._internal.scroll_w["up"]:emit_signal("widget::updated")
|
||||||
|
data._internal.scroll_w["down"]:emit_signal("widget::updated")
|
||||||
|
end
|
||||||
|
|
||||||
|
item.widget:emit_signal("widget::updated")
|
||||||
|
end
|
||||||
|
|
||||||
|
return module
|
316
context.lua
316
context.lua
|
@ -1,307 +1,81 @@
|
||||||
local base = require( "radical.base" )
|
|
||||||
local print = print
|
|
||||||
local unpack = unpack or table.unpack
|
local unpack = unpack or table.unpack
|
||||||
local debug = debug
|
|
||||||
local rawset = rawset
|
local rawset = rawset
|
||||||
local type = type
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
local color = require( "gears.color" )
|
local base = require( "radical.base" )
|
||||||
local wibox = require( "wibox" )
|
local wibox = require( "wibox" )
|
||||||
local beautiful = require( "beautiful" )
|
local beautiful = require( "beautiful" )
|
||||||
local cairo = require( "lgi" ).cairo
|
|
||||||
local awful = require( "awful" )
|
|
||||||
local util = require( "awful.util" )
|
|
||||||
local layout = require( "radical.layout" )
|
local layout = require( "radical.layout" )
|
||||||
local checkbox = require( "radical.widgets.checkbox" )
|
|
||||||
local arrow_style = require( "radical.style.arrow" )
|
local arrow_style = require( "radical.style.arrow" )
|
||||||
local item_mod = require("radical.item")
|
local smart_wibox = require( "radical.smart_wibox" )
|
||||||
local glib = require("lgi").GLib
|
local common = require( "radical.common" )
|
||||||
local margins2 = require("radical.margins")
|
|
||||||
|
|
||||||
local capi,module = { mouse = mouse , screen = screen, keygrabber = keygrabber },{}
|
local capi, module = { keygrabber = keygrabber },{}
|
||||||
|
|
||||||
local function get_direction(data)
|
local function set_visible(i, value)
|
||||||
local parent_geometry = data.parent_geometry --Local cache to avoid always calling the object hooks
|
local w, pg = i.w, i.private_data.parent_geometry
|
||||||
if not parent_geometry or not parent_geometry.drawable then return "bottom" end
|
|
||||||
|
|
||||||
-- The border width is not included in the geometry
|
if value then
|
||||||
local bw = data.wibox.border_width or 0
|
w:move_by_parent(pg, true)
|
||||||
|
|
||||||
local drawable_geom = parent_geometry.drawable.drawable.geometry(parent_geometry.drawable.drawable)
|
|
||||||
|
|
||||||
drawable_geom.x, drawable_geom.height = drawable_geom.x - bw, drawable_geom.height + 2*bw
|
|
||||||
|
|
||||||
if parent_geometry.y+parent_geometry.height < drawable_geom.height then --Vertical wibox
|
|
||||||
if drawable_geom.x >= capi.screen[capi.mouse.screen].geometry.width - (drawable_geom.x+drawable_geom.width) then
|
|
||||||
return "right"
|
|
||||||
else
|
|
||||||
return "left"
|
|
||||||
end
|
|
||||||
else --Horizontal wibox
|
|
||||||
if drawable_geom.y >= capi.screen[capi.mouse.screen].geometry.height - (drawable_geom.y+drawable_geom.height) then
|
|
||||||
return "bottom"
|
|
||||||
else
|
|
||||||
return "top"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function set_geometry_real(data)
|
w.visible = value
|
||||||
local geo = data._internal._next_geometry
|
|
||||||
if geo then
|
|
||||||
for k,v in pairs(geo) do
|
|
||||||
data.wibox[k] = math.ceil(v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
data._internal._next_geometry = nil
|
|
||||||
data._internal._need_geometry_reload = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- This will update the position before the next loop cycle
|
if not value and (not pg or not pg.is_menu) then
|
||||||
-- This avoid tons of round trips with X for dynamic menus
|
|
||||||
local function change_geometry_idle(data, x, y, w, h)
|
|
||||||
data._internal._next_geometry = data._internal._next_geometry or {}
|
|
||||||
local geo = data._internal._next_geometry
|
|
||||||
|
|
||||||
-- The border_width is not included in the geometry
|
|
||||||
geo.x = x and (x - data.wibox.border_width) or geo.x
|
|
||||||
geo.y = y and (y - data.wibox.border_width) or geo.y
|
|
||||||
geo.width = w and (w - data.wibox.border_width) or geo.width
|
|
||||||
geo.height = h and (h - data.wibox.border_width) or geo.height
|
|
||||||
if not data._internal._need_geometry_reload then
|
|
||||||
glib.idle_add(0, function() set_geometry_real(data) end)
|
|
||||||
data._internal._need_geometry_reload = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function set_position(self)
|
|
||||||
if not self.visible then return end
|
|
||||||
local ret,parent = {x=self.x,y=self.y},self.parent_geometry
|
|
||||||
local prefx,prefy = self._internal.private_data.x,self._internal.private_data.y
|
|
||||||
local src_geo = capi.screen[capi.mouse.screen].geometry
|
|
||||||
if parent and parent.is_menu then
|
|
||||||
if parent.direction == "right" then
|
|
||||||
ret={x=parent.x-self.width,y=parent.y+(self.parent_item.y)}
|
|
||||||
else
|
|
||||||
local margins = self.margins
|
|
||||||
ret={x=parent.x+parent.width,y=parent.y+(self.parent_item.y)-(margins and self.margins.top or data.default_margins.top or self.style.margins.TOP)}
|
|
||||||
|
|
||||||
--Handle when the menu doesn't fit in the srceen horizontally
|
|
||||||
if ret.x+self.width > src_geo.x + src_geo.width then
|
|
||||||
ret.x = parent.x - self.width
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Handle when the menu doesn't fit on the screen vertically
|
|
||||||
if ret.y+self.height > src_geo.y + src_geo.height then
|
|
||||||
ret.y = ret.y - self.height + self.item_height + 2*(margins and self.margins.top or data.default_margins.top or self.style.margins.TOP)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif parent then
|
|
||||||
local drawable_geom = parent.drawable.drawable.geometry(parent.drawable.drawable)
|
|
||||||
if (self.direction == "left") or (self.direction == "right") then
|
|
||||||
ret = {
|
|
||||||
x=drawable_geom.x+((self.direction == "right") and - self.width or drawable_geom.width),
|
|
||||||
y=drawable_geom.y+parent.y--[[+((self.arrow_type ~= base.arrow_type.NONE) and parent.height/2-(self.arrow_x or 20)-6 or 0)]]
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ret = {
|
|
||||||
x=drawable_geom.x+parent.x-((self.arrow_type ~= base.arrow_type.NONE) and (self.arrow_x or 20)+11-parent.width/2 or 0),
|
|
||||||
y=(self.direction == "bottom") and drawable_geom.y-self.height or drawable_geom.y+drawable_geom.height}
|
|
||||||
end
|
|
||||||
elseif prefx ~= 0 or prefy ~= 0 then
|
|
||||||
ret = capi.mouse.coords()
|
|
||||||
if prefx then
|
|
||||||
ret.x = prefx
|
|
||||||
end
|
|
||||||
if prefy then
|
|
||||||
ret.y = prefy
|
|
||||||
end
|
|
||||||
else --Use mouse position to set position --TODO it is called too often
|
|
||||||
ret = capi.mouse.coords()
|
|
||||||
local draw = awful.mouse.wibox_under_pointer and awful.mouse.wibox_under_pointer() or awful.mouse.drawin_under_pointer and awful.mouse.drawin_under_pointer()
|
|
||||||
if draw then
|
|
||||||
local geometry = draw.geometry(draw)
|
|
||||||
if self.direction == "top" or self.direction == "bottom" then
|
|
||||||
ret.x = ret.x - (self.arrow_x or 20) - 13
|
|
||||||
ret.y = geometry.y+geometry.height
|
|
||||||
if ret.y+self.height > src_geo.height then
|
|
||||||
self.direction = "bottom"
|
|
||||||
ret.y = geometry.y-self.height
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--Handle when menu doesn't fit horizontally (if not handled earlier)
|
|
||||||
if ret.x+self.width > src_geo.x + src_geo.width then
|
|
||||||
ret.x = ret.x - (ret.x+self.width - (src_geo.x + src_geo.width))
|
|
||||||
elseif ret.x < 0 then
|
|
||||||
ret.x = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
change_geometry_idle(self,ret.x,ret.y - 2*(self.wibox.border_width or 0))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function setup_drawable(data)
|
|
||||||
local internal = data._internal
|
|
||||||
local private_data = internal.private_data
|
|
||||||
|
|
||||||
--Init
|
|
||||||
internal.w = wibox({})
|
|
||||||
internal.margin = wibox.layout.margin()
|
|
||||||
if not data.layout then
|
|
||||||
data.layout = layout.vertical
|
|
||||||
end
|
|
||||||
internal.layout = data.layout(data)
|
|
||||||
internal.w.visible = false
|
|
||||||
internal.w.ontop = true
|
|
||||||
internal.margin:set_widget(internal.layout)
|
|
||||||
internal.w:set_widget(internal.margin)
|
|
||||||
internal.w:set_fg(data.fg)
|
|
||||||
internal.w.opacity = data.opacity
|
|
||||||
internal.w.border_color = data.border_color or beautiful.menu_outline_color or beautiful.menu_border_color or beautiful.fg_normal
|
|
||||||
internal.w:set_bg(data.bg)
|
|
||||||
|
|
||||||
--Getters
|
|
||||||
data.get_wibox = function() return internal.w end
|
|
||||||
data.get_x = function() return data._internal._next_geometry and data._internal._next_geometry.x or internal.w.x end
|
|
||||||
data.get_y = function() return data._internal._next_geometry and data._internal._next_geometry.y or internal.w.y end
|
|
||||||
data.get_width = function() return data._internal._next_geometry and data._internal._next_geometry.width or internal.w.width end
|
|
||||||
data.get_height = function() return data._internal._next_geometry and data._internal._next_geometry.height or 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()
|
|
||||||
if not internal._margins then
|
|
||||||
local ret = {
|
|
||||||
left = data.border_width+(data.default_margins.left or data.style.margins.LEFT or 0),
|
|
||||||
right = data.border_width+(data.default_margins.right or data.style.margins.RIGHT or 0),
|
|
||||||
top = data.border_width+(data.default_margins.top or data.style.margins.TOP or 0),
|
|
||||||
bottom = data.border_width+(data.default_margins.bottom or data.style.margins.BOTTOM or 0),
|
|
||||||
}
|
|
||||||
local m = margins2(internal.margin,ret)
|
|
||||||
rawset(m,"_reset",m.reset)
|
|
||||||
m.reset = function(margins)
|
|
||||||
m.defaults = ret
|
|
||||||
m:_reset()
|
|
||||||
end
|
|
||||||
internal._margins = m
|
|
||||||
end
|
|
||||||
return internal._margins
|
|
||||||
end
|
|
||||||
|
|
||||||
--Setters
|
|
||||||
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()
|
|
||||||
data.height = fit_h
|
|
||||||
data.width = fit_w
|
|
||||||
end
|
|
||||||
end
|
|
||||||
data.set_x = function(_,value) change_geometry_idle(data,value) end
|
|
||||||
data.set_y = function(_,value) change_geometry_idle(data,nil,value) end
|
|
||||||
data.set_width = function(_,value)
|
|
||||||
local need_update = internal.w.width == (value + 2*data.border_width)
|
|
||||||
local margins = data.margins
|
|
||||||
change_geometry_idle(data,nil,nil,value + data.margins.left + data.margins.right)
|
|
||||||
if need_update then
|
|
||||||
data.style(data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
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
|
|
||||||
change_geometry_idle(data,nil,nil,nil,new_height > 0 and new_height or 1)
|
|
||||||
if need_update then
|
|
||||||
data.style(data)
|
|
||||||
internal.set_position(data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function internal:set_visible(value)
|
|
||||||
internal.w.visible = value
|
|
||||||
if not value and (not data.parent_geometry or not data.parent_geometry.is_menu) then
|
|
||||||
capi.keygrabber.stop()
|
capi.keygrabber.stop()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if data.visible then
|
local function setup_drawable(data)
|
||||||
local fit_w,fit_h = data._internal.layout:fit()
|
local internal = data._internal
|
||||||
data.width = fit_w
|
|
||||||
data.height = fit_h
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function setup_buttons(data,item,args)
|
-- Create the layout
|
||||||
local buttons = {}
|
data.layout = data.layout or layout.vertical
|
||||||
for i=1,10 do
|
|
||||||
if args["button"..i] then
|
|
||||||
buttons[i] = args["button"..i]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Click to open sub_menu
|
internal.layout = data.layout(data)
|
||||||
if not buttons[1] and data.sub_menu_on == base.event.BUTTON1 then
|
internal.margin = wibox.layout.margin(internal.layout)
|
||||||
buttons[1] = function() item_mod.execute_sub_menu(data,item) end
|
|
||||||
end
|
|
||||||
|
|
||||||
--Hide on right click
|
-- Init
|
||||||
if not buttons[3] then
|
internal.w = smart_wibox(internal.margin, {
|
||||||
buttons[3] = function()
|
visible = false ,
|
||||||
data:hide()
|
ontop = true ,
|
||||||
end
|
opacity = data.opacity ,
|
||||||
end
|
bg = data.bg ,
|
||||||
|
fg = data.fg ,
|
||||||
|
preferred_positions = {"right", "bottom"},
|
||||||
|
border_color = data.border_color
|
||||||
|
or beautiful.menu_outline_color
|
||||||
|
or beautiful.menu_border_color
|
||||||
|
or beautiful.fg_normal
|
||||||
|
})
|
||||||
|
|
||||||
-- Scroll up
|
-- Accessors
|
||||||
if not buttons[4] then
|
data.get_wibox = function() return internal.w end
|
||||||
buttons[4] = function()
|
data.get_visible = function() return internal.private_data.visible end
|
||||||
data:scroll_up()
|
data.get_margins = common.get_margins
|
||||||
end
|
internal.set_visible = set_visible
|
||||||
end
|
|
||||||
|
|
||||||
-- Scroll down
|
|
||||||
if not buttons[5] then
|
|
||||||
buttons[5] = function()
|
|
||||||
data:scroll_down()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
item:connect_signal("button::release",function(_m,_i,button_id,mods,geo)
|
-- Support remove, swap, insert, append...
|
||||||
if #mods == 0 and buttons[button_id] then
|
common.setup_item_move_events(data)
|
||||||
buttons[button_id](_m,_i,mods,geo)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function setup_item(data,item,args)
|
|
||||||
-- Layout
|
|
||||||
local f = (data._internal.layout.setup_item) or (layout.vertical.setup_item)
|
|
||||||
f(data._internal.layout,data,item,args)
|
|
||||||
|
|
||||||
-- Buttons
|
|
||||||
setup_buttons(data,item,args)
|
|
||||||
|
|
||||||
-- Tooltip
|
|
||||||
item.widget:set_tooltip(item.tooltip)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function new(args)
|
local function new(args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
args.internal = args.internal or {}
|
args.internal = args.internal or {}
|
||||||
args.internal.get_direction = args.internal.get_direction or get_direction
|
|
||||||
args.internal.set_position = args.internal.set_position or set_position
|
|
||||||
args.internal.setup_drawable = args.internal.setup_drawable or setup_drawable
|
args.internal.setup_drawable = args.internal.setup_drawable or setup_drawable
|
||||||
args.internal.setup_item = args.internal.setup_item or setup_item
|
args.internal.setup_item = args.internal.setup_item or common.setup_item
|
||||||
args.style = args.style or beautiful.menu_default_style or arrow_style
|
args.style = args.style or beautiful.menu_default_style or arrow_style
|
||||||
local ret = base(args)
|
local ret = base(args)
|
||||||
ret:connect_signal("clear::menu",function(_,vis)
|
|
||||||
ret._internal.layout:reset()
|
ret:connect_signal("parent_geometry::changed", function()
|
||||||
end)
|
args.internal.w:move_by_parent(ret.parent_geometry, true)
|
||||||
ret:connect_signal("_hidden::changed",function(_,item)
|
|
||||||
item.widget:emit_signal("widget::updated")
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- Init the style
|
||||||
|
args.style(ret)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(module, { __call = function(_, ...) return new(...) end })
|
return setmetatable(module, { __call = function(_, ...) return new(...) end })
|
||||||
-- kate: space-indent on; indent-width 2; replace-tabs on;
|
-- kate: space-indent on; indent-width 4; replace-tabs on;
|
||||||
|
|
341
dock.lua
341
dock.lua
|
@ -1,141 +1,29 @@
|
||||||
local setmetatable,unpack,table = setmetatable,unpack,table
|
local setmetatable = setmetatable
|
||||||
local math = math
|
local math = math
|
||||||
local base = require( "radical.base" )
|
local base = require( "radical.base" )
|
||||||
local color = require( "gears.color" )
|
local color = require( "gears.color" )
|
||||||
local wibox = require( "wibox" )
|
local wibox = require( "wibox" )
|
||||||
local beautiful = require( "beautiful" )
|
local beautiful = require( "beautiful" )
|
||||||
local cairo = require( "lgi" ).cairo
|
|
||||||
local awful = require( "awful" )
|
|
||||||
local util = require( "awful.util" )
|
|
||||||
local fkey = require( "radical.widgets.fkey" )
|
|
||||||
local button = require( "awful.button" )
|
|
||||||
local checkbox = require( "radical.widgets.checkbox" )
|
|
||||||
local vertical = require( "radical.layout.vertical" )
|
local vertical = require( "radical.layout.vertical" )
|
||||||
local horizontal = require( "radical.layout.horizontal" )
|
local horizontal = require( "radical.layout.horizontal" )
|
||||||
local item_layout = require( "radical.item.layout.icon" )
|
local item_layout = require( "radical.item.layout.icon" )
|
||||||
local item_style = require( "radical.item.style.rounded" )
|
local item_style = require( "radical.item.style.rounded" )
|
||||||
local glib = require( "lgi" ).GLib
|
local hot_corner = require( "radical.hot_corner" )
|
||||||
local margins2 = require("radical.margins" )
|
local shape = require( "gears.shape" )
|
||||||
|
local common = require( "radical.common" )
|
||||||
|
local smart_wibox = require( "radical.smart_wibox" )
|
||||||
|
local placement = require( "radical.placement" )
|
||||||
|
|
||||||
|
local default_radius = 10
|
||||||
|
local rad = beautiful.dock_corner_radius or default_radius
|
||||||
|
local default_shape = function(cr, width, height) shape.partially_rounded_rect(cr, width, height, false, true, true, false, rad) end
|
||||||
|
|
||||||
local capi,module = { mouse = mouse , screen = screen, keygrabber = keygrabber },{}
|
local capi,module = { mouse = mouse , screen = screen, keygrabber = keygrabber },{}
|
||||||
local max_size = {height={},width={}}
|
local max_size = {height={},width={}}
|
||||||
|
|
||||||
local default_radius = 10
|
|
||||||
|
|
||||||
local dir_to_deg = {left=0,bottom=math.pi/2,right=math.pi,top=3*(math.pi/2)}
|
|
||||||
|
|
||||||
local function get_direction(data)
|
|
||||||
local dir = data._internal.position or "left"
|
|
||||||
return dir,dir_to_deg[dir]--"left" -- Nothing to do
|
|
||||||
end
|
|
||||||
|
|
||||||
--No, screen 1 is not always at x=0, yet
|
|
||||||
local function get_first_screen()
|
|
||||||
for i=1,capi.screen.count() do
|
|
||||||
if capi.screen[i].geometry.x == 0 then
|
|
||||||
return i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
------------------------------------
|
|
||||||
-- Drawing related code --
|
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
local function rotate2(img, geometry, angle,swap_size)
|
|
||||||
geometry = swap_size and {width = geometry.height, height=geometry.width} or geometry
|
|
||||||
local matrix,pattern,img2 = cairo.Matrix(),cairo.Pattern.create_for_surface(img),cairo.ImageSurface(cairo.Format.ARGB32, geometry.width, geometry.height)
|
|
||||||
cairo.Matrix.init_rotate(matrix,angle)
|
|
||||||
matrix:translate((angle == math.pi/2) and 0 or -geometry.width, (angle == 3*(math.pi/2)) and 0 or -geometry.height)
|
|
||||||
pattern:set_matrix(matrix)
|
|
||||||
local cr2 = cairo.Context(img2)
|
|
||||||
cr2:set_source(pattern)
|
|
||||||
cr2:paint()
|
|
||||||
return img2
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Draw the round corners
|
|
||||||
local function mask(rotate,width,height,radius,offset,anti,bg,fg)
|
|
||||||
local invert = (rotate ~= 0) and (rotate ~= math.pi)
|
|
||||||
local width,height = invert and height or width,invert and width or height
|
|
||||||
local img = cairo.ImageSurface.create(cairo.Format.ARGB32, width, height)
|
|
||||||
local cr = cairo.Context(img)
|
|
||||||
cr:set_operator(cairo.Operator.SOURCE)
|
|
||||||
cr:set_antialias(anti)
|
|
||||||
cr:rectangle(0, 0, width, height)
|
|
||||||
cr:set_source(bg)
|
|
||||||
cr:fill()
|
|
||||||
cr:set_source(fg)
|
|
||||||
cr:arc(width-radius-1-offset,radius+offset*2,radius,0,2*math.pi)
|
|
||||||
cr:arc(width-radius-1-offset,height-radius-2*offset,radius,0,2*math.pi)
|
|
||||||
cr:rectangle(0, offset, width-radius-1, height-2*offset)
|
|
||||||
cr:rectangle(width-radius-1-offset, radius+2*offset, radius, height-2*radius-2*offset)
|
|
||||||
cr:fill()
|
|
||||||
return rotate~=0 and rotate2(img,{width=width,height=height},rotate,true) or img
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Do not draw over the boder, ever
|
|
||||||
local function dock_draw(self, context, cr, width, height)
|
|
||||||
|
|
||||||
local w = context.wibox
|
|
||||||
|
|
||||||
-- Generate the border surface
|
|
||||||
if not self.mask or self.mask_hash ~= width*1000+height then
|
|
||||||
local dir,rotation = get_direction(self.data)
|
|
||||||
self.mask = mask(rotation,w.width,w.height,(beautiful.dock_corner_radius or default_radius) - 2,1,0,color(self.data.border_color or seld.data.fg),color("#FF000000"))
|
|
||||||
self.mask_hash = width*1000+height
|
|
||||||
end
|
|
||||||
cr:save()
|
|
||||||
|
|
||||||
--Draw the border
|
|
||||||
--self.__draw(self, context, cr, width, height)
|
|
||||||
cr:set_source_surface(self.mask)
|
|
||||||
cr:paint()
|
|
||||||
cr:restore()
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--Make sure the wibox is at the center of the screen
|
|
||||||
local function align_wibox(w,direction,screen)
|
|
||||||
local axis = (direction == "left" or direction == "right") and "height" or "width"
|
|
||||||
local offset = axis == "height" and "y" or "x"
|
|
||||||
local src_geom = capi.screen[screen].geometry
|
|
||||||
local scr_size = src_geom[offset] + (src_geom[axis] - w[axis]) /2
|
|
||||||
|
|
||||||
w[offset] = math.ceil(scr_size)
|
|
||||||
if direction == "left" then
|
|
||||||
w.x = math.ceil(src_geom.x)
|
|
||||||
elseif direction == "right" then
|
|
||||||
w.x = math.ceil(src_geom.x + src_geom.width - w.width)
|
|
||||||
elseif direction == "bottom" then
|
|
||||||
w.y = math.ceil(src_geom.y+src_geom.height-w.height)
|
|
||||||
else
|
|
||||||
w.y = math.ceil(src_geom.y)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------
|
|
||||||
-- Size and position related code --
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
-- Change the position, TODO
|
|
||||||
local function set_position(self,value)
|
|
||||||
self._internal.position = value
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_position(self,value)
|
|
||||||
return self._internal.position
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Compute the optimal maxmimum size
|
-- Compute the optimal maxmimum size
|
||||||
local function get_max_size(data,screen)
|
local function get_max_size(data,screen)
|
||||||
local dir = get_direction(data)
|
local dir = "left"
|
||||||
local w_or_h = ((dir == "left" or dir == "right") and "height" or "width")
|
local w_or_h = ((dir == "left" or dir == "right") and "height" or "width")
|
||||||
local x_or_y = w_or_h == "height" and "y" or "x"
|
local x_or_y = w_or_h == "height" and "y" or "x"
|
||||||
local res = max_size[w_or_h][screen]
|
local res = max_size[w_or_h][screen]
|
||||||
|
@ -144,22 +32,14 @@ local function get_max_size(data,screen)
|
||||||
local top,bottom = wa[x_or_y],full-(wa.y+wa[w_or_h])
|
local top,bottom = wa[x_or_y],full-(wa.y+wa[w_or_h])
|
||||||
local biggest = top > bottom and top or bottom
|
local biggest = top > bottom and top or bottom
|
||||||
--res = full - biggest*2 - 52 -- 26px margins
|
--res = full - biggest*2 - 52 -- 26px margins
|
||||||
res = wa[w_or_h] - 52 -- 26px margins
|
local margin = beautiful.dock_margin or 52
|
||||||
|
res = wa[w_or_h] - margin
|
||||||
max_size[w_or_h][screen] = res
|
max_size[w_or_h][screen] = res
|
||||||
end
|
end
|
||||||
return res
|
return res
|
||||||
end
|
end
|
||||||
|
|
||||||
-- local function get_size(data,screen)
|
--TODO it still works, but rewrite this code anyway
|
||||||
-- local max = get_max_size(data,screen)
|
|
||||||
-- if data._internal.orientation == "vertical" and h > max then
|
|
||||||
--
|
|
||||||
-- elseif data._internal.orientation == "horizontal" and w > max then
|
|
||||||
--
|
|
||||||
-- end
|
|
||||||
-- return w,h,max
|
|
||||||
-- end
|
|
||||||
|
|
||||||
-- The dock always have to be shorter than the screen
|
-- The dock always have to be shorter than the screen
|
||||||
local function adapt_size(data,w,h,screen)
|
local function adapt_size(data,w,h,screen)
|
||||||
local max = get_max_size(data,screen)
|
local max = get_max_size(data,screen)
|
||||||
|
@ -171,7 +51,9 @@ local function adapt_size(data,w,h,screen)
|
||||||
-- This can be used to approximate the number of pixel to remove
|
-- This can be used to approximate the number of pixel to remove
|
||||||
local visible_item = data.visible_row_count - #data._internal.widgets + 1
|
local visible_item = data.visible_row_count - #data._internal.widgets + 1
|
||||||
|
|
||||||
if data._internal.orientation == "vertical" and h > max then
|
local orientation = "vertical"
|
||||||
|
|
||||||
|
if orientation == "vertical" and h > max then
|
||||||
local wdg_height = data.widget_fit_height_sum
|
local wdg_height = data.widget_fit_height_sum
|
||||||
--TODO this assume the widget size wont change
|
--TODO this assume the widget size wont change
|
||||||
-- data.item_height = math.ceil((data.item_height*max)/h) --OLD
|
-- data.item_height = math.ceil((data.item_height*max)/h) --OLD
|
||||||
|
@ -183,7 +65,7 @@ local function adapt_size(data,w,h,screen)
|
||||||
w = w + data.margins.left+data.margins.right
|
w = w + data.margins.left+data.margins.right
|
||||||
data.default_width = w
|
data.default_width = w
|
||||||
data._internal.private_data.width = w
|
data._internal.private_data.width = w
|
||||||
elseif data._internal.orientation == "horizontal" and w > max then
|
elseif orientation == "horizontal" and w > max then
|
||||||
--TODO merge this with above
|
--TODO merge this with above
|
||||||
local wdg_width = data.widget_fit_width_sum
|
local wdg_width = data.widget_fit_width_sum
|
||||||
data.item_width = math.ceil((data.item_height*max)/w)
|
data.item_width = math.ceil((data.item_height*max)/w)
|
||||||
|
@ -198,152 +80,50 @@ local function adapt_size(data,w,h,screen)
|
||||||
if data.icon_size and data.icon_size > w then
|
if data.icon_size and data.icon_size > w then
|
||||||
data.icon_size = w
|
data.icon_size = w
|
||||||
end
|
end
|
||||||
data._internal._geom_vals = nil
|
|
||||||
|
data._internal.margin:emit_signal("widget::layout_changed")
|
||||||
|
data._internal.margin:emit_signal("widget::redraw_needed")
|
||||||
|
|
||||||
return w == 0 and 1 or w, h == 0 and 1 or h
|
return w == 0 and 1 or w, h == 0 and 1 or h
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Create the auto hiding wibox
|
-- Create the main wibox (lazy-loading)
|
||||||
local function get_wibox(data, screen)
|
local function get_wibox(data, screen)
|
||||||
if data._internal.w then return data._internal.w end
|
if data._internal.w then return data._internal.w end
|
||||||
data:emit_signal("dock::request")
|
|
||||||
|
|
||||||
local dir,rotation = get_direction(data)
|
data._internal.margin = wibox.layout.margin(data._internal.layout)
|
||||||
local geo_src = data._internal._geom_vals or data
|
|
||||||
|
|
||||||
-- Need to be created befoce calling align_wibox
|
local w = smart_wibox(data._internal.margin, {
|
||||||
local m = wibox.layout.margin()
|
screen = screen ,
|
||||||
m:set_widget(data._internal.layout)
|
ontop = true ,
|
||||||
m:set_margins(0)
|
shape = beautiful.dock_shape or default_shape ,
|
||||||
data._internal.mrgns.widget = m
|
shape_border_width = 1 ,
|
||||||
|
shape_border_color = color(data.border_color or data.fg ),
|
||||||
|
bg = color(beautiful.bg_dock or beautiful.bg_normal),
|
||||||
|
})
|
||||||
|
|
||||||
-- Make sure the down will fit on the screen
|
|
||||||
geo_src.width,geo_src.height = adapt_size(data,geo_src.width,geo_src.height,screen)
|
|
||||||
|
|
||||||
local w = wibox{ screen = screen, width = geo_src.width, height = geo_src.height,ontop=true}
|
|
||||||
align_wibox(w,dir,screen)
|
|
||||||
|
|
||||||
w:set_widget(m)
|
|
||||||
data._internal.w = w
|
data._internal.w = w
|
||||||
|
|
||||||
-- Create the rounded corner mask
|
|
||||||
w:set_bg(cairo.Pattern.create_for_surface(mask(rotation,w.width,w.height,(beautiful.dock_corner_radius or default_radius)-2,1,0,color(beautiful.fg_normal),color(beautiful.bg_dock or beautiful.bg_normal))))
|
|
||||||
w.shape_bounding = mask(rotation,w.width,w.height,beautiful.dock_corner_radius or default_radius,0,1,color("#00000000"),color("#FFFFFFFF"))._native
|
|
||||||
local function prop_change()
|
|
||||||
w:set_bg(cairo.Pattern.create_for_surface(mask(rotation,w.width,w.height,(beautiful.dock_corner_radius or default_radius) -2,1,0,color(beautiful.fg_normal),color(beautiful.bg_dock or beautiful.bg_normal))))
|
|
||||||
w.shape_bounding = mask(rotation,w.width,w.height,beautiful.dock_corner_radius or default_radius,0,1,color("#00000000"),color("#FFFFFFFF"))._native
|
|
||||||
end
|
|
||||||
w:connect_signal("property::height",prop_change)
|
|
||||||
w:connect_signal("property::width" ,prop_change)
|
|
||||||
|
|
||||||
-- Hide the dock when the mouse leave
|
|
||||||
w:connect_signal("mouse::leave",function()
|
|
||||||
if not (data._tmp_menu and data._tmp_menu.visible) then
|
|
||||||
data.visible = false
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
data:emit_signal("visible::changed",true)
|
data:emit_signal("visible::changed",true)
|
||||||
|
|
||||||
-- Bring back the placeholder when hiding
|
w:connect_signal("property::height",function()
|
||||||
data:connect_signal("visible::changed",function(data,val)
|
adapt_size(data, w.width, w.height, 1)
|
||||||
if not val then
|
|
||||||
data._internal.placeholder.visible = true
|
|
||||||
end
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
placement.pin(w, placement.corner, "left", screen or 1)
|
||||||
|
|
||||||
return w
|
return w
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Create the "hidden" wibox that display the first one on command
|
|
||||||
local function create_placeholder(data)
|
|
||||||
local screen,dir = data.screen or get_first_screen() or 1,get_direction(data)
|
|
||||||
local h_or_w = (dir == "left" or dir == "right") and "width" or "height"
|
|
||||||
local hw_invert = h_or_w == "height" and "width" or "height"
|
|
||||||
local placeholder = wibox{ screen = screen, [h_or_w] = 1,[hw_invert] = 1,bg="#00000000", ontop = true,visible=true }
|
|
||||||
|
|
||||||
placeholder:geometry({ [h_or_w] = 1, [hw_invert] = capi.screen[screen].geometry.height -100, x = dir == "right" and capi.screen[screen].geometry.width -1 or 0, y = capi.screen[screen].geometry.y + 50})
|
|
||||||
|
|
||||||
|
|
||||||
-- Raise of create the main dock wibox
|
|
||||||
placeholder:connect_signal("mouse::enter", function()
|
|
||||||
get_wibox(data,screen).visible = true
|
|
||||||
placeholder.visible = false
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Move the placeholder when the wibox is resized
|
|
||||||
data:connect_signal(((dir == "left" or dir == "right") and "height" or "width").."::changed",function()
|
|
||||||
-- placeholder[hw_invert] = data[hw_invert]
|
|
||||||
align_wibox(placeholder,dir,screen)
|
|
||||||
end)
|
|
||||||
data._internal.placeholder = placeholder
|
|
||||||
|
|
||||||
-- Adapt the size when new items are added
|
|
||||||
data:connect_signal("layout_size",function(_,w,h)
|
|
||||||
if not data._internal._has_changed then
|
|
||||||
glib.idle_add(glib.PRIORITY_DEFAULT_IDLE, function()
|
|
||||||
if not data._internal._geom_vals then return end
|
|
||||||
local w,h,internal = data._internal._geom_vals.width,data._internal._geom_vals.height,data._internal
|
|
||||||
|
|
||||||
if h == 0 then
|
|
||||||
h = 1
|
|
||||||
end
|
|
||||||
if w == 0 then
|
|
||||||
w = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Resize the placeholder
|
|
||||||
internal.placeholder[hw_invert] = (hw_invert == "height") and h or w
|
|
||||||
align_wibox(internal.placeholder,dir,screen)
|
|
||||||
|
|
||||||
-- Resize the dock wibox
|
|
||||||
if internal.w then
|
|
||||||
w,h=adapt_size(data,w,h,screen) --TODO place holder need to do
|
|
||||||
internal.w.height = h
|
|
||||||
internal.w.width = w
|
|
||||||
align_wibox(internal.w,dir,screen)
|
|
||||||
end
|
|
||||||
|
|
||||||
data._internal._has_changed = false
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
data._internal._geom_vals = {height=h,width=w}
|
|
||||||
data._internal._has_changed = true
|
|
||||||
end)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
local function setup_drawable(data)
|
local function setup_drawable(data)
|
||||||
local internal = data._internal
|
local internal = data._internal
|
||||||
local private_data = internal.private_data
|
|
||||||
|
|
||||||
-- Create the layout
|
-- Create the layout
|
||||||
internal.layout = data.layout(data)
|
internal.layout = data.layout(data)
|
||||||
internal.layout.__draw = internal.layout.draw
|
|
||||||
internal.layout.draw = dock_draw
|
|
||||||
internal.layout.data = data
|
|
||||||
|
|
||||||
-- Getters
|
-- Getters
|
||||||
data.get_x = function() return 0 end
|
|
||||||
data.get_y = function() return 0 end
|
|
||||||
data.get_width = function()
|
|
||||||
return internal.w and internal.w.width or data._internal.layout:get_preferred_size({force_values=true})
|
|
||||||
end
|
|
||||||
data.get_height = function()
|
|
||||||
if internal.orientation == "horizontal" then
|
|
||||||
return beautiful.default_height
|
|
||||||
else
|
|
||||||
local w,h = internal.layout:get_preferred_size()
|
|
||||||
return h
|
|
||||||
end
|
|
||||||
end
|
|
||||||
data.get_visible = function() return true end
|
data.get_visible = function() return true end
|
||||||
data.get_direction = get_direction
|
data.get_margins = common.get_margins
|
||||||
|
|
||||||
local mrgns = margins2(nil,{})
|
|
||||||
data._internal.mrgns = mrgns
|
|
||||||
data.get_margins = function()
|
|
||||||
return data._internal.mrgns or {}
|
|
||||||
end
|
|
||||||
|
|
||||||
function data:set_visible(value)
|
function data:set_visible(value)
|
||||||
if internal.w then
|
if internal.w then
|
||||||
|
@ -351,32 +131,7 @@ local function setup_drawable(data)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- This widget do not use wibox, so setup correct widget interface
|
common.setup_item_move_events(data)
|
||||||
data.fit = internal.layout
|
|
||||||
data.draw = internal.layout
|
|
||||||
end
|
|
||||||
|
|
||||||
local function setup_item(data,item,args)
|
|
||||||
-- Add widgets
|
|
||||||
local f = (data._internal.layout.setup_item) or (vertical.setup_item)
|
|
||||||
f(data._internal.layout,data,item,args)
|
|
||||||
|
|
||||||
-- Buttons
|
|
||||||
local buttons = {}
|
|
||||||
for i=1,10 do
|
|
||||||
if args["button"..i] then
|
|
||||||
buttons[i] = args["button"..i]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
item:connect_signal("button::release",function(_m,_i,button_id,mods,geo)
|
|
||||||
if #mods == 0 and buttons[button_id] then
|
|
||||||
buttons[button_id](_m,_i,mods,geo)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Tooltip
|
|
||||||
item.widget:set_tooltip(item.tooltip)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function new(args)
|
local function new(args)
|
||||||
|
@ -387,10 +142,8 @@ local function new(args)
|
||||||
-- The the Radical arguments
|
-- The the Radical arguments
|
||||||
args.internal = args.internal or {}
|
args.internal = args.internal or {}
|
||||||
args.internal.orientation = orientation
|
args.internal.orientation = orientation
|
||||||
args.internal.get_direction = args.internal.get_direction or get_direction
|
|
||||||
args.internal.set_position = args.internal.set_position or set_position
|
|
||||||
args.internal.setup_drawable = args.internal.setup_drawable or setup_drawable
|
args.internal.setup_drawable = args.internal.setup_drawable or setup_drawable
|
||||||
args.internal.setup_item = args.internal.setup_item or setup_item
|
args.internal.setup_item = args.internal.setup_item or common.setup_item
|
||||||
args.item_style = args.item_style or item_style
|
args.item_style = args.item_style or item_style
|
||||||
args.bg = color("#00000000") --Use the dock bg instead
|
args.bg = color("#00000000") --Use the dock bg instead
|
||||||
args.item_height = 40
|
args.item_height = 40
|
||||||
|
@ -405,17 +158,23 @@ local function new(args)
|
||||||
|
|
||||||
-- Create the dock
|
-- Create the dock
|
||||||
local ret = base(args)
|
local ret = base(args)
|
||||||
ret.set_position = set_position
|
|
||||||
ret.get_position = get_position
|
|
||||||
ret.position = args.position or "left"
|
ret.position = args.position or "left"
|
||||||
ret.screen = args.screen
|
ret.screen = args.screen or 1
|
||||||
|
|
||||||
-- Add a 1px placeholder to trigger it
|
-- Add a 1px placeholder to trigger it
|
||||||
create_placeholder(ret)
|
if not beautiful.dock_always_show then
|
||||||
|
hot_corner.register_wibox(ret.position, function()
|
||||||
|
return get_wibox(ret, 1)
|
||||||
|
end, ret.screen, 1)
|
||||||
|
else
|
||||||
|
timer.delayed_call(function()
|
||||||
|
local w = get_wibox(ret, 1)
|
||||||
|
w.visible = true
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
return setmetatable(module, { __call = function(_, ...) return new(...) end })
|
return setmetatable(module, { __call = function(_, ...) return new(...) end })
|
||||||
-- kate: space-indent on; indent-width 2; replace-tabs on;
|
-- kate: space-indent on; indent-width 4; replace-tabs on;
|
||||||
|
|
46
embed.lua
46
embed.lua
|
@ -14,6 +14,7 @@ local button = require( "awful.button" )
|
||||||
local layout = require( "radical.layout" )
|
local layout = require( "radical.layout" )
|
||||||
local checkbox = require( "radical.widgets.checkbox" )
|
local checkbox = require( "radical.widgets.checkbox" )
|
||||||
local classic_style = require( "radical.style.classic" )
|
local classic_style = require( "radical.style.classic" )
|
||||||
|
local common = require( "radical.common" )
|
||||||
|
|
||||||
local capi,module = { mouse = mouse , screen = screen , keygrabber = keygrabber },{}
|
local capi,module = { mouse = mouse , screen = screen , keygrabber = keygrabber },{}
|
||||||
|
|
||||||
|
@ -26,14 +27,11 @@ local function setup_drawable(data)
|
||||||
data.set_visible = function(_,v) if data._embeded_parent then data._embeded_parent.visible = v end end
|
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
|
-- Enumate geometry --BUG this is fake, but better than nothing
|
||||||
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
|
if not data.layout then
|
||||||
data.layout = layout.vertical
|
data.layout = layout.vertical
|
||||||
end
|
end
|
||||||
internal.layout = data.layout(data)
|
internal.layout = data.layout(data)
|
||||||
data.width,data.height = data._internal.layout:fit()
|
|
||||||
data.margins={left=0,right=0,bottom=0,top=0}
|
data.margins={left=0,right=0,bottom=0,top=0}
|
||||||
internal.layout:connect_signal("mouse::enter",function(_,geo)
|
internal.layout:connect_signal("mouse::enter",function(_,geo)
|
||||||
if data._embeded_parent._current_item then
|
if data._embeded_parent._current_item then
|
||||||
|
@ -47,49 +45,11 @@ local function setup_drawable(data)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function setup_item(data,item,args)
|
|
||||||
|
|
||||||
-- Create the layout
|
|
||||||
local f = (data._internal.layout.setup_item) or (layout.vertical.setup_item)
|
|
||||||
f(data._internal.layout,data,item,args)
|
|
||||||
local buttons = {}
|
|
||||||
for i=1,10 do
|
|
||||||
if args["button"..i] then
|
|
||||||
buttons[i] = args["button"..i]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if not buttons[3] then --Hide on right click
|
|
||||||
buttons[3] = function()
|
|
||||||
data.visible = false
|
|
||||||
if data.parent_geometry and data.parent_geometry.is_menu then
|
|
||||||
data.parent_geometry.visible = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if not buttons[4] then
|
|
||||||
buttons[4] = function()
|
|
||||||
data:scroll_up()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if not buttons[5] then
|
|
||||||
buttons[5] = function()
|
|
||||||
data:scroll_down()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
item:connect_signal("button::release",function(_m,_i,button_id,mods,geo)
|
|
||||||
if #mods == 0 and buttons[button_id] then
|
|
||||||
buttons[button_id](_m,_i,mods,geo)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
local function new(args)
|
local function new(args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
args.internal = args.internal or {}
|
args.internal = args.internal or {}
|
||||||
args.internal.setup_drawable = args.internal.setup_drawable or setup_drawable
|
args.internal.setup_drawable = args.internal.setup_drawable or setup_drawable
|
||||||
args.internal.setup_item = args.internal.setup_item or setup_item
|
args.internal.setup_item = args.internal.setup_item or common.setup_item
|
||||||
args.style = args.style or classic_style
|
args.style = args.style or classic_style
|
||||||
local ret = base(args)
|
local ret = base(args)
|
||||||
ret:connect_signal("clear::menu",function(_,vis)
|
ret:connect_signal("clear::menu",function(_,vis)
|
||||||
|
|
|
@ -98,10 +98,6 @@ function module.screenshot(clients,geo)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if geo then
|
|
||||||
prev_menu.parent_geometry = geo
|
|
||||||
end
|
|
||||||
|
|
||||||
prev_menu.visible = true
|
prev_menu.visible = true
|
||||||
return prev_menu
|
return prev_menu
|
||||||
end
|
end
|
||||||
|
|
47
init.lua
47
init.lua
|
@ -11,11 +11,32 @@ local function set_tooltip(self, text, args)
|
||||||
self._tooltip = tooltip(self,text, args)
|
self._tooltip = tooltip(self,text, args)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function set_menu(self,menu,button)
|
--- Set a menu for widget "self".
|
||||||
|
-- This function is available for all widgets.
|
||||||
|
-- Any signals can be used as trigger, the common ones are:
|
||||||
|
--
|
||||||
|
-- * "button::press" (default) Left mouse button (normal click_
|
||||||
|
-- * "mouse::enter" When the mouse enter the widget
|
||||||
|
--
|
||||||
|
-- @param self A widget (implicit parameter)
|
||||||
|
-- @param menu A radical menu or a function returning one (for lazy-loading)
|
||||||
|
-- @tparam[opt="button1::pressed"] string event The event trigger for showing
|
||||||
|
-- the menu.
|
||||||
|
-- @tparam[opt=1] button_id The mouse button 1 (1= left, 3=right)
|
||||||
|
local function set_menu(self,menu, event, button_id)
|
||||||
if not menu then return end
|
if not menu then return end
|
||||||
local b = button or 1
|
local event = event or "button::pressed"
|
||||||
local current,bt = self:buttons(),aw_button({},b,function(geo)
|
local button_id = button_id or 1
|
||||||
|
|
||||||
|
|
||||||
|
local function trigger(_, geo)
|
||||||
|
local geo = geo or _
|
||||||
local m = menu
|
local m = menu
|
||||||
|
|
||||||
|
if self._data and self._data.is_menu then
|
||||||
|
geo.parent_menu = self._data
|
||||||
|
end
|
||||||
|
|
||||||
if type(menu) == "function" then
|
if type(menu) == "function" then
|
||||||
if self._tmp_menu and self._tmp_menu.visible then
|
if self._tmp_menu and self._tmp_menu.visible then
|
||||||
self._tmp_menu.visible = false
|
self._tmp_menu.visible = false
|
||||||
|
@ -26,22 +47,20 @@ local function set_menu(self,menu,button)
|
||||||
end
|
end
|
||||||
if not m then return end
|
if not m then return end
|
||||||
|
|
||||||
local dgeo = geo.drawable.drawable:geometry()
|
m.parent_geometry = geo
|
||||||
-- The geometry is a mix of the drawable and widget one
|
m._internal.w:move_by_parent(geo)
|
||||||
local geo2 = {
|
|
||||||
x = dgeo.x + geo.x,
|
|
||||||
y = dgeo.y + geo.y,
|
|
||||||
width = geo.width ,
|
|
||||||
height = geo.height ,
|
|
||||||
drawable = geo.drawable ,
|
|
||||||
}
|
|
||||||
|
|
||||||
m.parent_geometry = geo2
|
|
||||||
m.visible = not m.visible
|
m.visible = not m.visible
|
||||||
end)
|
end
|
||||||
|
|
||||||
|
if event == "button::pressed" then
|
||||||
|
local current,bt = self:buttons(),aw_button({},b,trigger)
|
||||||
for k, v in pairs(bt) do
|
for k, v in pairs(bt) do
|
||||||
current[type(k) == "number" and (#current+1) or k] = v
|
current[type(k) == "number" and (#current+1) or k] = v
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
self:connect_signal(event, trigger)
|
||||||
|
end
|
||||||
self._menu = menu
|
self._menu = menu
|
||||||
return bt
|
return bt
|
||||||
end
|
end
|
||||||
|
|
|
@ -66,20 +66,6 @@ local function load_async(tab,key)
|
||||||
return rawget(module,key)
|
return rawget(module,key)
|
||||||
end
|
end
|
||||||
|
|
||||||
function module.execute_sub_menu(data,item)
|
|
||||||
if (item._private_data.sub_menu_f or item._private_data.sub_menu_m) then
|
|
||||||
local sub_menu = item._private_data.sub_menu_m or item._private_data.sub_menu_f(data,item)
|
|
||||||
if sub_menu and (item._private_data.sub_menu_f or sub_menu.rowcount > 0) then
|
|
||||||
sub_menu.arrow_type = module.arrow_type.NONE
|
|
||||||
sub_menu.parent_item = item
|
|
||||||
sub_menu.parent_geometry = data
|
|
||||||
sub_menu.visible = true
|
|
||||||
item._tmp_menu = sub_menu
|
|
||||||
data._tmp_menu = sub_menu
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function hide_sub_menu(item,data)
|
local function hide_sub_menu(item,data)
|
||||||
if item._tmp_menu then
|
if item._tmp_menu then
|
||||||
item._tmp_menu.visible = false
|
item._tmp_menu.visible = false
|
||||||
|
@ -212,15 +198,18 @@ local function new_item(data,args)
|
||||||
item.state[module.item_flags.SELECTED] = nil
|
item.state[module.item_flags.SELECTED] = nil
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Select the new one
|
|
||||||
if data.sub_menu_on == module.event.SELECTED and (current_item ~= item or not item._tmp_menu)then
|
|
||||||
module.execute_sub_menu(data,item)
|
|
||||||
end
|
|
||||||
item.state[module.item_flags.SELECTED] = true
|
item.state[module.item_flags.SELECTED] = true
|
||||||
data._current_item = item
|
data._current_item = item
|
||||||
end
|
end
|
||||||
|
|
||||||
|
item.set_icon = function (_,value)
|
||||||
|
local icon_w = item._internal.icon_w
|
||||||
|
|
||||||
|
if not icon_w then return end
|
||||||
|
|
||||||
|
icon_w:set_image(value)
|
||||||
|
end
|
||||||
|
|
||||||
-- Listen to signals
|
-- Listen to signals
|
||||||
item:connect_signal("state::changed",function()
|
item:connect_signal("state::changed",function()
|
||||||
item:style()
|
item:style()
|
||||||
|
|
|
@ -1,7 +1,33 @@
|
||||||
local holo = require("radical.item.style.holo")
|
local holo = require("radical.item.style.holo")
|
||||||
local rounded = require("radical.item.style.rounded" )
|
local rounded = require("radical.item.style.rounded" )
|
||||||
|
local theme = require( "radical.theme" )
|
||||||
|
local unpack = unpack or table.unpack
|
||||||
|
|
||||||
return {
|
-- Create a generic item_style
|
||||||
|
local function generic(_, args)
|
||||||
|
local args = args or {}
|
||||||
|
|
||||||
|
args.margins = args.margins or {
|
||||||
|
TOP = 0,
|
||||||
|
BOTTOM = 0,
|
||||||
|
RIGHT = 0,
|
||||||
|
LEFT = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
local module = {
|
||||||
|
margins = args.margins
|
||||||
|
}
|
||||||
|
|
||||||
|
local function draw(item)
|
||||||
|
item.widget:set_shape(args.shape, unpack(args.shape_args or {}))
|
||||||
|
item.widget:set_shape_border_width(item.border_width)
|
||||||
|
theme.update_colors(item)
|
||||||
|
end
|
||||||
|
|
||||||
|
return setmetatable(module, { __call = function(_, ...) return draw(...) end })
|
||||||
|
end
|
||||||
|
|
||||||
|
return setmetatable({
|
||||||
basic = require("radical.item.style.basic" ),
|
basic = require("radical.item.style.basic" ),
|
||||||
classic = require("radical.item.style.classic" ),
|
classic = require("radical.item.style.classic" ),
|
||||||
subtle = require("radical.item.style.subtle" ),
|
subtle = require("radical.item.style.subtle" ),
|
||||||
|
@ -15,4 +41,4 @@ return {
|
||||||
arrow_3d = require("radical.item.style.arrow_3d" ),
|
arrow_3d = require("radical.item.style.arrow_3d" ),
|
||||||
slice_prefix = require("radical.item.style.slice_prefix" ),
|
slice_prefix = require("radical.item.style.slice_prefix" ),
|
||||||
line_3d = require("radical.item.style.line_3d" ),
|
line_3d = require("radical.item.style.line_3d" ),
|
||||||
}
|
}, {__call=generic})
|
||||||
|
|
|
@ -5,101 +5,13 @@ local util = require( "awful.util" )
|
||||||
local button = require( "awful.button" )
|
local button = require( "awful.button" )
|
||||||
local checkbox = require( "radical.widgets.checkbox" )
|
local checkbox = require( "radical.widgets.checkbox" )
|
||||||
local wibox = require( "wibox" )
|
local wibox = require( "wibox" )
|
||||||
|
local common = require( "radical.common" )
|
||||||
local item_layout = require("radical.item.layout.icon")
|
local item_layout = require("radical.item.layout.icon")
|
||||||
local base = nil
|
|
||||||
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
local function left(data)
|
|
||||||
if data._current_item._tmp_menu then
|
|
||||||
data = data._current_item._tmp_menu
|
|
||||||
data.items.selected = true
|
|
||||||
return true,data
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function right(data)
|
|
||||||
if data.parent_geometry.is_menu then
|
|
||||||
for k,v in ipairs(data.items) do
|
|
||||||
if v._tmp_menu == data or v.sub_menu_m == data then
|
|
||||||
v.selected = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
data.visible = false
|
|
||||||
data = data.parent_geometry
|
|
||||||
return true,data
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function up(data)
|
|
||||||
data.previous_item.selected = true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function down(data)
|
|
||||||
data.next_item.selected = true
|
|
||||||
end
|
|
||||||
|
|
||||||
function module:setup_key_hooks(data)
|
|
||||||
data:add_key_hook({}, "Up" , "press", up )
|
|
||||||
data:add_key_hook({}, "&" , "press", up )
|
|
||||||
data:add_key_hook({}, "Down" , "press", down )
|
|
||||||
data:add_key_hook({}, "KP_Enter", "press", down )
|
|
||||||
data:add_key_hook({}, "Left" , "press", left )
|
|
||||||
data:add_key_hook({}, "\"" , "press", left )
|
|
||||||
data:add_key_hook({}, "Right" , "press", right )
|
|
||||||
data:add_key_hook({}, "#" , "press", right )
|
|
||||||
end
|
|
||||||
|
|
||||||
local function setup_event(data,item,args)
|
|
||||||
--Event handling
|
|
||||||
if data.select_on == base.event.HOVER then
|
|
||||||
item.widget:connect_signal("mouse::enter", function() item.selected = true end)
|
|
||||||
item.widget:connect_signal("mouse::leave", function() item.selected = false end)
|
|
||||||
end
|
|
||||||
data._internal.layout:add(item)
|
|
||||||
local buttons = {}
|
|
||||||
for i=1,10 do
|
|
||||||
if args["button"..i] then
|
|
||||||
buttons[#buttons+1] = button({},i,args["button"..i])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if not buttons[3] then --Hide on right click
|
|
||||||
buttons[#buttons+1] = button({},3,function()
|
|
||||||
data.visible = false
|
|
||||||
if data.parent_geometry and data.parent_geometry.is_menu then
|
|
||||||
data.parent_geometry.visible = false
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
--Be sure to always hide sub menus, even when data.visible is set manually
|
|
||||||
data:connect_signal("visible::changed",function(_,vis)
|
|
||||||
if data._tmp_menu and data.visible == false then
|
|
||||||
data._tmp_menu.visible = false
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
data:connect_signal("parent_geometry::changed",function(_,vis)
|
|
||||||
local fit_w,fit_h = data._internal.layout:fit()
|
|
||||||
data.height = fit_h
|
|
||||||
if data.style then
|
|
||||||
data.style(data)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
item.widget:buttons( util.table.join(unpack(buttons)))
|
|
||||||
end
|
|
||||||
|
|
||||||
function module:setup_item(data,item,args)
|
function module:setup_item(data,item,args)
|
||||||
local bg = item_layout(item,data,args)
|
|
||||||
|
|
||||||
-- Set size
|
|
||||||
local fit_w,fit_h = data._internal.layout:fit()
|
|
||||||
data.width = fit_w
|
|
||||||
data.height = fit_h
|
|
||||||
if data.style then
|
|
||||||
data.style(data)
|
|
||||||
end
|
|
||||||
local text_w = item._internal.text_w
|
local text_w = item._internal.text_w
|
||||||
local icon_w = item._internal.icon_w
|
|
||||||
|
|
||||||
-- Setup text
|
-- Setup text
|
||||||
item.set_text = function (_,value)
|
item.set_text = function (_,value)
|
||||||
|
@ -118,50 +30,29 @@ function module:setup_item(data,item,args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
item.set_icon = function (_,value)
|
|
||||||
icon_w:set_image(value)
|
|
||||||
end
|
|
||||||
item:set_text(item._private_data.text)
|
item:set_text(item._private_data.text)
|
||||||
|
|
||||||
-- Setup tooltip
|
|
||||||
bg:set_tooltip(item.tooltip)
|
|
||||||
|
|
||||||
-- Set widget
|
|
||||||
item.widget = bg
|
|
||||||
data.item_style(item,{})
|
|
||||||
setup_event(data,item,args)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--Get preferred item geometry
|
--Get preferred item geometry
|
||||||
local function item_fit(data,item,self, content, width, height)
|
local function item_fit(data,item,self, content, width, height)
|
||||||
if not data.visible then return 1,1 end
|
if not data.visible then return 1,1 end
|
||||||
local w, h = item._private_data._fit(self,content,width,height) --TODO port to new context API
|
local w, h = item._private_data._fit(self,content,width,height) --TODO port to new context API
|
||||||
return data.item_width or 70, item._private_data.height or h
|
return data.item_width or 70, item._private_data.height or h --TODO broken
|
||||||
end
|
end
|
||||||
|
|
||||||
local function new(data)
|
local function new(data)
|
||||||
if not base then
|
|
||||||
base = require( "radical.base" )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Define the item layout
|
-- Define the item layout
|
||||||
local real_l = wibox.widget.base.make_widget_declarative {
|
local real_l = wibox.widget.base.make_widget_declarative {
|
||||||
spacing = data.spacing ,
|
spacing = data.spacing ,
|
||||||
item_fit = item_fit ,
|
item_fit = item_fit ,
|
||||||
setup_key_hooks = module.setup_key_hooks ,
|
setup_key_hooks = common.setup_key_hooks ,
|
||||||
setup_item = module.setup_item ,
|
setup_item = module.setup_item ,
|
||||||
layout = wibox.layout.fixed.horizontal,
|
layout = wibox.layout.fixed.horizontal,
|
||||||
}
|
}
|
||||||
|
|
||||||
data:connect_signal("widget::added",function(_,item,widget)
|
|
||||||
wibox.layout.fixed.add(real_l, item.widget)
|
|
||||||
real_l:emit_signal("widget::updated")
|
|
||||||
end)
|
|
||||||
|
|
||||||
function real_l:add(item)
|
|
||||||
return wibox.layout.fixed.add(self, item.widget)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Hack fit
|
-- Hack fit
|
||||||
local new_fit
|
local new_fit
|
||||||
new_fit = function(self,context,w,h,force_values) --TODO use the context instead of extra argument
|
new_fit = function(self,context,w,h,force_values) --TODO use the context instead of extra argument
|
||||||
|
|
|
@ -4,66 +4,24 @@ local scroll = require( "radical.widgets.scroll" )
|
||||||
local filter = require( "radical.widgets.filter" )
|
local filter = require( "radical.widgets.filter" )
|
||||||
local wibox = require( "wibox" )
|
local wibox = require( "wibox" )
|
||||||
local cairo = require( "lgi" ).cairo
|
local cairo = require( "lgi" ).cairo
|
||||||
local base = nil
|
local common = require( "radical.common" )
|
||||||
local horizontal_item_layout= require( "radical.item.layout.horizontal" )
|
local horizontal_item_layout= require( "radical.item.layout.horizontal" )
|
||||||
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
local function left(data)
|
|
||||||
if data._current_item._tmp_menu then
|
|
||||||
data = data._current_item._tmp_menu
|
|
||||||
data.items[1].selected = true
|
|
||||||
return true,data
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function right(data)
|
|
||||||
if data.parent_geometry and data.parent_geometry.is_menu then
|
|
||||||
for k,v in ipairs(data.items) do
|
|
||||||
if v._tmp_menu == data or v.sub_menu_m == data then
|
|
||||||
v.selected = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
data.visible = false
|
|
||||||
data = data.parent_geometry
|
|
||||||
return true,data
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function up(data)
|
|
||||||
data.previous_item.selected = true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function down(data)
|
|
||||||
data.next_item.selected = true
|
|
||||||
end
|
|
||||||
|
|
||||||
function module:setup_key_hooks(data)
|
|
||||||
data:add_key_hook({}, "Up" , "press", up )
|
|
||||||
data:add_key_hook({}, "&" , "press", up ) -- Xephyr bug
|
|
||||||
data:add_key_hook({}, "Down" , "press", down )
|
|
||||||
data:add_key_hook({}, "KP_Enter", "press", down ) -- Xephyr bug
|
|
||||||
data:add_key_hook({}, "Left" , "press", right )
|
|
||||||
data:add_key_hook({}, "\"" , "press", right ) -- Xephyr bug
|
|
||||||
data:add_key_hook({}, "Right" , "press", left )
|
|
||||||
data:add_key_hook({}, "#" , "press", left ) -- Xephyr bug
|
|
||||||
end
|
|
||||||
|
|
||||||
--Get preferred item geometry
|
--Get preferred item geometry
|
||||||
local function item_fit(data,item,self,context, width,height)
|
local function item_fit(data,item,self,context, width,height)
|
||||||
local w, h = 0,0--item._internal.cache_w or 1,item._internal.cache_h or 1
|
local w, h = 0,0--item._internal.cache_w or 1,item._internal.cache_h or 1
|
||||||
if data.visible then
|
if data.visible then
|
||||||
w, h = item._private_data._fit({},self,context,width,height)
|
w, h = item._private_data._fit({},self,context,width,height)
|
||||||
item._internal.pix_cache = {} --Clear the pimap cache
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return w, item.height or h
|
return w, item.height or h
|
||||||
end
|
end
|
||||||
|
|
||||||
function module:setup_text(item,data,text_w)
|
function module.setup_text(item,data,text_w)
|
||||||
local text_w = item._internal.text_w
|
local text_w = item._internal.text_w
|
||||||
|
if not text_w then return end
|
||||||
|
|
||||||
text_w.draw = function(self,context, cr, width, height)
|
text_w.draw = function(self,context, cr, width, height)
|
||||||
if item.underlay then
|
if item.underlay then
|
||||||
|
@ -81,86 +39,29 @@ function module:setup_text(item,data,text_w)
|
||||||
end
|
end
|
||||||
item._private_data.text = value
|
item._private_data.text = value
|
||||||
end
|
end
|
||||||
|
|
||||||
item:set_text(item._private_data.text)
|
item:set_text(item._private_data.text)
|
||||||
|
|
||||||
return text_w
|
return text_w
|
||||||
end
|
end
|
||||||
|
|
||||||
function module:setup_item(data,item,args)
|
function module:setup_item(data,item,args)
|
||||||
if not base then
|
|
||||||
base = require( "radical.base" )
|
|
||||||
end
|
|
||||||
--Create the background
|
|
||||||
local item_layout = item.layout or data.item_layout or horizontal_item_layout
|
|
||||||
item.widget = item_layout(item,data,args)
|
|
||||||
|
|
||||||
--Event handling
|
|
||||||
if data.select_on == base.event.HOVER then
|
|
||||||
item.widget:connect_signal("mouse::enter", function(_,geo)
|
|
||||||
item.y = geo.y
|
|
||||||
item.selected = true
|
|
||||||
end)
|
|
||||||
item.widget:connect_signal("mouse::leave", function()
|
|
||||||
item.selected = false
|
|
||||||
end)
|
|
||||||
else
|
|
||||||
item.widget:connect_signal("mouse::enter", function(_,geo)
|
|
||||||
item.y = geo.y
|
|
||||||
item.hover = true
|
|
||||||
end)
|
|
||||||
item.widget:connect_signal("mouse::leave", function()
|
|
||||||
item.hover = false
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
data._internal.layout:add(item)
|
|
||||||
|
|
||||||
--Be sure to always hide sub menus, even when data.visible is set manually
|
|
||||||
data:connect_signal("visible::changed",function(_,vis)
|
|
||||||
if data._tmp_menu and data.visible == false then
|
|
||||||
data._tmp_menu.visible = false
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
data:connect_signal("parent_geometry::changed",function(_,vis)
|
|
||||||
local fit_w,fit_h = data._internal.layout:fit()
|
|
||||||
data.height = fit_h
|
|
||||||
data.style(data)
|
|
||||||
end)
|
|
||||||
|
|
||||||
item._private_data._fit = wibox.widget.background.fit
|
item._private_data._fit = wibox.widget.background.fit
|
||||||
if item._internal.margin_w then
|
if item._internal.margin_w then
|
||||||
item._internal.margin_w.fit = function(...)
|
item._internal.margin_w.fit = function(...)
|
||||||
if (item.visible == false or item._filter_out == true or item._hidden == true) then
|
if (item.visible == false or item._filter_out == true or item._hidden == true) then
|
||||||
return 0,0
|
return 0,0
|
||||||
end
|
end
|
||||||
return data._internal.layout.item_fit(data,item,...)
|
return item_fit(data,item,...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Text need to take as much space as possible, override default
|
-- Text need to take as much space as possible, override default
|
||||||
module:setup_text(item,data)
|
module.setup_text(item,data)
|
||||||
|
|
||||||
-- Necessary for :set_position()
|
|
||||||
local fit_w,fit_h = data._internal.layout:fit()
|
|
||||||
|
|
||||||
data.width = fit_w
|
|
||||||
data.height = fit_h
|
|
||||||
|
|
||||||
-- Enable scrollbar if necessary
|
|
||||||
if data._internal.scroll_w and data.rowcount > data.max_items then
|
|
||||||
data._internal.scroll_w.visible = true
|
|
||||||
data._internal.scroll_w["up"]:emit_signal("widget::updated")
|
|
||||||
data._internal.scroll_w["down"]:emit_signal("widget::updated")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Setup tooltip
|
|
||||||
item.widget:set_tooltip(item.tooltip)
|
|
||||||
|
|
||||||
-- Apply item style
|
|
||||||
local item_style = item.item_style or data.item_style
|
|
||||||
item_style(item,{})
|
|
||||||
|
|
||||||
-- Compute the minimum width
|
-- Compute the minimum width
|
||||||
if data.auto_resize and item._internal.margin_w then
|
if data.auto_resize and item._internal.margin_w then
|
||||||
local fit_w = wibox.layout.margin.fit(item._internal.margin_w,{},9999,9999)
|
local fit_w = wibox.layout.margin.fit(item._internal.margin_w,{dpi=96},9999,9999)
|
||||||
local is_largest = item == data._internal.largest_item_w
|
local is_largest = item == data._internal.largest_item_w
|
||||||
if fit_w < 1000 and (not data._internal.largest_item_w_v or data._internal.largest_item_w_v < fit_w) then
|
if fit_w < 1000 and (not data._internal.largest_item_w_v or data._internal.largest_item_w_v < fit_w) then
|
||||||
data._internal.largest_item_w = item
|
data._internal.largest_item_w = item
|
||||||
|
@ -168,7 +69,6 @@ function module:setup_item(data,item,args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
item.widget:emit_signal("widget::updated")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function compute_geo(data,width,height,force_values)
|
local function compute_geo(data,width,height,force_values)
|
||||||
|
@ -191,7 +91,6 @@ local function compute_geo(data,width,height,force_values)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function new(data)
|
local function new(data)
|
||||||
base = base or require( "radical.base" )
|
|
||||||
|
|
||||||
local function real_fit(self,context,o_w,o_h,force_values)
|
local function real_fit(self,context,o_w,o_h,force_values)
|
||||||
if not data.visible then return 1,1 end
|
if not data.visible then return 1,1 end
|
||||||
|
@ -200,10 +99,6 @@ local function new(data)
|
||||||
return w,h
|
return w,h
|
||||||
end
|
end
|
||||||
|
|
||||||
local function real_add(self, item)
|
|
||||||
return wibox.layout.fixed.add(data._internal.content_layout, item.widget)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Create the scroll widgets
|
-- Create the scroll widgets
|
||||||
if data.max_items then
|
if data.max_items then
|
||||||
data._internal.scroll_w = scroll(data)
|
data._internal.scroll_w = scroll(data)
|
||||||
|
@ -250,7 +145,7 @@ local function new(data)
|
||||||
|
|
||||||
-- Methods
|
-- Methods
|
||||||
item_fit = item_fit ,
|
item_fit = item_fit ,
|
||||||
setup_key_hooks = module.setup_key_hooks,
|
setup_key_hooks = common.setup_key_hooks,
|
||||||
setup_item = module.setup_item ,
|
setup_item = module.setup_item ,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,46 +157,9 @@ local function new(data)
|
||||||
|
|
||||||
-- Set the overloaded methods
|
-- Set the overloaded methods
|
||||||
real_l.fit = real_fit
|
real_l.fit = real_fit
|
||||||
real_l.add = real_add
|
|
||||||
|
|
||||||
local l = data._internal.content_layout
|
local l = data._internal.content_layout
|
||||||
|
|
||||||
--SWAP / MOVE / REMOVE
|
|
||||||
data:connect_signal("item::swapped",function(_,item1,item2,index1,index2)
|
|
||||||
l:swap(index1, index2)
|
|
||||||
end)
|
|
||||||
|
|
||||||
data:connect_signal("item::moved",function(_,item,new_idx,old_idx)
|
|
||||||
local w = l:get_children()[old_idx]
|
|
||||||
l:remove(old_idx)
|
|
||||||
l:insert(new_idx, w)
|
|
||||||
end)
|
|
||||||
|
|
||||||
data:connect_signal("item::removed",function(_,item,old_idx)
|
|
||||||
l:remove(old_idx)
|
|
||||||
end)
|
|
||||||
|
|
||||||
data:connect_signal("item::appended",function(_,item)
|
|
||||||
l:add(item.widget)
|
|
||||||
end)
|
|
||||||
|
|
||||||
data:connect_signal("widget::added",function(_,item,widget)
|
|
||||||
wibox.layout.fixed.add(l,item.widget)
|
|
||||||
l:emit_signal("widget::updated")
|
|
||||||
end)
|
|
||||||
|
|
||||||
data:connect_signal("prefix_widget::added",function(_,widget,args)
|
|
||||||
data._internal.pref_l:insert(1,widget)
|
|
||||||
end)
|
|
||||||
|
|
||||||
data:connect_signal("suffix_widget::added",function(_,widget,args)
|
|
||||||
data._internal.suf_l:add(widget)
|
|
||||||
end)
|
|
||||||
|
|
||||||
data._internal.text_fit = function(self, context, width, height)
|
|
||||||
return width,height
|
|
||||||
end
|
|
||||||
|
|
||||||
return real_l
|
return real_l
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
196
style/arrow.lua
196
style/arrow.lua
|
@ -1,10 +1,9 @@
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
local unpack = unpack or table.unpack
|
||||||
local beautiful = require( "beautiful" )
|
local beautiful = require( "beautiful" )
|
||||||
local color = require( "gears.color" )
|
local color = require( "gears.color" )
|
||||||
local surface = require( "gears.surface" )
|
|
||||||
local cairo = require( "lgi" ).cairo
|
local cairo = require( "lgi" ).cairo
|
||||||
local base = require( "radical.base" )
|
local base = require( "radical.base" )
|
||||||
local glib = require("lgi").GLib
|
|
||||||
local shape = require( "gears.shape" )
|
local shape = require( "gears.shape" )
|
||||||
|
|
||||||
local module = {
|
local module = {
|
||||||
|
@ -16,16 +15,12 @@ local module = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Constants
|
|
||||||
local radius = 10
|
|
||||||
local arrow_height = 13
|
|
||||||
|
|
||||||
-- Matrix rotation per direction
|
-- Matrix rotation per direction
|
||||||
local angles = {
|
local angles = {
|
||||||
top = 0 , -- 0
|
top = math.pi , -- 180
|
||||||
bottom = math.pi , -- 180
|
bottom = 0 , -- 0
|
||||||
left = 3*math.pi/2 , -- 270
|
left = math.pi/2 , -- 90
|
||||||
right = math.pi/2 , -- 90
|
right = 3*math.pi/2 , -- 270
|
||||||
}
|
}
|
||||||
|
|
||||||
-- If width and height need to be swapped
|
-- If width and height need to be swapped
|
||||||
|
@ -36,11 +31,21 @@ local swaps = {
|
||||||
left = true ,
|
left = true ,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local invert = {
|
||||||
|
top = "bottom",
|
||||||
|
bottom = "top" ,
|
||||||
|
right = "left" , --FIXME this is wrong
|
||||||
|
left = "right" , --FIXME this is wrong
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Constants
|
||||||
|
local radius = 10
|
||||||
|
local arrow_height = 13
|
||||||
|
|
||||||
-- Generate the arrow position
|
-- Generate the arrow position
|
||||||
local function gen_arrow_x(data,direction)
|
local function gen_arrow_x(data,direction, width, height)
|
||||||
local at = data.arrow_type
|
local at = data.arrow_type
|
||||||
local par_center_x = data.parent_geometry and (data.parent_geometry.x + data.parent_geometry.width/2) or -1
|
local par_center_x = data.wibox.width/2
|
||||||
local menu_beg_x = data.x
|
|
||||||
|
|
||||||
if at == base.arrow_type.PRETTY or not at then
|
if at == base.arrow_type.PRETTY or not at then
|
||||||
if direction == "left" then
|
if direction == "left" then
|
||||||
|
@ -48,147 +53,88 @@ local function gen_arrow_x(data,direction)
|
||||||
elseif direction == "right" then
|
elseif direction == "right" then
|
||||||
--TODO
|
--TODO
|
||||||
elseif direction == "bottom" then
|
elseif direction == "bottom" then
|
||||||
data._arrow_x = data.width -20 - (data.arrow_x_orig or 20)
|
data._arrow_x = width -20 - (data.arrow_x_orig or 20)
|
||||||
if par_center_x >= menu_beg_x then
|
if par_center_x >= 0 then
|
||||||
data._arrow_x = data.width - (par_center_x - menu_beg_x) - arrow_height
|
data._arrow_x = width - (par_center_x - 0) - arrow_height
|
||||||
end
|
end
|
||||||
elseif direction == "top" then
|
elseif direction == "top" then
|
||||||
--TODO
|
--TODO
|
||||||
end
|
end
|
||||||
elseif at == base.arrow_type.CENTERED then
|
elseif at == base.arrow_type.CENTERED then
|
||||||
if direction == "left" or direction == "right" then
|
if direction == "left" or direction == "right" then
|
||||||
data._arrow_x = data.height/2 - arrow_height
|
data._arrow_x = height/2 - arrow_height
|
||||||
else
|
else
|
||||||
data._arrow_x = data.width/2 - arrow_height
|
data._arrow_x = width/2 - arrow_height
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function update_margins(data, pos)
|
||||||
|
-- Set the margins correctly
|
||||||
|
if data._internal.margin then
|
||||||
|
data.margins.left = module.margins.LEFT
|
||||||
|
data.margins.right = module.margins.RIGHT
|
||||||
|
data.margins.top = module.margins.TOP
|
||||||
|
data.margins.bottom = module.margins.BOTTOM
|
||||||
|
|
||||||
|
-- Add enough room for the arrow
|
||||||
|
if pos and data.arrow_type ~= base.arrow_type.NONE then
|
||||||
|
data.margins[invert[pos]] = data.margins[invert[pos]] + arrow_height
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Generate a rounded cairo path with the arrow
|
-- Generate a rounded cairo path with the arrow
|
||||||
local function draw_roundedrect_path(cr, width, height, radius, data, padding, angle, swap_size)
|
local function draw_roundedrect_path(cr, width, height, radius, data, position)
|
||||||
local no_arrow = data.arrow_type == base.arrow_type.NONE
|
if data.arrow_type == base.arrow_type.NONE then
|
||||||
local padding = padding or 0
|
return shape.rounded_rect(cr, width, height, radius)
|
||||||
local arrow_offset = no_arrow and 0 or padding/2
|
end
|
||||||
local width, height = width - 2*padding - (swap_size and arrow_offset or 0), height - 2*padding - (swap_size and 0 or arrow_offset)
|
|
||||||
|
|
||||||
if swap_size then
|
local angle, swap = angles[position], swaps[position]
|
||||||
width, height = height - arrow_offset, width
|
|
||||||
|
-- Invert width and height to avoid distortion
|
||||||
|
if swap then
|
||||||
|
width, height = height, width
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Use rounded rext for sub-menu and
|
-- Use rounded rext for sub-menu and
|
||||||
local s = shape.transform(no_arrow and shape.rounded_rect or shape.infobubble)
|
local s = shape.transform(shape.infobubble)
|
||||||
|
|
||||||
-- Apply transformations
|
-- Apply transformations
|
||||||
s = s : rotate_at(width / 2, height / 2, angle)
|
s = s : rotate_at(width / 2, height / 2, angle)
|
||||||
if padding > 0 then
|
|
||||||
s = s : translate(padding + (swap_size and arrow_offset or 0), padding + (angle == 0 and arrow_offset or 0))
|
-- Decide where the arrow will be
|
||||||
|
gen_arrow_x(data, data.direction, width, height)
|
||||||
|
|
||||||
|
-- Forward to the real shape
|
||||||
|
local ax = swap and width - (data._arrow_x or 20) or (data._arrow_x or 20)
|
||||||
|
s(cr, width, height, radius, arrow_height, ax)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Avoid a race condition
|
|
||||||
if (not data._arrow_x) and (not no_arrow) then
|
|
||||||
gen_arrow_x(data, data.direction)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- the (swap_size and 2 or 1) indicate a bug elsewhere
|
|
||||||
s(cr, width, height, radius, arrow_height - arrow_offset, (data._arrow_x or 20) - arrow_offset*(swap_size and 2 or 1))
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
local function _set_direction(data,direction)
|
|
||||||
local hash = data.height*1000 + data.width
|
|
||||||
|
|
||||||
-- Try not to waste time for nothing
|
|
||||||
if data._internal._last_direction == direction..(hash) then return end
|
|
||||||
|
|
||||||
-- Avoid recomputing the arrow_x value
|
|
||||||
if not data._arrow_x or data._internal.last_size ~= hash then
|
|
||||||
gen_arrow_x(data,direction)
|
|
||||||
data._internal.last_size = hash
|
|
||||||
end
|
|
||||||
|
|
||||||
local angle, swap = angles[direction],swaps[direction]
|
|
||||||
|
|
||||||
data._internal._need_direction_reload = false
|
|
||||||
data._internal._last_direction = direction..(hash)
|
|
||||||
|
|
||||||
surface.apply_shape_bounding(data.wibox, draw_roundedrect_path, radius, data, 0, angle, swap)
|
|
||||||
-- surface.apply_shape_clip (data.wibox, draw_roundedrect_path, radius, data, data.border_width, angle, swap)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Try to avoid useless repaint, this function is heavy
|
|
||||||
local function set_direction(data,direction)
|
|
||||||
data._internal._need_direction = direction
|
|
||||||
if not data._internal._need_direction_reload and data._internal._last_direction ~= direction..(data.height*1000+data.width) then
|
|
||||||
glib.idle_add(glib.PRIORITY_HIGH_IDLE, function() _set_direction(data,data._internal._need_direction) end)
|
|
||||||
data._internal._need_direction_reload = true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Margins need to set manually, a reset will override user changes
|
|
||||||
if data.arrow_type ~= base.arrow_type.NONE and (not (data.parent_geometry and data.parent_geometry.is_menu)) and data._internal.former_direction ~= direction then
|
|
||||||
if data._internal.former_direction then
|
|
||||||
data.margins[data._internal.former_direction] = data.border_width + module.margins[data._internal.former_direction:upper()]
|
|
||||||
end
|
|
||||||
data.margins[direction] = arrow_height + 2*data.border_width
|
|
||||||
end
|
|
||||||
data._internal.former_direction = direction
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_arrow_x(data)
|
|
||||||
local height,width = data.height,data.width
|
|
||||||
local hash = height*1000+width
|
|
||||||
if not data._arrow_x or data._internal.last_size ~= hash then
|
|
||||||
gen_arrow_x(data,direction)
|
|
||||||
data._internal.last_size = hash
|
|
||||||
end
|
|
||||||
return data._arrow_x
|
|
||||||
end
|
|
||||||
|
|
||||||
-- As the menus have a rounded border, rectangle elements will draw over the
|
|
||||||
-- corner border. To fix this, this method re-draw the border on top of the
|
|
||||||
-- content
|
|
||||||
local function after_draw_children(self, context, cr, width, height)
|
|
||||||
local data = self._data
|
|
||||||
|
|
||||||
local dir = data.direction
|
|
||||||
local angle, swap = angles[dir], swaps[dir]
|
|
||||||
|
|
||||||
cr:translate(data.border_width/2,data.border_width/2)
|
|
||||||
|
|
||||||
-- Generate the path
|
|
||||||
draw_roundedrect_path(cr, width, height, beautiful.menu_corner_radius or radius, data, data.border_width/2, angle, swap)
|
|
||||||
cr:set_source(color(beautiful.menu_outline_color or beautiful.menu_border_color or beautiful.fg_normal))
|
|
||||||
cr:set_line_width(data.border_width)
|
|
||||||
cr:stroke()
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function draw(data,args)
|
local function draw(data,args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
local direction = data.direction or "top"
|
|
||||||
if not data.get_arrow_x then
|
|
||||||
rawset(data,"arrow_x_orig",data.arrow_x)
|
|
||||||
rawset(data,"arrow_x_orig",nil)
|
|
||||||
data.get_arrow_x = get_arrow_x
|
|
||||||
-- Prevent sharp corners from being over the border
|
|
||||||
if data._internal.margin then
|
|
||||||
data._internal.margin.__draw = data._internal.margin.draw
|
|
||||||
|
|
||||||
--TODO eventually restart work on upstreaming this, for now it pull too
|
if not data._internal.arrow_setup then
|
||||||
-- much trouble along with it
|
data._internal.w:set_shape_border_width(data.border_width or 1)
|
||||||
data._internal.margin._data = data
|
data._internal.w:set_shape_border_color(color(beautiful.menu_outline_color or beautiful.menu_border_color or beautiful.fg_normal))
|
||||||
data._internal.margin.after_draw_children = after_draw_children
|
data._internal.w:set_shape(data.shape or shape.infobubble, unpack(data.shape_args or {}))
|
||||||
|
|
||||||
if not data._internal.margin._data then
|
data._internal.w:connect_signal("property::position", function(_, pos)
|
||||||
data._internal.margin._data = data
|
data._internal.w:set_shape(function(cr, w, h) draw_roundedrect_path(cr, w, h, radius, data, pos) end)
|
||||||
end
|
update_margins(data, pos)
|
||||||
|
end)
|
||||||
|
|
||||||
|
local pos = data._internal.w.position
|
||||||
|
if pos then
|
||||||
|
data._internal.w:set_shape(function(cr, w, h) draw_roundedrect_path(cr, w, h, radius, data, data._internal.w.position) end)
|
||||||
end
|
end
|
||||||
|
update_margins(data, pos)
|
||||||
|
|
||||||
|
data._internal.arrow_setup = true
|
||||||
end
|
end
|
||||||
|
|
||||||
set_direction(data,direction)
|
|
||||||
|
|
||||||
--TODO call this less often
|
|
||||||
return w,w2
|
return w,w2
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(module, { __call = function(_, ...) return draw(...) end })
|
return setmetatable(module, { __call = function(_, ...) return draw(...) end })
|
||||||
-- kate: space-indent on; indent-width 2; replace-tabs on;
|
-- kate: space-indent on; indent-width 4; replace-tabs on;
|
||||||
|
|
Loading…
Reference in New Issue