Skip to content

Commit

Permalink
Added mode indicator (talonhub#1194)
Browse files Browse the repository at this point in the history
Will show different colors for sleep, dictation, mixed, command/other
modes
<img width="30" alt="Screenshot 2023-05-13T18-04-21"
src="https://github.com/knausj85/knausj_talon/assets/3511326/5b6007b6-18fd-4bc5-a91d-7c2747a0c16b">

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Michael Arntzenius <[email protected]>
Co-authored-by: Phil Cohen <[email protected]>
  • Loading branch information
4 people authored and MartinRykfors committed Jul 4, 2023
1 parent b77475f commit 94f1992
Show file tree
Hide file tree
Showing 8 changed files with 249 additions and 0 deletions.
34 changes: 34 additions & 0 deletions plugin/mode_indicator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Mode indicator

Graphical indicator to show you which Talon mode your currently are in. Supports a lot of settings to move, resize and change colors.

## Default colors

Command mode

![Command mode](./images/command.png)

Dictation mode

![Dictation mode](./images/dictation.png)

Mixed mode

![Mixed mode](./images/mixed.png)

Sleep mode

![Sleep mode](./images/sleep.png)

Other modes

![Others mode](./images/other.png)

## Usage

You can enable this by changing the following setting in `mode_indicator.talon`:
`user.mode_indicator_show = 1`

## Demo

[YouTube - Mode indicator demo](https://youtu.be/1lqtfM4vvH4)
Binary file added plugin/mode_indicator/images/command.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plugin/mode_indicator/images/dictation.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plugin/mode_indicator/images/mixed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plugin/mode_indicator/images/other.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plugin/mode_indicator/images/sleep.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
192 changes: 192 additions & 0 deletions plugin/mode_indicator/mode_indicator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
from talon import Module, app, registry, scope, skia, ui
from talon.canvas import Canvas
from talon.screen import Screen
from talon.skia.canvas import Canvas as SkiaCanvas
from talon.skia.imagefilter import ImageFilter
from talon.ui import Rect

canvas: Canvas = None
current_mode = ""
mod = Module()

setting_show = mod.setting(
"mode_indicator_show",
bool,
desc="If true the mode indicator is shown",
default=False,
)
setting_size = mod.setting(
"mode_indicator_size",
float,
desc="Mode indicator diameter in pixels",
)
setting_x = mod.setting(
"mode_indicator_x",
float,
desc="Mode indicator center X-position in percentages(0-1). 0=left, 1=right",
)
setting_y = mod.setting(
"mode_indicator_y",
float,
desc="Mode indicator center Y-position in percentages(0-1). 0=top, 1=bottom",
)
setting_color_alpha = mod.setting(
"mode_indicator_color_alpha",
float,
desc="Mode indicator alpha/opacity in percentages(0-1). 0=fully transparent, 1=fully opaque",
)
setting_color_gradient = mod.setting(
"mode_indicator_color_gradient",
float,
desc="Mode indicator gradient brightness in percentages(0-1). 0=darkest, 1=brightest",
)
setting_color_sleep = mod.setting("mode_indicator_color_sleep", str)
setting_color_dictation = mod.setting("mode_indicator_color_dictation", str)
setting_color_mixed = mod.setting("mode_indicator_color_mixed", str)
setting_color_command = mod.setting("mode_indicator_color_command", str)
setting_color_other = mod.setting("mode_indicator_color_other", str)

setting_paths = {
s.path
for s in [
setting_show,
setting_size,
setting_x,
setting_y,
setting_color_alpha,
setting_color_gradient,
setting_color_sleep,
setting_color_dictation,
setting_color_mixed,
setting_color_command,
setting_color_other,
]
}


def get_mode_color() -> str:
if current_mode == "sleep":
return setting_color_sleep.get()
elif current_mode == "dictation":
return setting_color_dictation.get()
elif current_mode == "mixed":
return setting_color_mixed.get()
elif current_mode == "command":
return setting_color_command.get()
else:
return setting_color_other.get()


def get_alpha_color() -> str:
return f"{int(setting_color_alpha.get() * 255):02x}"


def get_gradient_color(color: str) -> str:
factor = setting_color_gradient.get()
# hex -> rgb
(r, g, b) = tuple(int(color[i : i + 2], 16) for i in (0, 2, 4))
# Darken rgb
r, g, b = int(r * factor), int(g * factor), int(b * factor)
# rgb -> hex
return f"{r:02x}{g:02x}{b:02x}"


def get_colors():
color_mode = get_mode_color()
color_gradient = get_gradient_color(color_mode)
color_alpha = get_alpha_color()
return f"{color_mode}{color_alpha}", f"{color_gradient}"


def on_draw(c: SkiaCanvas):
color_mode, color_gradient = get_colors()
x, y = c.rect.center.x, c.rect.center.y
radius = c.rect.height / 2 - 2

c.paint.shader = skia.Shader.radial_gradient(
(x, y), radius, [color_mode, color_gradient]
)

c.paint.imagefilter = ImageFilter.drop_shadow(1, 1, 1, 1, color_gradient)

c.paint.style = c.paint.Style.FILL
c.paint.color = color_mode
c.draw_circle(x, y, radius)


def move_indicator():
screen: Screen = ui.main_screen()
rect = screen.rect
scale = screen.scale if app.platform != "mac" else 1
radius = setting_size.get() * scale / 2

x = rect.left + min(
max(setting_x.get() * rect.width - radius, 0),
rect.width - 2 * radius,
)

y = rect.top + min(
max(setting_y.get() * rect.height - radius, 0),
rect.height - 2 * radius,
)

side = 2 * radius
canvas.resize(side, side)
canvas.move(x, y)


def show_indicator():
global canvas
canvas = Canvas.from_rect(Rect(0, 0, 0, 0))
canvas.register("draw", on_draw)


def hide_indicator():
global canvas
canvas.unregister("draw", on_draw)
canvas.close()
canvas = None


def update_indicator():
if setting_show.get():
if not canvas:
show_indicator()
move_indicator()
canvas.freeze()
elif canvas:
hide_indicator()


def on_update_contexts():
global current_mode
modes = scope.get("mode")
if "sleep" in modes:
mode = "sleep"
elif "dictation" in modes:
if "command" in modes:
mode = "mixed"
else:
mode = "dictation"
elif "command" in modes:
mode = "command"
else:
mode = "other"

if current_mode != mode:
current_mode = mode
update_indicator()


def on_update_settings(updated_settings: set[str]):
if setting_paths & updated_settings:
update_indicator()


def on_ready():
registry.register("update_contexts", on_update_contexts)
registry.register("update_settings", on_update_settings)
ui.register("screen_change", lambda _: update_indicator)


app.register("ready", on_ready)
23 changes: 23 additions & 0 deletions plugin/mode_indicator/mode_indicator.talon
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
settings():
# Don't show mode indicator by default
user.mode_indicator_show = 0
# 30pixels diameter
user.mode_indicator_size = 30
# Center horizontally
user.mode_indicator_x = 0.5
# Align top
user.mode_indicator_y = 0
# Slightly transparent
user.mode_indicator_color_alpha = 0.75
# Grey gradient
user.mode_indicator_color_gradient = 0.5
# Grey color for sleep mode
user.mode_indicator_color_sleep = "808080"
# Gold color for dictation mode
user.mode_indicator_color_dictation = "ffd700"
# MediumSeaGreen color for mixed mode
user.mode_indicator_color_mixed = "3cb371"
# CornflowerBlue color for command mode
user.mode_indicator_color_command = "6495ed"
# GhostWhite color for other modes
user.mode_indicator_color_other = "f8f8ff"

0 comments on commit 94f1992

Please sign in to comment.