Skip to content

Commit

Permalink
Add theming to hide text cursor if no text is put in (#2106)
Browse files Browse the repository at this point in the history
* Add theming to hide text cursor if no text is put in

* rename "hide-empty-cursor" to "hide-cursor-on-empty"

* update docs
  • Loading branch information
J0hannes101 authored Feb 25, 2025
1 parent 22a0e39 commit e70e390
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 46 deletions.
9 changes: 6 additions & 3 deletions doc/rofi-theme.5.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -132,18 +132,18 @@ element-text {
└─────────────────────────────────────────────────────────────────────┘
```

We can also specify the color and width of the cursor. You could, for example,
create a crimson block cursor like this:
We can also customize the cursor's color, width, and choose to hide it when the input box is empty. You could, for example, create a crimson block cursor that only appears when text is entered, like this:

```css
entry {
cursor-color: rgb(220,20,60);
cursor-width: 8px;
hide-cursor-on-empty: true;
}
```

By default, the `cursor-color` will be the same as the `text-color`. The
`cursor-width` will always default to 2 pixels.
`cursor-width` will always default to 2 pixels and `hide-cursor-on-empty` is set to false.

If you want to see the complete theme, including the modification you can run:

Expand Down Expand Up @@ -1068,6 +1068,9 @@ The following properties are currently supported:

- **cursor-color**: The color used to draw the cursor.

- **hide-cursor-on-empty**: Hides the cursor when the search field is empty.
(Boolean)

- **cursor-outline**: Enable a border (outline) around the cursor.
(Boolean)

Expand Down
89 changes: 46 additions & 43 deletions source/widgets/textbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -552,51 +552,54 @@ static void textbox_draw(widget *wid, cairo_t *draw) {
if (tb->flags & TB_EDITABLE) {
// We want to place the cursor based on the text shown.
const char *text = pango_layout_get_text(tb->layout);
// Clamp the position, should not be needed, but we are paranoid.
size_t cursor_offset;

if ((tb->flags & TB_PASSWORD) == TB_PASSWORD) {
// Calculate cursor position based on mask length
size_t mask_len = strlen(tb->password_mask_char);
cursor_offset = MIN(tb->cursor * mask_len, strlen(text));
} else {
cursor_offset = MIN(tb->cursor, g_utf8_strlen(text, -1));
// convert to byte location.
char *offset = g_utf8_offset_to_pointer(text, cursor_offset);
cursor_offset = offset - text;
}
PangoRectangle pos;
pango_layout_get_cursor_pos(tb->layout, cursor_offset, &pos, NULL);
int cursor_x = pos.x / PANGO_SCALE;
int cursor_y = pos.y / PANGO_SCALE;
int cursor_height = pos.height / PANGO_SCALE;
RofiDistance cursor_width =
rofi_theme_get_distance(WIDGET(tb), "cursor-width", 2);
int cursor_pixel_width =
distance_get_pixel(cursor_width, ROFI_ORIENTATION_HORIZONTAL);
if ((x + cursor_x) != tb->cursor_x_pos) {
tb->cursor_x_pos = x + cursor_x;
}
if (tb->blink) {
// This save/restore state is necessary to render the text in the
// correct color when `cursor-color` is set
cairo_save(draw);
// use text color as fallback for themes that don't specify the cursor
// color
rofi_theme_get_color(WIDGET(tb), "cursor-color", draw);
cairo_rectangle(draw, x + cursor_x, y + cursor_y, cursor_pixel_width,
cursor_height);
if (rofi_theme_get_boolean(WIDGET(tb), "cursor-outline", FALSE)) {
cairo_fill_preserve(draw);
rofi_theme_get_color(WIDGET(tb), "cursor-outline-color", draw);
double width =
rofi_theme_get_double(WIDGET(tb), "cursor-outline-width", 0.5);
cairo_set_line_width(draw, width);
cairo_stroke(draw);
// hide the cursor, if no text is entered and hide-empty-cursor is set to true
if (!(tb->text[0] == '\0' && rofi_theme_get_boolean(WIDGET(tb), "hide-cursor-on-empty", FALSE) == TRUE)){
// Clamp the position, should not be needed, but we are paranoid.
size_t cursor_offset;

if ((tb->flags & TB_PASSWORD) == TB_PASSWORD) {
// Calculate cursor position based on mask length
size_t mask_len = strlen(tb->password_mask_char);
cursor_offset = MIN(tb->cursor * mask_len, strlen(text));
} else {
cairo_fill(draw);
cursor_offset = MIN(tb->cursor, g_utf8_strlen(text, -1));
// convert to byte location.
char *offset = g_utf8_offset_to_pointer(text, cursor_offset);
cursor_offset = offset - text;
}
PangoRectangle pos;
pango_layout_get_cursor_pos(tb->layout, cursor_offset, &pos, NULL);
int cursor_x = pos.x / PANGO_SCALE;
int cursor_y = pos.y / PANGO_SCALE;
int cursor_height = pos.height / PANGO_SCALE;
RofiDistance cursor_width =
rofi_theme_get_distance(WIDGET(tb), "cursor-width", 2);
int cursor_pixel_width =
distance_get_pixel(cursor_width, ROFI_ORIENTATION_HORIZONTAL);
if ((x + cursor_x) != tb->cursor_x_pos) {
tb->cursor_x_pos = x + cursor_x;
}
if (tb->blink) {
// This save/restore state is necessary to render the text in the
// correct color when `cursor-color` is set
cairo_save(draw);
// use text color as fallback for themes that don't specify the cursor
// color
rofi_theme_get_color(WIDGET(tb), "cursor-color", draw);
cairo_rectangle(draw, x + cursor_x, y + cursor_y, cursor_pixel_width,
cursor_height);
if (rofi_theme_get_boolean(WIDGET(tb), "cursor-outline", FALSE)) {
cairo_fill_preserve(draw);
rofi_theme_get_color(WIDGET(tb), "cursor-outline-color", draw);
double width =
rofi_theme_get_double(WIDGET(tb), "cursor-outline-width", 0.5);
cairo_set_line_width(draw, width);
cairo_stroke(draw);
} else {
cairo_fill(draw);
}
cairo_restore(draw);
}
cairo_restore(draw);
}
}

Expand Down

0 comments on commit e70e390

Please sign in to comment.