diff --git a/widget/app_launcher/init.lua b/widget/app_launcher/init.lua index 3d1e0bc..3efbb8c 100644 --- a/widget/app_launcher/init.lua +++ b/widget/app_launcher/init.lua @@ -6,6 +6,7 @@ local gtimer = require("gears.timer") local wibox = require("wibox") local beautiful = require("beautiful") local text_input_widget = require(... .. ".text_input") +local rofi_grid_widget = require(... .. ".rofi_grid") local dpi = beautiful.xresources.apply_dpi local string = string local table = table @@ -37,225 +38,221 @@ local function has_value(tab, val) return false end -local function scroll(self, dir, page_dir) - local grid = self:get_grid() - if #grid.children < 1 then - self._private.selected_app_widget = nil - return - end - - local next_app_index = nil - local grid_orientation = grid:get_orientation() - - if dir == "up" then - if grid_orientation == "horizontal" then - next_app_index = grid:index(self:get_selected_app_widget()) - 1 - elseif grid_orientation == "vertical" then - next_app_index = grid:index(self:get_selected_app_widget()) - grid.forced_num_cols - end - elseif dir == "down" then - if grid_orientation == "horizontal" then - next_app_index = grid:index(self:get_selected_app_widget()) + 1 - elseif grid_orientation == "vertical" then - next_app_index = grid:index(self:get_selected_app_widget()) + grid.forced_num_cols - end - elseif dir == "left" then - if grid_orientation == "horizontal" then - next_app_index = grid:index(self:get_selected_app_widget()) - grid.forced_num_rows - elseif grid_orientation == "vertical" then - next_app_index = grid:index(self:get_selected_app_widget()) - 1 - end - elseif dir == "right" then - if grid_orientation == "horizontal" then - next_app_index = grid:index(self:get_selected_app_widget()) + grid.forced_num_rows - elseif grid_orientation == "vertical" then - next_app_index = grid:index(self:get_selected_app_widget()) + 1 - end - end - - local next_app = grid.children[next_app_index] - if next_app then - next_app:select() - self:emit_signal("scroll", dir) - else - if dir == "up" or dir == "left" then - self:page_backward(page_dir or dir) - elseif dir == "down" or dir == "right" then - self:page_forward(page_dir or dir) - end - end -end - -local function app_widget(self, app) - if self._private.apps_widgets_cache[app.name] then - return self._private.apps_widgets_cache[app.name] - end - - local widget = nil - - if self.app_template == nil then - widget = wibox.widget +local function build_widget(self) + local widget_template = self.widget_template + if widget_template == nil then + widget_template = wibox.widget { - widget = wibox.container.background, - forced_width = dpi(300), - forced_height = dpi(120), - bg = self.app_normal_color, - { - widget = wibox.container.margin, - margins = dpi(10), + layout = rofi_grid_widget, + lazy_load_widgets = false, + widget_template = wibox.widget { + layout = wibox.layout.fixed.vertical, + forced_width = dpi(1000), + forced_height = dpi(1000), + spacing = dpi(15), { - layout = wibox.layout.fixed.vertical, + widget = text_input_widget, + id = "text_input_role", + reset_on_stop = self.reset_on_hide, + placeholder = self.text_input_placeholder, + unfocus_keys = { }, + unfocus_on_clicked_inside = false, + unfocus_on_clicked_outside = false, + unfocus_on_mouse_leave = false, + unfocus_on_tag_change = false, + unfocus_on_other_text_input_focus = false, + focus_on_subject_mouse_enter = nil, + unfocus_on_subject_mouse_leave = nil, + widget_template = wibox.widget { + widget = wibox.container.background, + forced_height = dpi(120), + bg = self.text_input_bg_color, + { + widget = wibox.container.margin, + margins = dpi(30), + { + widget = wibox.widget.textbox, + text_color = self.text_input_color, + id = "text_role" + } + } + } + }, + { + layout = wibox.layout.fixed.horizontal, spacing = dpi(10), { - widget = wibox.container.place, - halign = "center", - valign = "center", - { - widget = wibox.widget.imagebox, - id = "icon_role", - forced_width = dpi(70), - forced_height = dpi(70), - image = app.icon - }, + layout = wibox.layout.grid, + id = "grid_role", + orientation = "horizontal", + homogeneous = true, + spacing = dpi(30), + forced_num_cols = self.apps_per_column, + forced_num_rows = self.apps_per_row, }, { - widget = wibox.container.place, - halign = "center", - valign = "center", + layout = wibox.container.rotate, + direction = 'west', { - widget = wibox.widget.textbox, - id = "name_role", - markup = string.format("%s", self.app_name_normal_color, app.name) + widget = wibox.widget.slider, + id = "scrollbar_role", + forced_width = dpi(5), + minimum = 1, + value = 1, + -- bar_shape = helpers.ui.rrect(), + bar_height= 3, + bar_color = beautiful.colors.transparent, + bar_active_color = beautiful.colors.transparent, + handle_width = dpi(50), + handle_color = beautiful.bg_normal, + -- handle_shape = helpers.ui.rrect(), + handle_color = beautiful.colors.on_background } } } - } + }, + entry_template = function(app) + local widget = wibox.widget + { + widget = wibox.container.background, + forced_width = dpi(300), + forced_height = dpi(120), + bg = self.app_normal_color, + { + widget = wibox.container.margin, + margins = dpi(10), + { + layout = wibox.layout.fixed.vertical, + spacing = dpi(10), + { + widget = wibox.container.place, + halign = "center", + valign = "center", + { + widget = wibox.widget.imagebox, + id = "icon_role", + forced_width = dpi(70), + forced_height = dpi(70), + image = app.icon + }, + }, + { + widget = wibox.container.place, + halign = "center", + valign = "center", + { + widget = wibox.widget.textbox, + id = "name_role", + markup = string.format("%s", self.app_name_normal_color, app.name) + } + } + } + } + } + + widget:connect_signal("mouse::enter", function() + local widget = capi.mouse.current_wibox + if widget then + widget.cursor = "hand2" + end + end) + + widget:connect_signal("mouse::leave", function() + local widget = capi.mouse.current_wibox + if widget then + widget.cursor = "left_ptr" + end + end) + + widget:connect_signal("button::press", function(_, __, __, button) + if button == 1 then + if widget:is_selected() or not self.select_before_spawn then + widget:run() + else + widget:select() + end + end + end) + + widget:connect_signal("select", function() + widget.bg = self.app_selected_color + local name_widget = widget:get_children_by_id("name_role")[1] + name_widget.markup = string.format("%s", self.app_name_selected_color, name_widget.text) + end) + + widget:connect_signal("unselect", function() + widget.bg = self.app_normal_color + local name_widget = widget:get_children_by_id("name_role")[1] + name_widget.markup = string.format("%s", self.app_name_normal_color, name_widget.text) + end) + + return widget + end } - - widget:connect_signal("mouse::enter", function() - local widget = capi.mouse.current_wibox - if widget then - widget.cursor = "hand2" - end - end) - - widget:connect_signal("mouse::leave", function() - local widget = capi.mouse.current_wibox - if widget then - widget.cursor = "left_ptr" - end - end) - - widget:connect_signal("button::press", function(app, _, __, button) - if button == 1 then - if app:is_selected() or not self.select_before_spawn then - app:run() - else - app:select() + end + widget_template:set_search_fn(function(text, app) + local matched_apps = Gio.DesktopAppInfo.search(text:lower()) + for _, matched_app in ipairs(matched_apps) do + for _, app_id in ipairs(matched_app) do + if app.id == app_id then + return true end end - end) + end + end) + + self._private.widget = awful.popup + { + screen = self.screen, + type = self.type, + visible = false, + ontop = true, + placement = self.placement, + border_width = self.border_width, + border_color = self.border_color, + shape = self.shape, + bg = self.bg, + widget = widget_template + } + + self:get_text_input():connect_signal("key::press", function(_, mod, key, cmd) + if key == "Escape" then + self:hide() + end + end) + + self:get_text_input():connect_signal("key::release", function(_, mod, key, cmd) + if key == "Return" then + if self:get_rofi_grid():get_selected_widget() ~= nil then + self:get_rofi_grid():get_selected_widget():run() + end + end + end) +end + +local function default_sort_fn(a, b) + local is_a_favorite = has_value(self.favorites, a.id) + local is_b_favorite = has_value(self.favorites, b.id) + + -- Sort the favorite apps first + if is_a_favorite and not is_b_favorite then + return true + elseif not is_a_favorite and is_b_favorite then + return false + end + + -- Sort alphabetically if specified + if self.sort_alphabetically then + return a.name:lower() < b.name:lower() + elseif self.reverse_sort_alphabetically then + return b.name:lower() > a.name:lower() else - widget = self.app_template(app, self) + return true end - - local app_launcher = self - function widget:run() - if app.terminal == true then - local pid = awful.spawn.with_shell(AWESOME_SENSIBLE_TERMINAL_SCRIPT_PATH .. " -e " .. app.exec) - local class = app.startup_wm_class or app.name - awful.spawn.with_shell(string.format( - [[xdotool search --sync --all --pid %s --name '.*' set_window --classname "%s" set_window --class "%s"]], - pid, - class, - class - )) - else - app:launch() - end - - if app_launcher.hide_on_launch then - app_launcher:hide() - end - end - - function widget:run_or_select() - if self:is_selected() then - self:run() - else - self:select() - end - end - - function widget:run_as_root() - if app.terminal == true then - local pid = awful.spawn.with_shell( - AWESOME_SENSIBLE_TERMINAL_SCRIPT_PATH .. " -e " .. - RUN_AS_ROOT_SCRIPT_PATH .. " " .. - app.exec - ) - local class = app.startup_wm_class or app.name - awful.spawn.with_shell(string.format( - [[xdotool search --sync --all --pid %s --name '.*' set_window --classname "%s" set_window --class "%s"]], - pid, - class, - class - )) - else - awful.spawn(RUN_AS_ROOT_SCRIPT_PATH .. " " .. app.exec) - end - - if app_launcher.hide_on_launch then - app_launcher:hide() - end - end - - function widget:select() - if app_launcher:get_selected_app_widget() then - app_launcher:get_selected_app_widget():unselect() - end - app_launcher._private.selected_app_widget = self - self:emit_signal("select") - self.selected = true - - if app_launcher.app_template == nil then - widget.bg = app_launcher.app_selected_color - local name_widget = self:get_children_by_id("name_role")[1] - name_widget.markup = string.format("%s", app_launcher.app_name_selected_color, name_widget.text) - end - end - - function widget:unselect() - self:emit_signal("unselect") - self.selected = false - app_launcher._private.selected_app_widget = nil - - if app_launcher.app_template == nil then - widget.bg = app_launcher.app_normal_color - local name_widget = self:get_children_by_id("name_role")[1] - name_widget.markup = string.format("%s", app_launcher.app_name_normal_color, name_widget.text) - end - end - - function widget:is_selected() - return app_launcher._private.selected_app_widget == self - end - - function app:run() widget:run() end - function app:run_or_select() widget:run_or_select() end - function app:run_as_root() widget:run_as_root() end - function app:select() widget:select() end - function app:unselect() widget:unselect() end - function app:is_selected() widget:is_selected() end - - self._private.apps_widgets_cache[app.name] = widget - - return widget end local function generate_apps(self) - self._private.all_apps = {} - self._private.matched_apps = {} + local entries = {} local app_info = Gio.AppInfo local apps = app_info.get_all() @@ -299,353 +296,71 @@ local function generate_apps(self) app:launch() end } - table.insert(self._private.all_apps, app) - if self.lazy_load_widgets == false then - self._private.apps_widgets_cache[app.name] = app_widget(self, app) - end + table.insert(entries, app) end end end end - self:sort_apps() + self:get_rofi_grid():set_entries(entries, self.sort_fn) end -local function build_widget(self) - local widget = self.widget_template - if widget == nil then - self._private.text_input = wibox.widget - { - widget = text_input_widget, - reset_on_stop = self.reset_on_hide, - placeholder = self.text_input_placeholder, - widget_template = wibox.widget { - widget = wibox.container.background, - forced_height = dpi(120), - bg = self.text_input_bg_color, - { - widget = wibox.container.margin, - margins = dpi(30), - { - widget = wibox.widget.textbox, - id = "text_role" - } - } - } - } - self._private.grid = wibox.widget - { - layout = wibox.layout.grid, - orientation = "horizontal", - homogeneous = true, - spacing = dpi(30), - forced_num_cols = self.apps_per_column, - forced_num_rows = self.apps_per_row, - } - widget = wibox.widget - { - layout = wibox.layout.fixed.vertical, - self._private.text_input, - { - widget = wibox.container.margin, - margins = dpi(30), - self._private.grid - } - } +function app_launcher:run(widget) + if widget.entry.terminal == true then + local pid = awful.spawn.with_shell(AWESOME_SENSIBLE_TERMINAL_SCRIPT_PATH .. " -e " .. widget.entry.exec) + local class = widget.entry.startup_wm_class or widget.entry.name + awful.spawn.with_shell(string.format( + [[xdotool search --sync --all --pid %s --name '.*' set_window --classname "%s" set_window --class "%s"]], + pid, + class, + class + )) else - self._private.text_input = widget:get_children_by_id("text_input_role")[1] - self._private.grid = widget:get_children_by_id("grid_role")[1] + widget.entry:launch() end - self._private.widget = awful.popup - { - screen = self.screen, - type = self.type, - visible = false, - ontop = true, - placement = self.placement, - border_width = self.border_width, - border_color = self.border_color, - shape = self.shape, - bg = self.bg, - widget = widget - } - - self:get_grid():connect_signal("button::press", function(_, lx, ly, button, mods, find_widgets_result) - if button == 4 then - if self:get_grid():get_orientation() == "horizontal" then - self:scroll_up() - else - self:scroll_left("up") - end - elseif button == 5 then - if self:get_grid():get_orientation() == "horizontal" then - self:scroll_down() - else - self:scroll_right("down") - end - end - end) - - self:get_text_input():connect_signal("property::text", function(_, text) - if text == self:get_text() then - return - end - - self._private.text = text - self._private.search_timer:again() - end) - - - self:get_text_input():connect_signal("key::press", function(_, mod, key, cmd) - if key == "Escape" then - self:hide() - end - end) - - self:get_text_input():connect_signal("key::release", function(_, mod, key, cmd) - if key == "Return" then - if self:get_selected_app_widget() ~= nil then - self:get_selected_app_widget():run() - end - end - if key == "Up" then - self:scroll_up() - end - if key == "Down" then - self:scroll_down() - end - if key == "Left" then - self:scroll_left() - end - if key == "Right" then - self:scroll_right() - end - end) - - self._private.max_apps_per_page = self:get_grid().forced_num_cols * self:get_grid().forced_num_rows - self._private.apps_per_page = self._private.max_apps_per_page + if self.hide_on_launch then + app_launcher:hide() + end end -function app_launcher:sort_apps(sort_fn) - table.sort(self._private.all_apps, sort_fn or self.sort_fn or function(a, b) - local is_a_favorite = has_value(self.favorites, a.id) - local is_b_favorite = has_value(self.favorites, b.id) +function app_launcher:run_or_select(widget) + if self:get_selected_widget() == widget then + self:run(widget) + else + self:select(widget) + end +end - -- Sort the favorite apps first - if is_a_favorite and not is_b_favorite then - return true - elseif not is_a_favorite and is_b_favorite then - return false - end +function app_launcher:run_as_root(widget) + if widget.entry.terminal == true then + local pid = awful.spawn.with_shell( + AWESOME_SENSIBLE_TERMINAL_SCRIPT_PATH .. " -e " .. + RUN_AS_ROOT_SCRIPT_PATH .. " " .. + widget.entry.exec + ) + local class = widget.entry.startup_wm_class or widget.entry.name + awful.spawn.with_shell(string.format( + [[xdotool search --sync --all --pid %s --name '.*' set_window --classname "%s" set_window --class "%s"]], + pid, + class, + class + )) + else + awful.spawn(RUN_AS_ROOT_SCRIPT_PATH .. " " .. widget.entry.exec) + end - -- Sort alphabetically if specified - if self.sort_alphabetically then - return a.name:lower() < b.name:lower() - elseif self.reverse_sort_alphabetically then - return b.name:lower() > a.name:lower() - else - return true - end - end) + if self.hide_on_launch then + app_launcher:hide() + end end function app_launcher:set_favorites(favorites) self.favorites = favorites - self:sort_apps() + self:get_rofi_grid():set_sort_fn(self.sort_fn) self:refresh() end -function app_launcher:refresh() - local max_app_index_to_include = self._private.apps_per_page * self:get_current_page() - local min_app_index_to_include = max_app_index_to_include - self._private.apps_per_page - - self:get_grid():reset() - - for index, app in ipairs(self._private.matched_apps) do - -- Only add widgets that are between this range (part of the current page) - if index > min_app_index_to_include and index <= max_app_index_to_include then - self:get_grid():add(app_widget(self, app)) - end - end -end - -function app_launcher:search() - local text = self:get_text() - local old_pos = self:get_grid():get_widget_position(self:get_selected_app_widget()) - - -- Reset all the matched apps - self._private.matched_apps = {} - -- Remove all the grid widgets - self:get_grid():reset() - - if text == "" then - self._private.matched_apps = self._private.all_apps - for _, matched_app in ipairs(self._private.matched_apps) do - if #self:get_grid().children + 1 <= self._private.max_apps_per_page then - self:get_grid():add(app_widget(self, matched_app)) - else - break - end - end - else - local matched_apps = Gio.DesktopAppInfo.search(text:lower()) - for _, matched_app in ipairs(matched_apps) do - for _, app_id in ipairs(matched_app) do - for _, app in ipairs(self._private.all_apps) do - if app.id == app_id then - table.insert(self._private.matched_apps, app) - -- Only add the widgets for apps that are part of the first page - if #self:get_grid().children + 1 <= self._private.max_apps_per_page then - self:get_grid():add(app_widget(self, app)) - end - end - end - end - end - end - - -- Recalculate the apps per page based on the current matched apps - self._private.apps_per_page = math.min(#self._private.matched_apps, self._private.max_apps_per_page) - - -- Recalculate the pages count based on the current apps per page - self._private.pages_count = math.ceil(math.max(1, #self._private.matched_apps) / math.max(1, self._private.apps_per_page)) - - -- Page should be 1 after a search - self._private.current_page = 1 - - -- This is an option to mimic rofi behaviour where after a search - -- it will reselect the app whose index is the same as the app index that was previously selected - -- and if matched_apps.length < current_index it will instead select the app with the greatest index - if self.try_to_keep_index_after_searching then - if self:get_grid():get_widgets_at(old_pos.row, old_pos.col) == nil then - local app = self:get_grid().children[#self:get_grid().children] - app:select() - else - local app = self:get_grid():get_widgets_at(old_pos.row, old_pos.col)[1] - app:select() - end - -- Otherwise select the first app on the list - elseif #self:get_grid().children > 0 then - local app = self:get_grid():get_widgets_at(1, 1)[1] - app:select() - end - - self:emit_signal("search", self:get_text(), self:get_current_page(), self:get_pages_count()) -end - -function app_launcher:scroll_up(page_dir) - scroll(self, "up", page_dir) -end - -function app_launcher:scroll_down(page_dir) - scroll(self, "down", page_dir) -end - -function app_launcher:scroll_left(page_dir) - scroll(self, "left", page_dir) -end - -function app_launcher:scroll_right(page_dir) - scroll(self, "right", page_dir) -end - -function app_launcher:page_forward(dir) - local min_app_index_to_include = 0 - local max_app_index_to_include = self._private.apps_per_page - - if self:get_current_page() < self:get_pages_count() then - min_app_index_to_include = self._private.apps_per_page * self:get_current_page() - self._private.current_page = self:get_current_page() + 1 - max_app_index_to_include = self._private.apps_per_page * self:get_current_page() - elseif self.wrap_page_scrolling and #self._private.matched_apps >= self._private.max_apps_per_page then - self._private.current_page = 1 - min_app_index_to_include = 0 - max_app_index_to_include = self._private.apps_per_page - elseif self.wrap_app_scrolling then - local app = self:get_grid():get_widgets_at(1, 1)[1] - app:select() - return - else - return - end - - local pos = self:get_grid():get_widget_position(self:get_selected_app_widget()) - - -- Remove the current page apps from the grid - self:get_grid():reset() - - for index, app in ipairs(self._private.matched_apps) do - -- Only add widgets that are between this range (part of the current page) - if index > min_app_index_to_include and index <= max_app_index_to_include then - self:get_grid():add(app_widget(self, app)) - end - end - - if self:get_current_page() > 1 or self.wrap_page_scrolling then - local app = nil - if dir == "down" then - app = self:get_grid():get_widgets_at(1, 1)[1] - elseif dir == "right" then - app = self:get_grid():get_widgets_at(pos.row, 1) - if app then - app = app[1] - end - if app == nil then - app = self:get_grid().children[#self:get_grid().children] - end - end - app:select() - end - - self:emit_signal("page::forward", dir, self:get_current_page(), self:get_pages_count()) -end - -function app_launcher:page_backward(dir) - if self:get_current_page() > 1 then - self._private.current_page = self:get_current_page() - 1 - elseif self.wrap_page_scrolling and #self._private.matched_apps >= self._private.max_apps_per_page then - self._private.current_page = self:get_pages_count() - elseif self.wrap_app_scrolling then - local app = self:get_grid().children[#self:get_grid().children] - app:select() - return - else - return - end - - local pos = self:get_grid():get_widget_position(self:get_selected_app_widget()) - - -- Remove the current page apps from the grid - self:get_grid():reset() - - local max_app_index_to_include = self._private.apps_per_page * self:get_current_page() - local min_app_index_to_include = max_app_index_to_include - self._private.apps_per_page - - for index, app in ipairs(self._private.matched_apps) do - -- Only add widgets that are between this range (part of the current page) - if index > min_app_index_to_include and index <= max_app_index_to_include then - self:get_grid():add(app_widget(self, app)) - end - end - - local app = nil - if self:get_current_page() < self:get_pages_count() then - if dir == "up" then - app = self:get_grid().children[#self:get_grid().children] - else - -- Keep the same row from last page - local _, columns = self:get_grid():get_dimension() - app = self:get_grid():get_widgets_at(pos.row, columns)[1] - end - elseif self.wrap_page_scrolling then - app = self:get_grid().children[#self:get_grid().children] - end - app:select() - - self:emit_signal("page::backward", dir, self:get_current_page(), self:get_pages_count()) -end - function app_launcher:show() if self.show_on_focused_screen then self:get_widget().screen = awful.screen.focused() @@ -662,7 +377,7 @@ function app_launcher:hide() end if self.reset_on_hide == true then - self:reset() + self:get_rofi_grid():reset() end self:get_widget().visible = false @@ -678,54 +393,16 @@ function app_launcher:toggle() end end -function app_launcher:reset() - self:get_grid():reset() - self._private.matched_apps = self._private.all_apps - self._private.apps_per_page = self._private.max_apps_per_page - self._private.pages_count = math.ceil(#self._private.all_apps / self._private.apps_per_page) - self._private.current_page = 1 - - for index, app in ipairs(self._private.all_apps) do - -- Only add the apps that are part of the first page - if index <= self._private.apps_per_page then - self:get_grid():add(app_widget(self, app)) - else - break - end - end - - local app = self:get_grid():get_widgets_at(1, 1)[1] - app:select() - - self:get_text_input():set_text("") -end - function app_launcher:get_widget() return self._private.widget end +function app_launcher:get_rofi_grid() + return self:get_widget().widget +end + function app_launcher:get_text_input() - return self._private.text_input -end - -function app_launcher:get_grid() - return self._private.grid -end - -function app_launcher:get_pages_count() - return self._private.pages_count -end - -function app_launcher:get_current_page() - return self._private.current_page -end - -function app_launcher:get_text() - return self._private.text -end - -function app_launcher:get_selected_app_widget() - return self._private.selected_app_widget + return self:get_rofi_grid():get_text_input() end local function new(args) @@ -766,6 +443,7 @@ local function new(args) args.apps_per_column = default_value(args.apps_per_column, 3) args.text_input_bg_color = default_value(args.text_input_bg_color, "#000000") + args.text_input_color = default_value(args.text_input_bg_color, "#FFFFFF") args.text_input_placeholder = default_value(args.text_input_placeholder, "Search: ") args.app_normal_color = default_value(args.app_normal_color, "#000000") @@ -781,7 +459,6 @@ local function new(args) ret._private.text = "" ret._private.pages_count = 0 ret._private.current_page = 1 - ret._private.apps_widgets_cache = setmetatable({}, { __mode = "v" }) ret._private.search_timer = gtimer { timeout = 0.05, call_now = false, @@ -827,7 +504,6 @@ local function new(args) build_widget(ret) generate_apps(ret) - ret:reset() return ret end diff --git a/widget/app_launcher/rofi_grid.lua b/widget/app_launcher/rofi_grid.lua index ebc1382..85caeca 100644 --- a/widget/app_launcher/rofi_grid.lua +++ b/widget/app_launcher/rofi_grid.lua @@ -74,7 +74,7 @@ local function scroll(self, dir, page_dir) local next_widget = grid.children[next_widget_index] if next_widget then next_widget:select() - self:emit_signal("scroll", self:get_index_of_widget(next_widget)) + self:emit_signal("scroll", self:get_index_of_entry(next_widget.entry)) else if dir == "up" or dir == "left" then self:page_backward(page_dir or dir) @@ -93,17 +93,37 @@ local function entry_widget(self, entry) local rofi_grid = self function widget:select() - rofi_grid:select_widget(self) + if rofi_grid:get_selected_widget() then + rofi_grid:get_selected_widget():unselect() + end + rofi_grid._private.selected_widget = self + self.selected = true + + local index = rofi_grid:get_index_of_entry(entry) + self:emit_signal("select", index) + rofi_grid:emit_signal("select", index) + end + + function widget:unselect() + self.selected = false + rofi_grid._private.selected_widget = nil + + self:emit_signal("unselect") + rofi_grid:emit_signal("unselect") end function widget:is_selected() - return rofi_grid:get_selected_widget() == self + return rofi_grid._private.selected_widget == self end + function entry:select() widget:select() end + function entry:unselect() widget:unselect() end + function entry:is_selected() widget:is_selected() end entry.widget = widget widget.entry = entry self._private.entries_widgets_cache[entry] = widget + return widget end @@ -182,7 +202,7 @@ function rofi_grid:set_widget_template(widget_template) scrollbar:connect_signal("property::value", function(_, value, instant) if instant ~= true then - self:select_widget_by_index(value) + self:set_selected_entry(value) end end) end @@ -253,12 +273,12 @@ function rofi_grid:search() else for _, entry in ipairs(self._private.entries) do text = text:gsub( "%W", "" ) - if self.search_fn(text:lower(), entry, self:get_entries()) then + if self._private.search_fn(text:lower(), entry) then table.insert(self:get_matched_entries(), entry) end end - if self:get_sort_fn() then + if self:get_search_sort_fn() then table.sort(self:get_matched_entries(), function(a, b) return self._private.search_sort_fn(text, a, b) end) @@ -284,9 +304,9 @@ function rofi_grid:search() -- it will reselect the entry whose index is the same as the entry index that was previously selected -- and if matched_entries.length < current_index it will instead select the entry with the greatest index if self._private.try_to_keep_index_after_searching then - local widget_at_old_pos = self:get_grid():get_widgets_at(old_pos.row, old_pos.col) - if widget_at_old_pos and widget_at_old_pos[1] then - widget_at_old_pos[1]:select() + local entry_at_old_pos = self:get_grid():get_widgets_at(old_pos.row, old_pos.col) + if entry_at_old_pos and entry_at_old_pos[1] then + entry_at_old_pos[1]:select() else local widget = self:get_grid().children[#self:get_grid().children] widget:select() @@ -297,35 +317,21 @@ function rofi_grid:search() widget:select() end - self:emit_signal("search", self:get_text(), self:get_index_of_widget(self:get_selected_widget())) + self:emit_signal("search", self:get_text(), self:get_index_of_entry(self:get_selected_widget().entry)) end -function rofi_grid:select_widget(widget) - print(widget) - self:select_widget_by_index(self:get_index_of_widget(widget)) -end - -function rofi_grid:select_widget_by_index(index) - local previous_widget = self:get_selected_widget() - if previous_widget then - self._private.selected_widget = nil - self:emit_signal("unselect") - previous_widget:emit_signal("unselect") +function rofi_grid:set_selected_entry(index) + local selected_widget_index = self:get_grid():index(self:get_selected_widget()) + if index == selected_widget_index then + return end - print(index) + local page = self:get_page_of_index(index) + if self:get_current_page() ~= page then + self:set_page(page) + end - -- local new_widget = self:get_widget_of_index(index) - -- if new_widget then - -- local page = self:get_page_of_index(index) - -- if self:get_current_page() ~= page then - -- self:set_page(page) - -- end - - -- self._private.selected_widget = new_widget - -- self:emit_signal("select", index) - -- new_widget:emit_signal("select", index) - -- end + self:get_entry_of_index(index).widget:select() end function rofi_grid:scroll_up(page_dir) @@ -359,7 +365,7 @@ function rofi_grid:page_forward(dir) elseif self._private.wrap_entry_scrolling then local widget = self:get_grid():get_widgets_at(1, 1)[1] widget:select() - self:emit_signal("scroll", self:get_index_of_widget(widget)) + self:emit_signal("scroll", self:get_index_of_entry(widget.entry)) return else return @@ -378,22 +384,22 @@ function rofi_grid:page_forward(dir) end if self:get_current_page() > 1 or self._private.wrap_page_scrolling then - local widget = nil + local entry = nil if dir == "down" then - widget = self:get_grid():get_widgets_at(1, 1)[1] + entry = self:get_grid():get_widgets_at(1, 1)[1] elseif dir == "right" then - widget = self:get_grid():get_widgets_at(pos.row, 1) - if widget then - widget = widget[1] + entry = self:get_grid():get_widgets_at(pos.row, 1) + if entry then + entry = entry[1] end - if widget == nil then - widget = self:get_grid().children[#self:get_grid().children] + if entry == nil then + entry = self:get_grid().children[#self:get_grid().children] end end - widget:select() + entry:select() end - self:emit_signal("page::forward", self:get_index_of_widget(self:get_selected_widget())) + self:emit_signal("page::forward", self:get_index_of_entry(self:get_selected_widget().entry)) end function rofi_grid:page_backward(dir) @@ -404,7 +410,7 @@ function rofi_grid:page_backward(dir) elseif self._private.wrap_entry_scrolling then local widget = self:get_grid().children[#self:get_grid().children] widget:select() - self:emit_signal("scroll", self:get_index_of_widget(widget)) + self:emit_signal("scroll", self:get_index_of_entry(widget.entry)) return else return @@ -425,21 +431,21 @@ function rofi_grid:page_backward(dir) end end - local widget = nil + local entry = nil if self:get_current_page() < self:get_pages_count() then if dir == "up" then - widget = self:get_grid().children[#self:get_grid().children] + entry = self:get_grid().children[#self:get_grid().children] else -- Keep the same row from last page local _, columns = self:get_grid():get_dimension() - widget = self:get_grid():get_widgets_at(pos.row, columns)[1] + entry = self:get_grid():get_widgets_at(pos.row, columns)[1] end elseif self._private.wrap_page_scrolling then - widget = self:get_grid().children[#self:get_grid().children] + entry = self:get_grid().children[#self:get_grid().children] end - widget:select() + entry:select() - self:emit_signal("page::backward", self:get_index_of_widget(self:get_selected_widget())) + self:emit_signal("page::backward", self:get_index_of_entry(self:get_selected_widget().entry)) end function rofi_grid:set_page(page) @@ -459,11 +465,11 @@ function rofi_grid:set_page(page) end end - local widget = self:get_grid():get_widgets_at(1, 1) - if widget then - widget = widget[1] - if widget then - widget:select() + local entry = self:get_grid():get_widgets_at(1, 1) + if entry then + entry = entry[1] + if entry then + entry:select() end end end @@ -484,11 +490,11 @@ function rofi_grid:reset() end end - local widget = self:get_grid():get_widgets_at(1, 1) - if widget then - widget = widget[1] - if widget then - widget:select() + local entry = self:get_grid():get_widgets_at(1, 1) + if entry then + entry = entry[1] + if entry then + entry:select() end end @@ -527,22 +533,6 @@ function rofi_grid:get_matched_entries() return self._private.matched_entries end -function rofi_grid:get_page_of_index(index) - return math.floor((index - 1) / self._private.entries_per_page) + 1 -end - -function rofi_grid:get_index_of_widget(widget) - for index, matched_widget in ipairs(self:get_matched_entries()) do - if matched_widget.entry == widget.entry then - return index - end - end -end - -function rofi_grid:get_widget_of_index(index) - return self:get_matched_entries()[index].widget -end - function rofi_grid:get_text() return self._private.text end @@ -551,6 +541,26 @@ function rofi_grid:get_selected_widget() return self._private.selected_widget end +function rofi_grid:get_page_of_entry(entry) + return math.floor((self:get_index_of_entry(entry) - 1) / self._private.entries_per_page) + 1 +end + +function rofi_grid:get_page_of_index(index) + return math.floor((index - 1) / self._private.entries_per_page) + 1 +end + +function rofi_grid:get_index_of_entry(entry) + for index, matched_entry in ipairs(self:get_matched_entries()) do + if matched_entry == entry then + return index + end + end +end + +function rofi_grid:get_entry_of_index(index) + return self:get_matched_entries()[index] +end + local function new() local widget = wibox.container.background() gtable.crush(widget, rofi_grid, true)