如何使鼠标事件传播到“滚动”容器中的小部件?

时间:2019-05-01 12:55:46

标签: awesome-wm

所以我知道在官方文档上写着

  

请注意,鼠标事件不会传播到滚动容器内部的窗口小部件。

但是我要尝试的完全是这样:如何使鼠标事件通过此小部件传播?有办法吗?

我要做的是制作一个内置的“待办应用”。但是为此,我实际上需要准备一些物品(这是我要完成的任务)

所以我想要一个菜单​​,里面有成行的小部件,这样我就可以用它通过鼠标滚轮(或键盘)上下滚动,但仍然可以选择东西。我想我可以通过设置小部件的buttons并使用scroll容器的:pause:continue等方法来进行鼠标滚动,但是我做不到点击部分。

因此,我的问题是:我怎样才能做到这一点?即使不是通过使用scroll容器,该如何工作?

要了解我想要的东西,这是我到目前为止所做的:

uhhhhh menu

2 个答案:

答案 0 :(得分:1)

以下示例对您有帮助吗?它创建了一个新的窗口小部件,该窗口小部件以硬编码的宽度/高度和偏移绘制了其他窗口小部件。计时器用于对事物进行动画处理。

-- No idea how to pick a good width and height for the wibox.
local w = wibox{ x = 100, y = 100, width = 100, height = 20, visible = true }
local own_widget = wibox.widget.base.make_widget()
local offset_x, offset_y = -20, 0
function own_widget:layout(context, width, height)
    -- No idea how to pick good widths and heights for the inner widget.
    return { wibox.widget.base.place_widget_at(screen[1].mytaglist, offset_x, offset_y, 200, 40) }
end
gears.timer.start_new(1, function()
    if offset_x < 0 then
        offset_x = 20
    else
        offset_x = -20
    end
    own_widget:emit_signal("widget::layout_changed")
    return true
end)
w:set_widget(own_widget)

答案 1 :(得分:1)

好的,因此,您需要一个复杂的版本,该版本将其包含的窗口小部件裁剪到其大小并还处理输入事件。以下是复杂而缓慢的版本:

local inner_widget = screen[1].mytaglist
local inner_width, inner_height = 200, 40
-- No idea how to pick a good width and height for the wibox.
local w = wibox{ x = 100, y = 100, width = 100, height = 20, visible = true }
local own_widget = wibox.widget.base.make_widget()
w:set_widget(own_widget)
local offset_x, offset_y = -20, 0
local own_context = { screen = screen[1], dpi = 92 } -- We have to invent something here... :-(
local hierarchy
hierarchy = wibox.hierarchy.new(own_context, inner_widget, inner_width, inner_height, function()
    own_widget:emit_signal("widget::redraw_needed")
end, function()
    hierarchy:update(own_context, inner_widget, inner_width, inner_height)
    own_widget:emit_signal("widget::redraw_needed")
end, nil)
function own_widget:draw(context, cr, width, height)
    -- This does the scrolling
    cr:translate(offset_x, offset_y)

    -- Then just draw the inner stuff directly
    hierarchy:draw(own_context, cr)
end
-- Start a timer to simulate scrolling: Once per second we move things slightly
gears.timer.start_new(1, function()
    offset_x = - offset_x
    own_widget:emit_signal("widget::redraw_needed")
    return true
end)
-- Finally, make input events work
local function button_signal(name)
    -- This function is basically copy&paste from find_widgets() in
    -- wibox.drawable
    local function traverse_hierarchy_tree(h, x, y, ...)
        local m = h:get_matrix_from_device()

        -- Is (x,y) inside of this hierarchy or any child (aka the draw extents)?
        -- If not, we can stop searching.
        local x1, y1 = m:transform_point(x, y)
        local x2, y2, w2, h2 = h:get_draw_extents()
        if x1 < x2 or x1 >= x2 + w2 then
            return
        end
        if y1 < y2 or y1 >= y2 + h2 then
            return
        end
        -- Is (x,y) inside of this widget?
        -- If yes, we have to emit the signal on the widget.
        local width, height = h:get_size()
        if x1 >= 0 and y1 >= 0 and x1 <= width and y1 <= height then
            h:get_widget():emit_signal(name, x1, y1, ...)
        end
        -- Continue searching in all children.
        for _, child in ipairs(h:get_children()) do
            traverse_hierarchy_tree(child, x, y, ...)
        end
    end
    own_widget:connect_signal(name, function(_, x, y, ...)
        -- Translate to "local" coordinates
        x = x - offset_x
        y = y - offset_y
        -- Figure out which widgets were hit and emit the signal on them
        traverse_hierarchy_tree(hierarchy, x, y, ...)
    end)
end
button_signal("button::press")
button_signal("button::release")

此代码并没有让AwesomeWM处理所有事情,而只是在:layout中放置了另一个小部件,而是执行了更多操作。即,它直接管理窗口小部件树(在AwesomeWM中称为“层次结构”)并对其进行绘制。然后,这段代码的一半负责处理按钮事件:传入代码后,此代码会将当前滚动考虑在内,将其转发到正确的小部件。

请注意,只要有任何更改,此操作就会重绘此自定义小部件显示的所有内容。我想对于您的滚动问题来说还是有必要的,因为滚动一点时“一切都会改变”。但是,当AwesomeWM自己绘制一些小部件时,它将尝试仅重绘实际更改的部分。例如,如果由于时间更改而导致时钟更新,则只有时钟会被重绘。相反,此代码始终重绘所有内容。

(是的,我知道这段代码很意大利面,很糟糕,但是它应该可以帮助您找出必需的成分。)