mirror of
https://codeberg.org/vyivel/dulcepan/
synced 2025-06-24 22:44:18 +03:00
Compare commits
5 Commits
9879f3ad69
...
quick-sele
Author | SHA1 | Date | |
---|---|---|---|
60518fe18e | |||
b9e94f9584 | |||
8bc62fdae4 | |||
accbd01ad6 | |||
0167c017a0 |
@ -30,4 +30,4 @@ GPL-3.0-only
|
|||||||
|
|
||||||
See `LICENSE` for more information.
|
See `LICENSE` for more information.
|
||||||
|
|
||||||
Copyright © 2024 Kirill Primak
|
Copyright © 2025 Kirill Primak
|
||||||
|
@ -33,6 +33,10 @@ animation-duration = 0
|
|||||||
# or when a whole output is selected with a mouse button.
|
# or when a whole output is selected with a mouse button.
|
||||||
quick-select = false
|
quick-select = false
|
||||||
|
|
||||||
|
# If true, dulcepan will allow editing the current selection if quick-select is
|
||||||
|
# true. Has no effect if quick-select is false.
|
||||||
|
quick-select-allow-editing = true
|
||||||
|
|
||||||
# If true, dulcepan will remember selection between runs.
|
# If true, dulcepan will remember selection between runs.
|
||||||
# The state is stored at $XDG_CACHE_HOME/dulcepan.
|
# The state is stored at $XDG_CACHE_HOME/dulcepan.
|
||||||
persistence = true
|
persistence = true
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
project(
|
project(
|
||||||
'dulcepan',
|
'dulcepan',
|
||||||
'c',
|
'c',
|
||||||
version: '1.0.2',
|
version: '1.0.3',
|
||||||
license: 'GPL-3.0-only',
|
license: 'GPL-3.0-only',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=c11',
|
'c_std=c11',
|
||||||
|
@ -125,6 +125,7 @@ void dp_config_load(struct dp_state *state, const char *user_path) {
|
|||||||
.animation_duration = 0,
|
.animation_duration = 0,
|
||||||
.png_compression = 6,
|
.png_compression = 6,
|
||||||
.quick_select = false,
|
.quick_select = false,
|
||||||
|
.quick_select_allow_editing = true,
|
||||||
.persistence = true,
|
.persistence = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -243,6 +244,8 @@ void dp_config_load(struct dp_state *state, const char *user_path) {
|
|||||||
load_int(value, line_idx, 0, 9, &config->png_compression);
|
load_int(value, line_idx, 0, 9, &config->png_compression);
|
||||||
} else if (strcmp(key, "quick-select") == 0) {
|
} else if (strcmp(key, "quick-select") == 0) {
|
||||||
load_bool(value, line_idx, &config->quick_select);
|
load_bool(value, line_idx, &config->quick_select);
|
||||||
|
} else if (strcmp(key, "quick-select-allow-editing") == 0) {
|
||||||
|
load_bool(value, line_idx, &config->quick_select_allow_editing);
|
||||||
} else if (strcmp(key, "persistence") == 0) {
|
} else if (strcmp(key, "persistence") == 0) {
|
||||||
load_bool(value, line_idx, &config->persistence);
|
load_bool(value, line_idx, &config->persistence);
|
||||||
} else if (strcmp(key, "quit-key") == 0) {
|
} else if (strcmp(key, "quit-key") == 0) {
|
||||||
|
@ -126,6 +126,14 @@ struct dp_selection {
|
|||||||
int resize_edges;
|
int resize_edges;
|
||||||
// Resize anchor
|
// Resize anchor
|
||||||
double resize_x, resize_y;
|
double resize_x, resize_y;
|
||||||
|
|
||||||
|
// Used for toggling
|
||||||
|
struct {
|
||||||
|
// If not NULL, the current output has been selected via the dedicated
|
||||||
|
// action rather than by persistent state loading or manual resizing
|
||||||
|
struct dp_output *output;
|
||||||
|
double x, y, width, height;
|
||||||
|
} last_partial;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum dp_file_format {
|
enum dp_file_format {
|
||||||
@ -163,7 +171,10 @@ struct dp_config {
|
|||||||
int animation_duration; // In milliseconds
|
int animation_duration; // In milliseconds
|
||||||
|
|
||||||
int png_compression;
|
int png_compression;
|
||||||
|
|
||||||
bool quick_select;
|
bool quick_select;
|
||||||
|
bool quick_select_allow_editing;
|
||||||
|
|
||||||
bool persistence;
|
bool persistence;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -200,6 +211,8 @@ struct dp_state {
|
|||||||
const char *output_path; // May be NULL
|
const char *output_path; // May be NULL
|
||||||
enum dp_file_format output_format;
|
enum dp_file_format output_format;
|
||||||
|
|
||||||
|
bool allow_selection_editing;
|
||||||
|
|
||||||
bool show_cursors;
|
bool show_cursors;
|
||||||
|
|
||||||
cairo_pattern_t *border_pattern;
|
cairo_pattern_t *border_pattern;
|
||||||
@ -232,7 +245,7 @@ void dp_select_stop_interactive(struct dp_selection *selection);
|
|||||||
void dp_select_notify_pointer_position(
|
void dp_select_notify_pointer_position(
|
||||||
struct dp_selection *selection, struct dp_output *output, double x, double y);
|
struct dp_selection *selection, struct dp_output *output, double x, double y);
|
||||||
|
|
||||||
void dp_select_whole(struct dp_selection *selection, struct dp_output *output);
|
void dp_select_toggle_whole(struct dp_selection *selection, struct dp_output *output);
|
||||||
|
|
||||||
void dp_save(struct dp_state *state);
|
void dp_save(struct dp_state *state);
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ static void help(const char *prog) {
|
|||||||
"\n"
|
"\n"
|
||||||
"Use the left or right mouse button to select a part of the output. A selection\n"
|
"Use the left or right mouse button to select a part of the output. A selection\n"
|
||||||
"can also be moved and resized with the left mouse button. Clicking the middle\n"
|
"can also be moved and resized with the left mouse button. Clicking the middle\n"
|
||||||
"mouse button selects the entire output.\n",
|
"mouse button toggles the selection of the entire output.\n",
|
||||||
prog);
|
prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,6 +248,9 @@ int main(int argc, char **argv) {
|
|||||||
state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||||
|
|
||||||
struct dp_config *config = &state.config;
|
struct dp_config *config = &state.config;
|
||||||
|
|
||||||
|
state.allow_selection_editing = !config->quick_select || config->quick_select_allow_editing;
|
||||||
|
|
||||||
if (config->border_gradient != DP_BORDER_GRADIENT_NONE) {
|
if (config->border_gradient != DP_BORDER_GRADIENT_NONE) {
|
||||||
state.border_pattern = cairo_pattern_create_linear(0, 0, 1, 0);
|
state.border_pattern = cairo_pattern_create_linear(0, 0, 1, 0);
|
||||||
cairo_pattern_add_color_stop_rgba(state.border_pattern, 0, config->border_color[0],
|
cairo_pattern_add_color_stop_rgba(state.border_pattern, 0, config->border_color[0],
|
||||||
|
21
src/seat.c
21
src/seat.c
@ -92,7 +92,9 @@ static const struct wl_keyboard_listener keyboard_listener = {
|
|||||||
.modifiers = keyboard_handle_modifiers,
|
.modifiers = keyboard_handle_modifiers,
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum wp_cursor_shape_device_v1_shape get_cursor_shape(struct dp_selection *selection) {
|
static enum wp_cursor_shape_device_v1_shape get_cursor_shape(struct dp_state *state) {
|
||||||
|
if (state->allow_selection_editing) {
|
||||||
|
struct dp_selection *selection = &state->selection;
|
||||||
switch (selection->action) {
|
switch (selection->action) {
|
||||||
case DP_SELECTION_ACTION_NONE:
|
case DP_SELECTION_ACTION_NONE:
|
||||||
break;
|
break;
|
||||||
@ -129,14 +131,16 @@ static enum wp_cursor_shape_device_v1_shape get_cursor_shape(struct dp_selection
|
|||||||
}
|
}
|
||||||
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE;
|
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The default cursor
|
// The default cursor
|
||||||
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR;
|
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_cursor(struct dp_seat *seat) {
|
static void update_cursor(struct dp_seat *seat) {
|
||||||
if (seat->cursor_shape_device != NULL) {
|
if (seat->cursor_shape_device != NULL) {
|
||||||
wp_cursor_shape_device_v1_set_shape(seat->cursor_shape_device, seat->pointer_serial,
|
wp_cursor_shape_device_v1_set_shape(
|
||||||
get_cursor_shape(&seat->state->selection));
|
seat->cursor_shape_device, seat->pointer_serial, get_cursor_shape(seat->state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +186,8 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uin
|
|||||||
|
|
||||||
struct dp_selection *selection = &state->selection;
|
struct dp_selection *selection = &state->selection;
|
||||||
if (button_state != WL_POINTER_BUTTON_STATE_PRESSED) {
|
if (button_state != WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||||
if (selection->width > 0 && selection->height > 0 && state->config.quick_select) {
|
if (selection->action == DP_SELECTION_ACTION_RESIZING && selection->width > 0 &&
|
||||||
|
selection->height > 0 && state->config.quick_select) {
|
||||||
state->status = DP_STATUS_SAVED;
|
state->status = DP_STATUS_SAVED;
|
||||||
}
|
}
|
||||||
dp_select_stop_interactive(selection);
|
dp_select_stop_interactive(selection);
|
||||||
@ -196,14 +201,14 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uin
|
|||||||
switch (button) {
|
switch (button) {
|
||||||
case BTN_LEFT:
|
case BTN_LEFT:
|
||||||
case BTN_RIGHT:
|
case BTN_RIGHT:
|
||||||
dp_select_start_interactive(
|
dp_select_start_interactive(selection, seat->ptr_output, seat->ptr_x, seat->ptr_y,
|
||||||
selection, seat->ptr_output, seat->ptr_x, seat->ptr_y, button == BTN_LEFT);
|
state->allow_selection_editing && button == BTN_LEFT);
|
||||||
update_cursor(seat);
|
update_cursor(seat);
|
||||||
break;
|
break;
|
||||||
case BTN_MIDDLE:
|
case BTN_MIDDLE:
|
||||||
dp_select_whole(selection, seat->ptr_output);
|
dp_select_toggle_whole(selection, seat->ptr_output);
|
||||||
|
|
||||||
// dp_select_whole() doesn't invalidate the interactive state, so do it manually
|
// Update the interaction state manually
|
||||||
dp_select_notify_pointer_position(selection, seat->ptr_output, seat->ptr_x, seat->ptr_y);
|
dp_select_notify_pointer_position(selection, seat->ptr_output, seat->ptr_x, seat->ptr_y);
|
||||||
update_cursor(seat);
|
update_cursor(seat);
|
||||||
|
|
||||||
|
48
src/select.c
48
src/select.c
@ -20,6 +20,24 @@ static void set_selected_output(struct dp_selection *selection, struct dp_output
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool has_last_partial(struct dp_selection *selection) {
|
||||||
|
return selection->last_partial.output != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void reset_last_partial(struct dp_selection *selection) {
|
||||||
|
selection->last_partial.output = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool has_partial(struct dp_selection *selection) {
|
||||||
|
struct dp_output *output = selection->output;
|
||||||
|
if (output == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selection->x != 0 || selection->y != 0 || selection->width != output->effective_width ||
|
||||||
|
selection->height != output->effective_height;
|
||||||
|
}
|
||||||
|
|
||||||
static void update_action(
|
static void update_action(
|
||||||
struct dp_selection *selection, struct dp_output *output, double x, double y) {
|
struct dp_selection *selection, struct dp_output *output, double x, double y) {
|
||||||
if (output == selection->output) {
|
if (output == selection->output) {
|
||||||
@ -161,6 +179,8 @@ void dp_select_start_interactive(struct dp_selection *selection, struct dp_outpu
|
|||||||
update_action(selection, output, x, y);
|
update_action(selection, output, x, y);
|
||||||
selection->action_active = true;
|
selection->action_active = true;
|
||||||
|
|
||||||
|
reset_last_partial(selection);
|
||||||
|
|
||||||
if (modify_existing) {
|
if (modify_existing) {
|
||||||
switch (selection->action) {
|
switch (selection->action) {
|
||||||
case DP_SELECTION_ACTION_NONE:
|
case DP_SELECTION_ACTION_NONE:
|
||||||
@ -213,13 +233,35 @@ void dp_select_notify_pointer_position(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dp_select_whole(struct dp_selection *selection, struct dp_output *output) {
|
void dp_select_toggle_whole(struct dp_selection *selection, struct dp_output *output) {
|
||||||
|
if (selection->output == output && has_last_partial(selection)) {
|
||||||
|
// Toggle the selection back to the last partial one
|
||||||
|
set_selected_output(selection, selection->last_partial.output);
|
||||||
|
|
||||||
|
selection->x = selection->last_partial.x;
|
||||||
|
selection->y = selection->last_partial.y;
|
||||||
|
selection->width = selection->last_partial.width;
|
||||||
|
selection->height = selection->last_partial.height;
|
||||||
|
|
||||||
|
reset_last_partial(selection);
|
||||||
|
} else {
|
||||||
|
// Don't save another whole output selection as partial
|
||||||
|
if (has_partial(selection) && !has_last_partial(selection)) {
|
||||||
|
selection->last_partial.output = selection->output;
|
||||||
|
|
||||||
|
selection->last_partial.x = selection->x;
|
||||||
|
selection->last_partial.y = selection->y;
|
||||||
|
selection->last_partial.width = selection->width;
|
||||||
|
selection->last_partial.height = selection->height;
|
||||||
|
}
|
||||||
|
|
||||||
set_selected_output(selection, output);
|
set_selected_output(selection, output);
|
||||||
|
|
||||||
selection->x = 0;
|
selection->x = 0;
|
||||||
selection->y = 0;
|
selection->y = 0;
|
||||||
selection->width = output->effective_width;
|
selection->width = output->effective_width;
|
||||||
selection->height = output->effective_height;
|
selection->height = output->effective_height;
|
||||||
|
}
|
||||||
dp_output_redraw(output);
|
|
||||||
|
dp_output_redraw(selection->output);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user