Как заставить события мыши распространяться на виджеты в контейнерах `scroll`? - PullRequest
0 голосов
/ 01 мая 2019

Итак, я знаю, что в официальной документации написано

Обратите внимание, что события мыши не распространяются на виджеты внутри контейнера прокрутки.

Но то, что я пытаюсь сделать, это то, что: Как я могу заставить события мыши распространяться через этот виджет? Есть ли способ?

То, что я пытаюсь сделать, это сделать «приложение для работы», встроенное в удивительное. Но для этого мне действительно нужны предметы (которые будут выполнять задачи, которые я хочу выполнить)

Итак, я хочу, чтобы в нем было меню с виджетами в виде строк, чтобы я мог использовать его для прокрутки колесиком мыши (или клавиатурой) вверх и вниз, но при этом иметь возможность выбирать элементы. Я думаю, что могу выполнить прокрутку с помощью мыши, установив buttons виджета и настроив методы :pause, :continue контейнера scroll и т. Д., Но не могу выполнить щелчковую часть.

Поэтому мой вопрос: как я могу это сделать? как я могу заставить эту работу работать, даже если не используется контейнер scroll?

Чтобы понять, чего я хочу, вот что я сделал до сих пор:

uhhhhh menu

Ответы [ 2 ]

1 голос
/ 09 мая 2019

Хорошо, вам нужна сложная версия, которая будет обрезать содержащийся в ней виджет до его размера, а также обрабатывать события ввода.Ниже приведена сложная и медленная версия:

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 рисует некоторые виджеты сам, он пытается перерисовать только ту часть, которая фактически изменилась.Например, если часы обновляются из-за изменения времени, будут перерисованы только часы.Этот код здесь вместо этого перерисовывает все всегда.

(И да, я знаю, что этот код довольно спагетти и плох, но он должен помочь вам определить необходимые ингредиенты.)

1 голос
/ 05 мая 2019

Вам поможет следующий пример? Он создает новый виджет, который рисует какой-то другой виджет с некоторыми жестко заданными шириной / высотой и смещением. Таймер используется, чтобы оживить вещи немного.

-- 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)
...