diff --git a/include/slurp.h b/include/slurp.h index f370103..1de5e80 100644 --- a/include/slurp.h +++ b/include/slurp.h @@ -12,6 +12,14 @@ #define TOUCH_ID_EMPTY -1 +enum slurp_label_anchor { + ANCHOR_NONE = 0, + ANCHOR_TOP = 1, + ANCHOR_BOTTOM = 2, + ANCHOR_LEFT = 4, + ANCHOR_RIGHT = 8, +}; + struct slurp_box { int32_t x, y; int32_t width, height; @@ -48,6 +56,8 @@ struct slurp_state { uint32_t border; uint32_t selection; uint32_t choice; + uint32_t label_text; + uint32_t label_background; } colors; const char *font_family; @@ -60,6 +70,7 @@ struct slurp_state { struct wl_list boxes; // slurp_box::link bool fixed_aspect_ratio; double aspect_ratio; // h / w + enum slurp_label_anchor label_anchor; struct slurp_box result; }; diff --git a/main.c b/main.c index e326ecd..deb9bba 100644 --- a/main.c +++ b/main.c @@ -17,6 +17,8 @@ #define BG_COLOR 0xFFFFFF40 #define BORDER_COLOR 0x000000FF #define SELECTION_COLOR 0x00000000 +#define LABEL_COLOR 0xFFFFFFFF +#define LABEL_BG_COLOR 0x000000FF #define FONT_FAMILY "sans-serif" static void noop() { @@ -719,13 +721,16 @@ static const char usage[] = " -c #rrggbbaa Set border color.\n" " -s #rrggbbaa Set selection color.\n" " -B #rrggbbaa Set option box color.\n" + " -l #rrggbbaa Set label text color.\n" + " -L #rrggbbaa Set label background color.\n" " -F s Set the font family for the dimensions.\n" " -w n Set border weight.\n" " -f s Set output format.\n" " -o Select a display output.\n" " -p Select a single point.\n" " -r Restrict selection to predefined boxes.\n" - " -a w:h Force aspect ratio.\n"; + " -a w:h Force aspect ratio.\n" + " -P Position labels on the option boxes.\n"; uint32_t parse_color(const char *color) { if (color[0] == '#') { @@ -745,6 +750,27 @@ uint32_t parse_color(const char *color) { return res; } + +enum slurp_label_anchor parse_label_anchor(const char *anchor) { + enum slurp_label_anchor label_anchor = ANCHOR_NONE; + if (strstr(anchor, "top") != NULL) { + label_anchor |= ANCHOR_TOP; + } + if (strstr(anchor, "bottom") != NULL) { + label_anchor |= ANCHOR_BOTTOM; + } + if (strstr(anchor, "left") != NULL) { + label_anchor |= ANCHOR_LEFT; + } + if (strstr(anchor, "right") != NULL) { + label_anchor |= ANCHOR_RIGHT; + } + if (strstr(anchor, "center") != NULL) { + label_anchor |= ANCHOR_TOP | ANCHOR_BOTTOM | ANCHOR_LEFT | ANCHOR_RIGHT; + } + return label_anchor; +} + static struct slurp_output *output_from_box(const struct slurp_box *box, struct wl_list *outputs) { struct slurp_output *output; wl_list_for_each(output, outputs, link) { @@ -887,6 +913,8 @@ int main(int argc, char *argv[]) { .border = BORDER_COLOR, .selection = SELECTION_COLOR, .choice = BG_COLOR, + .label_text = LABEL_COLOR, + .label_background = LABEL_BG_COLOR, }, .border_weight = 2, .display_dimensions = false, @@ -894,14 +922,15 @@ int main(int argc, char *argv[]) { .resizing_selection = false, .fixed_aspect_ratio = false, .aspect_ratio = 0, - .font_family = FONT_FAMILY + .font_family = FONT_FAMILY, + .label_anchor = ANCHOR_NONE }; int opt; char *format = "%x,%y %wx%h\n"; bool output_boxes = false; int w, h; - while ((opt = getopt(argc, argv, "hdb:c:s:B:w:proa:f:F:")) != -1) { + while ((opt = getopt(argc, argv, "hdb:c:s:B:l:L:w:proa:f:F:P:")) != -1) { switch (opt) { case 'h': printf("%s", usage); @@ -921,12 +950,21 @@ int main(int argc, char *argv[]) { case 'B': state.colors.choice = parse_color(optarg); break; + case 'l': + state.colors.label_text = parse_color(optarg); + break; + case 'L': + state.colors.label_background = parse_color(optarg); + break; case 'f': format = optarg; break; case 'F': state.font_family = optarg; break; + case 'P': + state.label_anchor = parse_label_anchor(optarg); + break; case 'w': { errno = 0; char *endptr; diff --git a/meson.build b/meson.build index 6b28156..888f025 100644 --- a/meson.build +++ b/meson.build @@ -12,6 +12,7 @@ add_project_arguments('-Wno-unused-parameter', language: 'c') cc = meson.get_compiler('c') cairo = dependency('cairo') +math = cc.find_library('m') realtime = cc.find_library('rt') wayland_client = dependency('wayland-client') wayland_cursor = dependency('wayland-cursor') @@ -30,6 +31,7 @@ executable( ], dependencies: [ cairo, + math, realtime, wayland_client, wayland_cursor, diff --git a/render.c b/render.c index d91f8a3..63c5de9 100644 --- a/render.c +++ b/render.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -6,6 +7,10 @@ #include "render.h" #include "slurp.h" +#define LABEL_BOX_PADDING 10 +#define LABEL_HORIZONTAL_MARGING 10 +#define LABEL_VERTICAL_MARGING 20 + static void set_source_u32(cairo_t *cairo, uint32_t color) { cairo_set_source_rgba(cairo, (color >> (3 * 8) & 0xFF) / 255.0, (color >> (2 * 8) & 0xFF) / 255.0, @@ -19,6 +24,45 @@ static void draw_rect(cairo_t *cairo, struct slurp_box *box, uint32_t color) { box->width, box->height); } +static void draw_rect_label(cairo_t *cairo, struct slurp_box *box, enum slurp_label_anchor anchor, + uint32_t text_color, uint32_t background_color, const char *font_family, const char *text) { + if (anchor == ANCHOR_NONE) + return; + cairo_select_font_face(cairo, font_family, + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(cairo, 20); + cairo_text_extents_t extents; + cairo_text_extents(cairo, text, &extents); + struct slurp_box labelbox = { 0 }; + labelbox.width = ceil(extents.width) + 2*LABEL_BOX_PADDING; + labelbox.height = ceil(extents.height) + 2*LABEL_BOX_PADDING; + labelbox.x = box->x + (box->width - labelbox.width) / 2; + labelbox.y = box->y + (box->height - labelbox.height) / 2; + + if (anchor & ANCHOR_TOP && anchor & ANCHOR_BOTTOM) { + // Nothing to do + } else if (anchor & ANCHOR_TOP) { + labelbox.y = box->y + LABEL_VERTICAL_MARGING; + } else if (anchor & ANCHOR_BOTTOM) { + labelbox.y = box->y + box->height - LABEL_VERTICAL_MARGING - labelbox.height; + } + if (anchor & ANCHOR_LEFT && anchor & ANCHOR_RIGHT) { + // Nothing to do + } else if (anchor & ANCHOR_LEFT) { + labelbox.x = box->x + LABEL_HORIZONTAL_MARGING; + } else if (anchor & ANCHOR_RIGHT) { + labelbox.x = box->x + box->width - LABEL_HORIZONTAL_MARGING - labelbox.width; + } + + draw_rect(cairo, &labelbox, background_color); + cairo_fill(cairo); + set_source_u32(cairo, text_color); + cairo_move_to(cairo, labelbox.x + LABEL_BOX_PADDING, + labelbox.y + LABEL_BOX_PADDING + ceil(extents.height)); + cairo_show_text(cairo, text); +} + static void box_layout_to_output(struct slurp_box *box, struct slurp_output *output) { box->x -= output->logical_geometry.x; box->y -= output->logical_geometry.y; @@ -43,6 +87,9 @@ void render(struct slurp_output *output) { box_layout_to_output(&b, output); draw_rect(cairo, &b, state->colors.choice); cairo_fill(cairo); + if (b.label) + draw_rect_label(cairo, &b, state->label_anchor, + state->colors.label_text, state->colors.label_background, state->font_family, b.label); } } @@ -64,6 +111,9 @@ void render(struct slurp_output *output) { draw_rect(cairo, &b, state->colors.selection); cairo_fill(cairo); + if (b.label) + draw_rect_label(cairo, &b, state->label_anchor, + state->colors.label_text, state->colors.label_background, state->font_family, b.label); // Draw border cairo_set_line_width(cairo, state->border_weight); diff --git a/slurp.1.scd b/slurp.1.scd index fdb6dea..988f5a3 100644 --- a/slurp.1.scd +++ b/slurp.1.scd @@ -44,6 +44,12 @@ held, the selection is moved instead of being resized. Set color for highlighting predefined rectangles from standard input when not selected. Default is #FFFFFF40. +*-l* _color_ + Set text color for labels. See *COLORS* for more detail. + +*-L* _color_ + Set background color for labels. See *COLORS* for more detail. + *-F* _font family_ Set the font family name when displaying the dimensions box. Only useful when combined with the -d option. The available font family names guaranteed @@ -56,6 +62,9 @@ held, the selection is moved instead of being resized. *-f* _format_ Set format. See *FORMAT* for more detail. +*-P* _anchor_ + Set postion anchor for the labels. See *ANCHOR* for more detail. + *-p* Select a single pixel instead of a rectangle. This mode ignores any predefined rectangles read from the standard input. @@ -108,6 +117,15 @@ Interpreted sequences are: The default format is "%x,%y %wx%h\\n". +# ANCHOR + +Valid values are: + +none, top, bottom, left, right, center + +Combinations of these keywords chained together are possible, eg. top-right to +position the label in the top right corner. + # KEYBOARD CONTROLS The following keyboard actions can be used during selection: