Replace the prompt with a proper text input widget
This commit is contained in:
parent
13d0f1c435
commit
4cdc4fb5f9
|
@ -5,7 +5,7 @@ local gtable = require("gears.table")
|
|||
local gtimer = require("gears.timer")
|
||||
local wibox = require("wibox")
|
||||
local beautiful = require("beautiful")
|
||||
local prompt_widget = require(... .. ".prompt")
|
||||
local text_input_widget = require(... .. ".text_input")
|
||||
local dpi = beautiful.xresources.apply_dpi
|
||||
local string = string
|
||||
local table = table
|
||||
|
@ -318,22 +318,24 @@ end
|
|||
local function build_widget(self)
|
||||
local widget = self.widget_template
|
||||
if widget == nil then
|
||||
self._private.prompt = wibox.widget
|
||||
self._private.text_input = wibox.widget
|
||||
{
|
||||
widget = prompt_widget,
|
||||
always_on = true,
|
||||
widget = text_input_widget,
|
||||
reset_on_stop = self.reset_on_hide,
|
||||
icon_font = self.prompt_icon_font,
|
||||
icon_size = self.prompt_icon_size,
|
||||
icon_color = self.prompt_icon_color,
|
||||
icon = self.prompt_icon,
|
||||
label_font = self.prompt_label_font,
|
||||
label_size = self.prompt_label_size,
|
||||
label_color = self.prompt_label_color,
|
||||
label = self.prompt_label,
|
||||
text_font = self.prompt_text_font,
|
||||
text_size = self.prompt_text_size,
|
||||
text_color = self.prompt_text_color,
|
||||
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
|
||||
{
|
||||
|
@ -347,21 +349,7 @@ local function build_widget(self)
|
|||
widget = wibox.widget
|
||||
{
|
||||
layout = wibox.layout.fixed.vertical,
|
||||
{
|
||||
widget = wibox.container.background,
|
||||
forced_height = dpi(120),
|
||||
bg = self.prompt_bg_color,
|
||||
{
|
||||
widget = wibox.container.margin,
|
||||
margins = dpi(30),
|
||||
{
|
||||
widget = wibox.container.place,
|
||||
halign = "left",
|
||||
valign = "center",
|
||||
self._private.prompt
|
||||
}
|
||||
}
|
||||
},
|
||||
self._private.text_input,
|
||||
{
|
||||
widget = wibox.container.margin,
|
||||
margins = dpi(30),
|
||||
|
@ -369,7 +357,7 @@ local function build_widget(self)
|
|||
}
|
||||
}
|
||||
else
|
||||
self._private.prompt = widget:get_children_by_id("prompt_role")[1]
|
||||
self._private.text_input = widget:get_children_by_id("text_input_role")[1]
|
||||
self._private.grid = widget:get_children_by_id("grid_role")[1]
|
||||
end
|
||||
|
||||
|
@ -403,7 +391,7 @@ local function build_widget(self)
|
|||
end
|
||||
end)
|
||||
|
||||
self:get_prompt():connect_signal("text::changed", function(_, text)
|
||||
self:get_text_input():connect_signal("property::text", function(_, text)
|
||||
if text == self:get_text() then
|
||||
return
|
||||
end
|
||||
|
@ -412,10 +400,14 @@ local function build_widget(self)
|
|||
self._private.search_timer:again()
|
||||
end)
|
||||
|
||||
self:get_prompt():connect_signal("key::release", function(_, mod, key, cmd)
|
||||
|
||||
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()
|
||||
|
@ -664,7 +656,7 @@ function app_launcher:show()
|
|||
end
|
||||
|
||||
self:get_widget().visible = true
|
||||
self:get_prompt():start()
|
||||
self:get_text_input():focus()
|
||||
self:emit_signal("visibility", true)
|
||||
end
|
||||
|
||||
|
@ -678,7 +670,7 @@ function app_launcher:hide()
|
|||
end
|
||||
|
||||
self:get_widget().visible = false
|
||||
self:get_prompt():stop()
|
||||
self:get_text_input():unfocus()
|
||||
self:emit_signal("visibility", false)
|
||||
end
|
||||
|
||||
|
@ -709,15 +701,15 @@ function app_launcher:reset()
|
|||
local app = self:get_grid():get_widgets_at(1, 1)[1]
|
||||
app:select()
|
||||
|
||||
self:get_prompt():set_text("")
|
||||
self:get_text_input():set_text("")
|
||||
end
|
||||
|
||||
function app_launcher:get_widget()
|
||||
return self._private.widget
|
||||
end
|
||||
|
||||
function app_launcher:get_prompt()
|
||||
return self._private.prompt
|
||||
function app_launcher:get_text_input()
|
||||
return self._private.text_input
|
||||
end
|
||||
|
||||
function app_launcher:get_grid()
|
||||
|
@ -777,18 +769,8 @@ local function new(args)
|
|||
args.apps_per_row = default_value(args.apps_per_row, 5)
|
||||
args.apps_per_column = default_value(args.apps_per_column, 3)
|
||||
|
||||
args.prompt_bg_color = default_value(args.prompt_bg_color, "#000000")
|
||||
args.prompt_icon_font = default_value(args.prompt_icon_font, beautiful.font)
|
||||
args.prompt_icon_size = default_value(args.prompt_icon_size, 12)
|
||||
args.prompt_icon_color = default_value(args.prompt_icon_color, "#FFFFFF")
|
||||
args.prompt_icon = default_value(args.prompt_icon, "")
|
||||
args.prompt_label_font = default_value(args.prompt_label_font, beautiful.font)
|
||||
args.prompt_label_size = default_value(args.prompt_label_size, 12)
|
||||
args.prompt_label_color = default_value(args.prompt_label_color, "#FFFFFF")
|
||||
args.prompt_label = default_value(args.prompt_label, "<b>Search</b>: ")
|
||||
args.prompt_text_font = default_value(args.prompt_text_font, beautiful.font)
|
||||
args.prompt_text_size = default_value(args.prompt_text_size, 12)
|
||||
args.prompt_text_color = default_value(args.prompt_text_color, "#FFFFFF")
|
||||
args.text_input_bg_color = default_value(args.text_input_bg_color, "#000000")
|
||||
args.text_input_placeholder = default_value(args.text_input_placeholder, "Search: ")
|
||||
|
||||
args.app_normal_color = default_value(args.app_normal_color, "#000000")
|
||||
args.app_selected_color = default_value(args.app_selected_color, "#FFFFFF")
|
||||
|
|
|
@ -1,480 +0,0 @@
|
|||
-------------------------------------------
|
||||
-- @author https://github.com/Kasper24
|
||||
-- @copyright 2021-2022 Kasper24
|
||||
-------------------------------------------
|
||||
local lgi = require('lgi')
|
||||
local Gtk = lgi.require('Gtk', '3.0')
|
||||
local Gdk = lgi.require('Gdk', '3.0')
|
||||
local awful = require("awful")
|
||||
local gtable = require("gears.table")
|
||||
local gstring = require("gears.string")
|
||||
local wibox = require("wibox")
|
||||
local beautiful = require("beautiful")
|
||||
local dpi = beautiful.xresources.apply_dpi
|
||||
local tostring = tostring
|
||||
local tonumber = tonumber
|
||||
local ceil = math.ceil
|
||||
local ipairs = ipairs
|
||||
local string = string
|
||||
local type = type
|
||||
local capi = {
|
||||
awesome = awesome,
|
||||
root = root,
|
||||
mouse = mouse,
|
||||
tag = tag,
|
||||
client = client
|
||||
}
|
||||
|
||||
local prompt = {
|
||||
mt = {}
|
||||
}
|
||||
|
||||
local properties = {
|
||||
"only_numbers", "round", "obscure",
|
||||
"always_on", "reset_on_stop",
|
||||
"stop_on_lost_focus", "stop_on_tag_changed", "stop_on_clicked_outside",
|
||||
"icon_font", "icon_size", "icon_color", "icon",
|
||||
"label_font", "label_size", "label_color", "label",
|
||||
"text_font", "text_size", "text_color", "text",
|
||||
"cursor_size", "cursor_color"
|
||||
}
|
||||
|
||||
local function is_word_char(c)
|
||||
if string.find(c, "[{[(,.:;_-+=@/ ]") then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function cword_start(s, pos)
|
||||
local i = pos
|
||||
if i > 1 then
|
||||
i = i - 1
|
||||
end
|
||||
while i >= 1 and not is_word_char(s:sub(i, i)) do
|
||||
i = i - 1
|
||||
end
|
||||
while i >= 1 and is_word_char(s:sub(i, i)) do
|
||||
i = i - 1
|
||||
end
|
||||
if i <= #s then
|
||||
i = i + 1
|
||||
end
|
||||
return i
|
||||
end
|
||||
|
||||
local function cword_end(s, pos)
|
||||
local i = pos
|
||||
while i <= #s and not is_word_char(s:sub(i, i)) do
|
||||
i = i + 1
|
||||
end
|
||||
while i <= #s and is_word_char(s:sub(i, i)) do
|
||||
i = i + 1
|
||||
end
|
||||
return i
|
||||
end
|
||||
|
||||
local function have_multibyte_char_at(text, position)
|
||||
return text:sub(position, position):wlen() == -1
|
||||
end
|
||||
|
||||
local function generate_markup(self)
|
||||
local wp = self._private
|
||||
|
||||
local label_size = dpi(ceil(wp.label_size * 1024))
|
||||
local text_size = dpi(ceil(wp.text_size * 1024))
|
||||
local cursor_size = dpi(ceil(wp.cursor_size * 1024))
|
||||
|
||||
local text = tostring(wp.text) or ""
|
||||
if wp.obscure == true then
|
||||
text = text:gsub(".", "*")
|
||||
end
|
||||
|
||||
local markup = ""
|
||||
if wp.icon ~= nil then
|
||||
if type(wp.icon) == "table" then
|
||||
local icon_size = dpi(ceil(wp.icon.size * 1024))
|
||||
markup = string.format(
|
||||
'<span font_family="%s" font_size="%s" foreground="%s">%s </span>',
|
||||
wp.icon.font, icon_size, wp.icon.color, wp.icon.icon)
|
||||
else
|
||||
local icon_size = dpi(ceil(wp.icon_size * 1024))
|
||||
markup = string.format(
|
||||
'<span font_family="%s" font_size="%s" foreground="%s">%s </span>',
|
||||
wp.icon_font, icon_size, wp.icon_color, wp.icon)
|
||||
end
|
||||
end
|
||||
|
||||
if self._private.state == true then
|
||||
local char, spacer, text_start, text_end
|
||||
|
||||
if #text < wp.cur_pos then
|
||||
char = " "
|
||||
spacer = ""
|
||||
text_start = gstring.xml_escape(text)
|
||||
text_end = ""
|
||||
else
|
||||
local offset = 0
|
||||
if have_multibyte_char_at(text, wp.cur_pos) then
|
||||
offset = 1
|
||||
end
|
||||
char = gstring.xml_escape(text:sub(wp.cur_pos, wp.cur_pos + offset))
|
||||
spacer = " "
|
||||
text_start = gstring.xml_escape(text:sub(1, wp.cur_pos - 1))
|
||||
text_end = gstring.xml_escape(text:sub(wp.cur_pos + offset))
|
||||
end
|
||||
|
||||
markup = markup .. (string.format(
|
||||
'<span font_family="%s" font_size="%s" foreground="%s">%s</span>' ..
|
||||
'<span font_family="%s" font_size="%s" foreground="%s">%s</span>' ..
|
||||
'<span font_size="%s" background="%s">%s</span>' ..
|
||||
'<span font_family="%s" font_size="%s" foreground="%s">%s%s</span>',
|
||||
wp.label_font, label_size, wp.label_color, wp.label,
|
||||
wp.text_font, text_size, wp.text_color, text_start,
|
||||
cursor_size, wp.cursor_color, char,
|
||||
wp.text_font, text_size, wp.text_color, text_end,
|
||||
spacer))
|
||||
else
|
||||
markup = markup .. string.format(
|
||||
'<span font_family="%s" font_size="%s" foreground="%s">%s</span>' ..
|
||||
'<span font_family="%s" font_size="%s" foreground="%s">%s</span>',
|
||||
wp.label_font, label_size, wp.label_color, wp.label,
|
||||
wp.text_font, text_size, wp.text_color, gstring.xml_escape(text))
|
||||
end
|
||||
|
||||
self:set_markup(markup)
|
||||
end
|
||||
|
||||
local function paste(self)
|
||||
local wp = self._private
|
||||
|
||||
wp.clipboard:request_text(function(clipboard, text)
|
||||
if text then
|
||||
wp.text = wp.text:sub(1, wp.cur_pos - 1) .. stdout .. self.text:sub(wp.cur_pos)
|
||||
wp.cur_pos = wp.cur_pos + #stdout
|
||||
generate_markup(self)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function build_properties(prototype, prop_names)
|
||||
for _, prop in ipairs(prop_names) do
|
||||
if not prototype["set_" .. prop] then
|
||||
prototype["set_" .. prop] = function(self, value)
|
||||
if self._private[prop] ~= value then
|
||||
self._private[prop] = value
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
self:emit_signal("property::" .. prop, value)
|
||||
generate_markup(self)
|
||||
end
|
||||
return self
|
||||
end
|
||||
end
|
||||
if not prototype["get_" .. prop] then
|
||||
prototype["get_" .. prop] = function(self)
|
||||
return self._private[prop]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function prompt:toggle_obscure()
|
||||
self:set_obscure(not self._private.obscure)
|
||||
end
|
||||
|
||||
function prompt:set_text(text)
|
||||
self._private.text = text
|
||||
self._private.cur_pos = #text + 1
|
||||
generate_markup(self)
|
||||
end
|
||||
|
||||
function prompt:get_text()
|
||||
return self._private.text
|
||||
end
|
||||
|
||||
function prompt:start()
|
||||
local wp = self._private
|
||||
wp.state = true
|
||||
|
||||
capi.awesome.emit_signal("prompt::toggled_on", self)
|
||||
generate_markup(self)
|
||||
|
||||
wp.grabber = awful.keygrabber.run(function(modifiers, key, event)
|
||||
-- Convert index array to hash table
|
||||
local mod = {}
|
||||
for _, v in ipairs(modifiers) do
|
||||
mod[v] = true
|
||||
end
|
||||
|
||||
if event ~= "press" then
|
||||
self:emit_signal("key::release", mod, key, wp.text)
|
||||
return
|
||||
end
|
||||
|
||||
self:emit_signal("key::press", mod, key, wp.text)
|
||||
|
||||
-- Control cases
|
||||
if mod.Control then
|
||||
if key == "v" then
|
||||
paste(self)
|
||||
elseif key == "a" then
|
||||
wp.cur_pos = 1
|
||||
elseif key == "b" then
|
||||
if wp.cur_pos > 1 then
|
||||
wp.cur_pos = wp.cur_pos - 1
|
||||
if have_multibyte_char_at(wp.text, wp.cur_pos) then
|
||||
wp.cur_pos = wp.cur_pos - 1
|
||||
end
|
||||
end
|
||||
elseif key == "d" then
|
||||
if wp.cur_pos <= #wp.text then
|
||||
wp.text = wp.text:sub(1, wp.cur_pos - 1) .. wp.text:sub(wp.cur_pos + 1)
|
||||
end
|
||||
elseif key == "e" then
|
||||
wp.cur_pos = #wp.text + 1
|
||||
elseif key == "f" then
|
||||
if wp.cur_pos <= #wp.text then
|
||||
if have_multibyte_char_at(wp.text, wp.cur_pos) then
|
||||
wp.cur_pos = wp.cur_pos + 2
|
||||
else
|
||||
wp.cur_pos = wp.cur_pos + 1
|
||||
end
|
||||
end
|
||||
elseif key == "h" then
|
||||
if wp.cur_pos > 1 then
|
||||
local offset = 0
|
||||
if have_multibyte_char_at(wp.text, wp.cur_pos - 1) then
|
||||
offset = 1
|
||||
end
|
||||
wp.text = wp.text:sub(1, wp.cur_pos - 2 - offset) .. wp.text:sub(wp.cur_pos)
|
||||
wp.cur_pos = wp.cur_pos - 1 - offset
|
||||
end
|
||||
elseif key == "k" then
|
||||
wp.text = wp.text:sub(1, wp.cur_pos - 1)
|
||||
elseif key == "u" then
|
||||
wp.text = wp.text:sub(wp.cur_pos, #wp.text)
|
||||
wp.cur_pos = 1
|
||||
elseif key == "w" or key == "BackSpace" then
|
||||
local wstart = 1
|
||||
local wend = 1
|
||||
local cword_start_pos = 1
|
||||
local cword_end_pos = 1
|
||||
while wend < wp.cur_pos do
|
||||
wend = wp.text:find("[{[(,.:;_-+=@/ ]", wstart)
|
||||
if not wend then
|
||||
wend = #wp.text + 1
|
||||
end
|
||||
if wp.cur_pos >= wstart and wp.cur_pos <= wend + 1 then
|
||||
cword_start_pos = wstart
|
||||
cword_end_pos = wp.cur_pos - 1
|
||||
break
|
||||
end
|
||||
wstart = wend + 1
|
||||
end
|
||||
wp.text = wp.text:sub(1, cword_start_pos - 1) .. wp.text:sub(cword_end_pos + 1)
|
||||
wp.cur_pos = cword_start_pos
|
||||
end
|
||||
elseif mod.Mod1 or mod.Mod3 then
|
||||
if key == "b" then
|
||||
wp.cur_pos = cword_start(wp.text, wp.cur_pos)
|
||||
elseif key == "f" then
|
||||
wp.cur_pos = cword_end(wp.text, wp.cur_pos)
|
||||
elseif key == "d" then
|
||||
wp.text = wp.text:sub(1, wp.cur_pos - 1) .. wp.text:sub(cword_end(wp.text, wp.cur_pos))
|
||||
elseif key == "BackSpace" then
|
||||
local wstart = cword_start(wp.text, wp.cur_pos)
|
||||
wp.text = wp.text:sub(1, wstart - 1) .. wp.text:sub(wp.cur_pos)
|
||||
wp.cur_pos = wstart
|
||||
end
|
||||
else
|
||||
if key == "Escape" or key == "Return" then
|
||||
if self.always_on == false then
|
||||
self:stop()
|
||||
return
|
||||
end
|
||||
elseif mod.Shift and key == "Insert" then
|
||||
paste(self)
|
||||
elseif key == "Home" then
|
||||
wp.cur_pos = 1
|
||||
elseif key == "End" then
|
||||
wp.cur_pos = #wp.text + 1
|
||||
elseif key == "BackSpace" then
|
||||
if wp.cur_pos > 1 then
|
||||
local offset = 0
|
||||
if have_multibyte_char_at(wp.text, wp.cur_pos - 1) then
|
||||
offset = 1
|
||||
end
|
||||
wp.text = wp.text:sub(1, wp.cur_pos - 2 - offset) .. wp.text:sub(wp.cur_pos)
|
||||
wp.cur_pos = wp.cur_pos - 1 - offset
|
||||
end
|
||||
elseif key == "Delete" then
|
||||
wp.text = wp.text:sub(1, wp.cur_pos - 1) .. wp.text:sub(wp.cur_pos + 1)
|
||||
elseif key == "Left" then
|
||||
wp.cur_pos = wp.cur_pos - 1
|
||||
elseif key == "Right" then
|
||||
wp.cur_pos = wp.cur_pos + 1
|
||||
else
|
||||
if wp.round and key == "." then
|
||||
return
|
||||
end
|
||||
if wp.only_numbers and tonumber(wp.text .. key) == nil then
|
||||
return
|
||||
end
|
||||
|
||||
-- wlen() is UTF-8 aware but #key is not,
|
||||
-- so check that we have one UTF-8 char but advance the cursor of # position
|
||||
if key:wlen() == 1 then
|
||||
wp.text = wp.text:sub(1, wp.cur_pos - 1) .. key .. wp.text:sub(wp.cur_pos)
|
||||
wp.cur_pos = wp.cur_pos + #key
|
||||
end
|
||||
end
|
||||
if wp.cur_pos < 1 then
|
||||
wp.cur_pos = 1
|
||||
elseif wp.cur_pos > #wp.text + 1 then
|
||||
wp.cur_pos = #wp.text + 1
|
||||
end
|
||||
end
|
||||
|
||||
if wp.only_numbers and wp.text == "" then
|
||||
wp.text = "0"
|
||||
wp.cur_pos = #wp.text + 1
|
||||
end
|
||||
|
||||
generate_markup(self)
|
||||
self:emit_signal("text::changed", wp.text)
|
||||
end)
|
||||
end
|
||||
|
||||
function prompt:stop()
|
||||
local wp = self._private
|
||||
if wp.state == false then
|
||||
return
|
||||
end
|
||||
|
||||
wp.state = false
|
||||
|
||||
if self.reset_on_stop == true then
|
||||
self:set_text("")
|
||||
end
|
||||
|
||||
if wp.grabber then
|
||||
awful.keygrabber.stop(wp.grabber)
|
||||
end
|
||||
generate_markup(self)
|
||||
|
||||
self:emit_signal("stopped", wp.text)
|
||||
end
|
||||
|
||||
function prompt:toggle()
|
||||
local wp = self._private
|
||||
|
||||
if wp.state == true then
|
||||
self:stop()
|
||||
else
|
||||
self:start()
|
||||
end
|
||||
end
|
||||
|
||||
local function new()
|
||||
local widget = wibox.widget.textbox()
|
||||
gtable.crush(widget, prompt, true)
|
||||
|
||||
local wp = widget._private
|
||||
|
||||
wp.only_numbers = false
|
||||
wp.round = false
|
||||
wp.always_on = false
|
||||
wp.reset_on_stop = false
|
||||
wp.obscure = false
|
||||
wp.stop_on_focus_lost = false
|
||||
wp.stop_on_tag_changed = false
|
||||
wp.stop_on_clicked_outside = true
|
||||
|
||||
wp.icon_font = beautiful.font
|
||||
wp.icon_size = 12
|
||||
wp.icon_color = beautiful.colors.on_background
|
||||
wp.icon = nil
|
||||
|
||||
wp.label_font = beautiful.font
|
||||
wp.label_size = 12
|
||||
wp.label_color = beautiful.colors.on_background
|
||||
wp.label = ""
|
||||
|
||||
wp.text_font = beautiful.font
|
||||
wp.text_size = 12
|
||||
wp.text_color = beautiful.colors.on_background
|
||||
wp.text = ""
|
||||
|
||||
wp.cursor_size = 4
|
||||
wp.cursor_color = beautiful.colors.on_background
|
||||
|
||||
wp.cur_pos = #wp.text + 1 or 1
|
||||
wp.state = false
|
||||
wp.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
||||
|
||||
widget:connect_signal("mouse::enter", function(self, find_widgets_result)
|
||||
capi.root.cursor("xterm")
|
||||
local wibox = capi.mouse.current_wibox
|
||||
if wibox then
|
||||
wibox.cursor = "xterm"
|
||||
end
|
||||
end)
|
||||
|
||||
widget:connect_signal("mouse::leave", function()
|
||||
capi.root.cursor("left_ptr")
|
||||
local wibox = capi.mouse.current_wibox
|
||||
if wibox then
|
||||
wibox.cursor = "left_ptr"
|
||||
end
|
||||
|
||||
if wp.stop_on_focus_lost ~= false and wp.always_on == false and wp.state == true then
|
||||
widget:stop()
|
||||
end
|
||||
end)
|
||||
|
||||
widget:connect_signal("button::press", function(self, lx, ly, button, mods, find_widgets_result)
|
||||
if wp.always_on then
|
||||
return
|
||||
end
|
||||
|
||||
if button == 1 then
|
||||
widget:toggle()
|
||||
end
|
||||
end)
|
||||
|
||||
-- TODO make it work outside my config
|
||||
capi.awesome.connect_signal("root::pressed", function()
|
||||
if wp.stop_on_clicked_outside ~= false and wp.always_on == false and wp.state == true then
|
||||
widget:stop()
|
||||
end
|
||||
end)
|
||||
|
||||
capi.client.connect_signal("button::press", function()
|
||||
if wp.stop_on_clicked_outside ~= false and wp.always_on == false and wp.state == true then
|
||||
widget:stop()
|
||||
end
|
||||
end)
|
||||
|
||||
capi.tag.connect_signal("property::selected", function()
|
||||
if wp.stop_on_tag_changed ~= false and wp.always_on == false and wp.state == true then
|
||||
widget:stop()
|
||||
end
|
||||
end)
|
||||
|
||||
capi.awesome.connect_signal("prompt::toggled_on", function(prompt)
|
||||
if wp.always_on == false and prompt ~= widget and wp.state == true then
|
||||
widget:stop()
|
||||
end
|
||||
end)
|
||||
|
||||
return widget
|
||||
end
|
||||
|
||||
function prompt.mt:__call(...)
|
||||
return new(...)
|
||||
end
|
||||
|
||||
build_properties(prompt, properties)
|
||||
|
||||
return setmetatable(prompt, prompt.mt)
|
|
@ -0,0 +1,769 @@
|
|||
-------------------------------------------
|
||||
-- @author https://github.com/Kasper24
|
||||
-- @copyright 2021-2022 Kasper24
|
||||
-------------------------------------------
|
||||
local lgi = require('lgi')
|
||||
local Gtk = lgi.require('Gtk', '3.0')
|
||||
local Gdk = lgi.require('Gdk', '3.0')
|
||||
local Pango = lgi.Pango
|
||||
local awful = require("awful")
|
||||
local gtable = require("gears.table")
|
||||
local gtimer = require("gears.timer")
|
||||
local gcolor = require("gears.color")
|
||||
local wibox = require("wibox")
|
||||
local beautiful = require("beautiful")
|
||||
local tonumber = tonumber
|
||||
local ipairs = ipairs
|
||||
local string = string
|
||||
local capi = {
|
||||
awesome = awesome,
|
||||
root = root,
|
||||
tag = tag,
|
||||
client = client,
|
||||
mouse = mouse,
|
||||
mousegrabber = mousegrabber
|
||||
}
|
||||
|
||||
local text_input = {
|
||||
mt = {}
|
||||
}
|
||||
|
||||
local properties = {
|
||||
"unfocus_keys", "unfocus_on_clicked_inside", "unfocus_on_clicked_outside", "unfocus_on_mouse_leave", "unfocus_on_tag_change",
|
||||
"focus_on_subject_mouse_enter", "unfocus_on_subject_mouse_leave",
|
||||
"reset_on_unfocus",
|
||||
"placeholder", "text", "only_numbers", "round", "obscure",
|
||||
"cursor_blink", "cursor_blink_rate","cursor_size", "cursor_bg",
|
||||
"selection_bg"
|
||||
}
|
||||
|
||||
local function build_properties(prototype, prop_names)
|
||||
for _, prop in ipairs(prop_names) do
|
||||
if not prototype["set_" .. prop] then
|
||||
prototype["set_" .. prop] = function(self, value)
|
||||
if self._private[prop] ~= value then
|
||||
self._private[prop] = value
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
self:emit_signal("property::" .. prop, value)
|
||||
end
|
||||
return self
|
||||
end
|
||||
end
|
||||
if not prototype["get_" .. prop] then
|
||||
prototype["get_" .. prop] = function(self)
|
||||
return self._private[prop]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function has_value(tab, val)
|
||||
for _, value in ipairs(tab) do
|
||||
if val:lower():find(value:lower(), 1, true) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function is_word_char(c)
|
||||
if string.find(c, "[{[(,.:;_-+=@/ ]") then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function cword_start(s, pos)
|
||||
local i = pos
|
||||
if i > 1 then
|
||||
i = i - 1
|
||||
end
|
||||
while i >= 1 and not is_word_char(s:sub(i, i)) do
|
||||
i = i - 1
|
||||
end
|
||||
while i >= 1 and is_word_char(s:sub(i, i)) do
|
||||
i = i - 1
|
||||
end
|
||||
if i <= #s then
|
||||
i = i + 1
|
||||
end
|
||||
return i
|
||||
end
|
||||
|
||||
local function cword_end(s, pos)
|
||||
local i = pos
|
||||
while i <= #s and not is_word_char(s:sub(i, i)) do
|
||||
i = i + 1
|
||||
end
|
||||
while i <= #s and is_word_char(s:sub(i, i)) do
|
||||
i = i + 1
|
||||
end
|
||||
return i
|
||||
end
|
||||
|
||||
local function run_mousegrabber(self)
|
||||
capi.mousegrabber.run(function(m)
|
||||
if m.buttons[1] then
|
||||
if capi.mouse.current_widget ~= self and self.unfocus_on_clicked_outside then
|
||||
self:unfocus()
|
||||
return false
|
||||
elseif capi.mouse.current_widget == self and self.unfocus_on_clicked_inside then
|
||||
self:unfocus()
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end, "xterm")
|
||||
end
|
||||
|
||||
local function run_keygrabber(self)
|
||||
local wp = self._private
|
||||
wp.keygrabber = awful.keygrabber.run(function(modifiers, key, event)
|
||||
if event ~= "press" then
|
||||
self:emit_signal("key::release", modifiers, key, event)
|
||||
return
|
||||
end
|
||||
self:emit_signal("key::press", modifiers, key, event)
|
||||
|
||||
-- Convert index array to hash table
|
||||
local mod = {}
|
||||
for _, v in ipairs(modifiers) do
|
||||
mod[v] = true
|
||||
end
|
||||
|
||||
if mod.Control then
|
||||
if key == "a" then
|
||||
self:select_all()
|
||||
elseif key == "c" then
|
||||
self:copy()
|
||||
elseif key == "v" then
|
||||
self:paste()
|
||||
elseif key == "b" or key == "Left" then
|
||||
self:set_cursor_index_to_word_start()
|
||||
elseif key == "f" or key == "Right" then
|
||||
self:set_cursor_index_to_word_end()
|
||||
elseif key == "d" then
|
||||
self:delete_next_word()
|
||||
elseif key == "BackSpace" then
|
||||
self:delete_previous_word()
|
||||
end
|
||||
elseif mod.Shift then
|
||||
if key =="Left" then
|
||||
self:decremeant_selection_end_index()
|
||||
elseif key == "Right" then
|
||||
self:increamant_selection_end_index()
|
||||
end
|
||||
else
|
||||
if has_value(wp.unfocus_keys, key) then
|
||||
self:unfocus()
|
||||
end
|
||||
|
||||
if mod.Shift and key == "Insert" then
|
||||
self:paste()
|
||||
elseif key == "Home" then
|
||||
self:set_cursor_index(0)
|
||||
elseif key == "End" then
|
||||
self:set_cursor_index_to_end()
|
||||
elseif key == "BackSpace" then
|
||||
self:delete_text()
|
||||
elseif key == "Delete" then
|
||||
self:delete_text_after_cursor()
|
||||
elseif key == "Left" then
|
||||
self:decremeant_cursor_index()
|
||||
elseif key == "Right" then
|
||||
self:increamant_cursor_index()
|
||||
else
|
||||
if (wp.round and key == ".") or (wp.only_numbers and tonumber(self:get_text() .. key) == nil) then
|
||||
return
|
||||
end
|
||||
|
||||
-- wlen() is UTF-8 aware but #key is not,
|
||||
-- so check that we have one UTF-8 char but advance the cursor of # position
|
||||
if key:wlen() == 1 then
|
||||
self:update_text(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function text_input:set_widget_template(widget_template)
|
||||
local wp = self._private
|
||||
|
||||
self._private.text_widget = widget_template:get_children_by_id("text_role")[1]
|
||||
self._private.text_widget.forced_width = math.huge
|
||||
local text_draw = self._private.text_widget.draw
|
||||
|
||||
local placeholder_widget = widget_template:get_children_by_id("placeholder_role")
|
||||
if placeholder_widget then
|
||||
placeholder_widget = placeholder_widget[1]
|
||||
end
|
||||
|
||||
function self._private.text_widget:draw(context, cr, width, height)
|
||||
-- Selection bg
|
||||
local ink_rect, logical_rect = self._private.layout:get_pixel_extents()
|
||||
cr:set_source(gcolor.change_opacity(wp.selection_bg, wp.selection_opacity))
|
||||
cr:rectangle(
|
||||
wp.selection_start_x,
|
||||
logical_rect.y - 3,
|
||||
wp.selection_end_x - wp.selection_start_x,
|
||||
logical_rect.y + logical_rect.height + 6
|
||||
)
|
||||
cr:fill()
|
||||
|
||||
-- Cursor
|
||||
local ink_rect, logical_rect = self._private.layout:get_pixel_extents()
|
||||
cr:set_source(gcolor.change_opacity(wp.cursor_bg, wp.cursor_opacity))
|
||||
cr:set_line_width(wp.cursor_width)
|
||||
cr:move_to(wp.cursor_x, logical_rect.y - 3)
|
||||
cr:line_to(wp.cursor_x, logical_rect.y + logical_rect.height + 6)
|
||||
cr:stroke()
|
||||
|
||||
cr:set_source_rgb(1, 1, 1)
|
||||
|
||||
text_draw(self, context, cr, width, height)
|
||||
|
||||
if self:get_text() == "" and placeholder_widget then
|
||||
placeholder_widget.visible = true
|
||||
elseif placeholder_widget then
|
||||
placeholder_widget.visible = false
|
||||
end
|
||||
end
|
||||
|
||||
wp.selecting_text = false
|
||||
|
||||
local function on_drag(drawable, lx, ly)
|
||||
if not wp.selecting_text and (lx ~= wp.press_pos.lx or ly ~= wp.press_pos.ly) then
|
||||
self:set_selection_start_index_from_x_y(wp.press_pos.lx, wp.press_pos.ly)
|
||||
self:set_selection_end_index(self._private.selection_start)
|
||||
wp.selecting_text = true
|
||||
elseif wp.selecting_text then
|
||||
self:set_selection_end_index_from_x_y(lx - wp.offset.x, ly - wp.offset.y)
|
||||
end
|
||||
end
|
||||
|
||||
self._private.text_widget:connect_signal("button::press", function(_, lx, ly, button, mods, find_widgets_result)
|
||||
if button == 1 then
|
||||
self:focus()
|
||||
wp.press_pos = { lx = lx, ly = ly }
|
||||
wp.offset = { x = find_widgets_result.x, y = find_widgets_result.y }
|
||||
find_widgets_result.drawable:connect_signal("mouse::move", on_drag)
|
||||
end
|
||||
end)
|
||||
|
||||
self._private.text_widget:connect_signal("button::release", function(_, lx, ly, button, mods, find_widgets_result)
|
||||
find_widgets_result.drawable:disconnect_signal("mouse::move", on_drag)
|
||||
if not wp.selecting_text then
|
||||
self:set_cursor_index_from_x_y(lx, ly)
|
||||
else
|
||||
wp.selecting_text = false
|
||||
end
|
||||
end)
|
||||
|
||||
self._private.text_widget:connect_signal("mouse::enter", function()
|
||||
capi.root.cursor("xterm")
|
||||
local wibox = capi.mouse.current_wibox
|
||||
if wibox then
|
||||
wibox.cursor = "xterm"
|
||||
end
|
||||
end)
|
||||
|
||||
self._private.text_widget:connect_signal("mouse::leave", function(_, find_widgets_result)
|
||||
if self:get_focused() == false then
|
||||
capi.root.cursor("left_ptr")
|
||||
local wibox = capi.mouse.current_wibox
|
||||
if wibox then
|
||||
wibox.cursor = "left_ptr"
|
||||
end
|
||||
end
|
||||
|
||||
find_widgets_result.drawable:disconnect_signal("mouse::move", on_drag)
|
||||
if wp.unfocus_on_mouse_leave then
|
||||
self:unfocus()
|
||||
end
|
||||
end)
|
||||
|
||||
self:set_widget(widget_template)
|
||||
end
|
||||
|
||||
function text_input:get_mode()
|
||||
return self._private.mode
|
||||
end
|
||||
|
||||
function text_input:set_focused(focused)
|
||||
if focused == true then
|
||||
self:focus()
|
||||
else
|
||||
self:unfocus()
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:toggle_obscure()
|
||||
self:set_obscure(not self._private.obscure)
|
||||
end
|
||||
|
||||
function text_input:update_text(text)
|
||||
if self:get_mode() == "insert" then
|
||||
self:insert_text(text)
|
||||
else
|
||||
self:overwrite_text(text)
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:set_text(text)
|
||||
local wp = self._private
|
||||
local text_widget = self:get_text_widget()
|
||||
|
||||
text_widget:set_text(text)
|
||||
if text_widget:get_text() == "" then
|
||||
self:set_cursor_index(0)
|
||||
else
|
||||
self:set_cursor_index(#text)
|
||||
end
|
||||
|
||||
self:emit_signal("property::text", text_widget:get_text())
|
||||
end
|
||||
|
||||
function text_input:insert_text(text)
|
||||
local old_text = self:get_text()
|
||||
local cursor_index = self:get_cursor_index()
|
||||
local left_text = old_text:sub(1, cursor_index) .. text
|
||||
local right_text = old_text:sub(cursor_index + 1)
|
||||
self:get_text_widget():set_text(left_text .. right_text)
|
||||
self:set_cursor_index(self:get_cursor_index() + #text)
|
||||
|
||||
self:emit_signal("property::text", self:get_text())
|
||||
end
|
||||
|
||||
function text_input:overwrite_text(text)
|
||||
local start_pos = self._private.selection_start
|
||||
local end_pos = self._private.selection_end
|
||||
if start_pos > end_pos then
|
||||
start_pos, end_pos = end_pos, start_pos
|
||||
end
|
||||
|
||||
local old_text = self:get_text()
|
||||
local left_text = old_text:sub(1, start_pos)
|
||||
local right_text = old_text:sub(end_pos + 1)
|
||||
self:get_text_widget():set_text(left_text .. text .. right_text)
|
||||
self:set_cursor_index(#left_text)
|
||||
|
||||
self:emit_signal("property::text", self:get_text())
|
||||
end
|
||||
|
||||
function text_input:copy()
|
||||
local wp = self._private
|
||||
if self:get_mode() == "overwrite" then
|
||||
local text = self:get_text()
|
||||
local start_pos = self._private.selection_start
|
||||
local end_pos = self._private.selection_end
|
||||
if start_pos > end_pos then
|
||||
start_pos, end_pos = end_pos + 1, start_pos
|
||||
end
|
||||
text = text:sub(start_pos, end_pos)
|
||||
wp.clipboard:set_text(text, -1)
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:paste()
|
||||
local wp = self._private
|
||||
|
||||
wp.clipboard:request_text(function(clipboard, text)
|
||||
if text then
|
||||
self:update_text(text)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function text_input:delete_next_word()
|
||||
local old_text = self:get_text()
|
||||
local cursor_index = self:get_cursor_index()
|
||||
|
||||
local left_text = old_text:sub(1, cursor_index)
|
||||
local right_text = old_text:sub(cword_end(old_text, cursor_index + 1))
|
||||
self:get_text_widget():set_text(left_text .. right_text)
|
||||
self:emit_signal("property::text", self:get_text())
|
||||
end
|
||||
|
||||
function text_input:delete_previous_word()
|
||||
local old_text = self:get_text()
|
||||
local cursor_index = self:get_cursor_index()
|
||||
local wstart = cword_start(old_text, cursor_index + 1) - 1
|
||||
local left_text = old_text:sub(1, wstart)
|
||||
local right_text = old_text:sub(cursor_index + 1)
|
||||
self:get_text_widget():set_text(left_text .. right_text)
|
||||
self:set_cursor_index(wstart)
|
||||
self:emit_signal("property::text", self:get_text())
|
||||
end
|
||||
|
||||
function text_input:delete_text()
|
||||
if self:get_mode() == "insert" then
|
||||
self:delete_text_before_cursor()
|
||||
else
|
||||
self:overwrite_text("")
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:delete_text_before_cursor()
|
||||
local cursor_index = self:get_cursor_index()
|
||||
if cursor_index > 0 then
|
||||
local old_text = self:get_text()
|
||||
local left_text = old_text:sub(1, cursor_index - 1)
|
||||
local right_text = old_text:sub(cursor_index + 1)
|
||||
self:get_text_widget():set_text(left_text .. right_text)
|
||||
self:set_cursor_index(cursor_index - 1)
|
||||
self:emit_signal("property::text", self:get_text())
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:delete_text_after_cursor()
|
||||
local cursor_index = self:get_cursor_index()
|
||||
if cursor_index < #self:get_text() then
|
||||
local old_text = self:get_text()
|
||||
local left_text = old_text:sub(1, cursor_index)
|
||||
local right_text = old_text:sub(cursor_index + 2)
|
||||
self:get_text_widget():set_text(left_text .. right_text)
|
||||
self:emit_signal("property::text", self:get_text())
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:get_text()
|
||||
return self:get_text_widget():get_text()
|
||||
end
|
||||
|
||||
function text_input:get_text_widget()
|
||||
return self._private.text_widget
|
||||
end
|
||||
|
||||
function text_input:show_selection()
|
||||
self._private.selection_opacity = 1
|
||||
self:get_text_widget():emit_signal("widget::redraw_needed")
|
||||
end
|
||||
|
||||
function text_input:hide_selection()
|
||||
self._private.selection_opacity = 0
|
||||
self:get_text_widget():emit_signal("widget::redraw_needed")
|
||||
end
|
||||
|
||||
function text_input:select_all()
|
||||
self:set_selection_start_index(0)
|
||||
self:set_selection_end_index(#self:get_text())
|
||||
end
|
||||
|
||||
function text_input:set_selection_start_index(index)
|
||||
index = math.max(math.min(index, #self:get_text()), 0)
|
||||
|
||||
local layout = self:get_text_widget()._private.layout
|
||||
local strong_pos, weak_pos = layout:get_caret_pos(index)
|
||||
if strong_pos then
|
||||
self._private.selection_start = index
|
||||
self._private.mode = "overwrite"
|
||||
|
||||
self._private.selection_start_x = strong_pos.x / Pango.SCALE
|
||||
self._private.selection_start_y = strong_pos.y / Pango.SCALE
|
||||
|
||||
self:show_selection()
|
||||
self:hide_cursor()
|
||||
|
||||
self:get_text_widget():emit_signal("widget::redraw_needed")
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:set_selection_end_index(index)
|
||||
index = math.max(math.min(index, #self:get_text()), 0)
|
||||
|
||||
local layout = self:get_text_widget()._private.layout
|
||||
local strong_pos, weak_pos = layout:get_caret_pos(index)
|
||||
if strong_pos then
|
||||
self._private.selection_end_x = strong_pos.x / Pango.SCALE
|
||||
self._private.selection_end_y = strong_pos.y / Pango.SCALE
|
||||
self._private.selection_end = index
|
||||
self:get_text_widget():emit_signal("widget::redraw_needed")
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:increamant_selection_end_index()
|
||||
if self:get_mode() == "insert" then
|
||||
self:set_selection_start_index(self:get_cursor_index())
|
||||
self:set_selection_end_index(self:get_cursor_index() + 1)
|
||||
else
|
||||
self:set_selection_end_index(self._private.selection_end + 1)
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:decremeant_selection_end_index()
|
||||
if self:get_mode() == "insert" then
|
||||
self:set_selection_start_index(self:get_cursor_index())
|
||||
self:set_selection_end_index(self:get_cursor_index() - 1)
|
||||
else
|
||||
self:set_selection_end_index(self._private.selection_end - 1)
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:set_selection_start_index_from_x_y(x, y)
|
||||
local layout = self:get_text_widget()._private.layout
|
||||
local index, trailing = layout:xy_to_index(x * Pango.SCALE, y * Pango.SCALE)
|
||||
if index then
|
||||
self:set_selection_start_index(index)
|
||||
else
|
||||
self:set_selection_start_index(#self:get_text())
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:set_selection_end_index_from_x_y(x, y)
|
||||
local layout = self:get_text_widget()._private.layout
|
||||
local index, trailing = layout:xy_to_index(x * Pango.SCALE, y * Pango.SCALE)
|
||||
if index then
|
||||
self:set_selection_end_index(index + trailing)
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:show_cursor()
|
||||
self._private.cursor_opacity = 1
|
||||
self:get_text_widget():emit_signal("widget::redraw_needed")
|
||||
end
|
||||
|
||||
function text_input:hide_cursor()
|
||||
self._private.cursor_opacity = 0
|
||||
self:get_text_widget():emit_signal("widget::redraw_needed")
|
||||
end
|
||||
|
||||
function text_input:set_cursor_index(index)
|
||||
index = math.max(math.min(index, #self:get_text()), 0)
|
||||
|
||||
local layout = self:get_text_widget()._private.layout
|
||||
local strong_pos, weak_pos = layout:get_cursor_pos(index)
|
||||
if strong_pos then
|
||||
self._private.cursor_index = index
|
||||
self._private.mode = "insert"
|
||||
|
||||
self._private.cursor_x = strong_pos.x / Pango.SCALE
|
||||
self._private.cursor_y = strong_pos.y / Pango.SCALE
|
||||
|
||||
if self:get_focused() then
|
||||
self:show_cursor()
|
||||
end
|
||||
self:hide_selection()
|
||||
|
||||
self:get_text_widget():emit_signal("widget::redraw_needed")
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:set_cursor_index_from_x_y(x, y)
|
||||
local layout = self:get_text_widget()._private.layout
|
||||
local index, trailing = layout:xy_to_index(x * Pango.SCALE, y * Pango.SCALE)
|
||||
|
||||
if index then
|
||||
self:set_cursor_index(index)
|
||||
else
|
||||
self:set_cursor_index(#self:get_text())
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:set_cursor_index_to_word_start()
|
||||
self:set_cursor_index(cword_start(self:get_text(), self:get_cursor_index() + 1) - 1)
|
||||
end
|
||||
|
||||
function text_input:set_cursor_index_to_word_end()
|
||||
self:set_cursor_index(cword_end(self:get_text(), self:get_cursor_index() + 1) - 1)
|
||||
end
|
||||
|
||||
function text_input:set_cursor_index_to_end()
|
||||
self:set_cursor_index(#self:get_text())
|
||||
end
|
||||
|
||||
function text_input:increamant_cursor_index()
|
||||
if self:get_mode() == "insert" then
|
||||
self:set_cursor_index(self:get_cursor_index() + 1)
|
||||
else
|
||||
local start_pos = self._private.selection_start
|
||||
local end_pos = self._private.selection_end
|
||||
if start_pos > end_pos then
|
||||
start_pos, end_pos = end_pos, start_pos
|
||||
end
|
||||
self:set_cursor_index(end_pos)
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:decremeant_cursor_index()
|
||||
if self:get_mode() == "insert" then
|
||||
self:set_cursor_index(self:get_cursor_index() - 1)
|
||||
else
|
||||
local start_pos = self._private.selection_start
|
||||
local end_pos = self._private.selection_end
|
||||
if start_pos > end_pos then
|
||||
start_pos, end_pos = end_pos, start_pos
|
||||
end
|
||||
self:set_cursor_index(start_pos)
|
||||
end
|
||||
end
|
||||
|
||||
function text_input:get_cursor_index()
|
||||
return self._private.cursor_index
|
||||
end
|
||||
|
||||
function text_input:set_focus_on_subject_mouse_enter(subject)
|
||||
subject:connect_signal("mouse::enter", function()
|
||||
self:focus()
|
||||
end)
|
||||
end
|
||||
|
||||
function text_input:set_unfocus_on_subject_mouse_leave(subject)
|
||||
subject:connect_signal("mouse::leave", function()
|
||||
self:unfocus()
|
||||
end)
|
||||
end
|
||||
|
||||
function text_input:get_focused()
|
||||
return self._private.focused
|
||||
end
|
||||
|
||||
function text_input:focus()
|
||||
local wp = self._private
|
||||
if self:get_focused() == true then
|
||||
return
|
||||
end
|
||||
|
||||
self:show_cursor()
|
||||
run_keygrabber(self)
|
||||
if wp.unfocus_on_clicked_outside or wp.unfocus_on_clicked_inside then
|
||||
run_mousegrabber(self)
|
||||
end
|
||||
|
||||
if wp.cursor_blink then
|
||||
gtimer.start_new(wp.cursor_blink_rate, function()
|
||||
if self:get_focused() == true then
|
||||
if self._private.cursor_opacity == 1 then
|
||||
self:hide_cursor()
|
||||
elseif self:get_mode() == "insert" then
|
||||
self:show_cursor()
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end)
|
||||
end
|
||||
|
||||
wp.focused = true
|
||||
self:emit_signal("focus")
|
||||
capi.awesome.emit_signal("text_input::focus", self)
|
||||
end
|
||||
|
||||
function text_input:unfocus()
|
||||
local wp = self._private
|
||||
if self:get_focused() == false then
|
||||
return
|
||||
end
|
||||
|
||||
self:hide_cursor()
|
||||
self:hide_selection()
|
||||
if self.reset_on_unfocus == true then
|
||||
self:set_text("")
|
||||
end
|
||||
awful.keygrabber.stop(wp.keygrabber)
|
||||
if wp.unfocus_on_clicked_outside then
|
||||
capi.mousegrabber.stop()
|
||||
end
|
||||
capi.root.cursor("left_ptr")
|
||||
local wibox = capi.mouse.current_wibox
|
||||
if wibox then
|
||||
wibox.cursor = "left_ptr"
|
||||
end
|
||||
|
||||
wp.focused = false
|
||||
self:emit_signal("unfocus")
|
||||
capi.awesome.emit_signal("text_input::unfocus", self)
|
||||
end
|
||||
|
||||
function text_input:toggle()
|
||||
local wp = self._private
|
||||
|
||||
if self:get_focused() == false then
|
||||
self:focus()
|
||||
else
|
||||
self:unfocus()
|
||||
end
|
||||
end
|
||||
|
||||
local function new()
|
||||
local widget = wibox.container.background()
|
||||
gtable.crush(widget, text_input, true)
|
||||
|
||||
local wp = widget._private
|
||||
|
||||
wp.focused = false
|
||||
wp.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
||||
wp.cursor_index = 0
|
||||
wp.mode = "insert"
|
||||
|
||||
wp.cursor_x = 0
|
||||
wp.cursor_y = 0
|
||||
wp.cursor_opacity = 0
|
||||
wp.selection_start_x = 0
|
||||
wp.selection_end_x = 0
|
||||
wp.selection_start_y = 0
|
||||
wp.selection_end_y = 0
|
||||
wp.selection_opacity = 0
|
||||
|
||||
wp.unfocus_keys = { "Escape", "Return" }
|
||||
wp.unfocus_on_clicked_inside = false
|
||||
wp.unfocus_on_clicked_outside = true
|
||||
wp.unfocus_on_mouse_leave = false
|
||||
wp.unfocus_on_tag_change = true
|
||||
wp.unfocus_on_other_text_input_focus = true
|
||||
|
||||
wp.focus_on_subject_mouse_enter = nil
|
||||
wp.unfocus_on_subject_mouse_leave = nil
|
||||
|
||||
wp.reset_on_unfocus = false
|
||||
|
||||
wp.placeholder = ""
|
||||
wp.text = ""
|
||||
wp.only_numbers = false
|
||||
wp.round = false
|
||||
wp.obscure = false
|
||||
|
||||
wp.cursor_width = 2
|
||||
wp.cursor_bg = beautiful.fg_normal
|
||||
wp.cursor_blink = true
|
||||
wp.cursor_blink_rate = 0.6
|
||||
|
||||
wp.selection_bg = beautiful.bg_normal
|
||||
|
||||
widget:set_widget_template(wibox.widget {
|
||||
layout = wibox.layout.stack,
|
||||
{
|
||||
widget = wibox.widget.textbox,
|
||||
id = "placeholder_role",
|
||||
text = wp.placeholder
|
||||
},
|
||||
{
|
||||
widget = wibox.widget.textbox,
|
||||
id = "text_role",
|
||||
text = wp.text
|
||||
}
|
||||
})
|
||||
|
||||
capi.tag.connect_signal("property::selected", function()
|
||||
if wp.unfocus_on_tag_change then
|
||||
widget:unfocus()
|
||||
end
|
||||
end)
|
||||
|
||||
capi.awesome.connect_signal("text_input::focus", function(text_input)
|
||||
if wp.unfocus_on_other_text_input_focus == false and text_input ~= self then
|
||||
widget:unfocus()
|
||||
end
|
||||
end)
|
||||
|
||||
return widget
|
||||
end
|
||||
|
||||
function text_input.mt:__call(...)
|
||||
return new(...)
|
||||
end
|
||||
|
||||
build_properties(text_input, properties)
|
||||
|
||||
return setmetatable(text_input, text_input.mt)
|
Loading…
Reference in New Issue