Skip to content

Commit

Permalink
Add support for custom info text scheme
Browse files Browse the repository at this point in the history
Modes can be specified in config file.

Resolves #77.

Signed-off-by: Artem Senichev <[email protected]>
  • Loading branch information
artemsen committed Dec 28, 2023
1 parent d692f73 commit 2e52b29
Show file tree
Hide file tree
Showing 15 changed files with 834 additions and 279 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Default key bindings can be overridden using a configuration file.
| `F6` or `]` | Rotate 90 degrees clockwise |
| `F7` | Flip vertical |
| `F8` | Flip horizontal |
| `i` | Show/hide image properties |
| `i` | Switch text info mode |
| `F11` or `f` | Toggle full screen mode |
| `PgDown`, `Space`, or `n` | Open next file |
| `PgUp` or `p` | Open previous file |
Expand Down
2 changes: 1 addition & 1 deletion extra/swayimg.1
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Flip vertical.
.IP "\fBF8\fP"
Flip horizontal.
.IP "\fBi\fP"
Show/hide image properties.
Switch text info mode.
.IP "\fBf\fP, \fBF11\fP"
Toggle full screen mode.
.IP "\fBPgDown\fR, \fBSpace\fR, \fBn\fR"
Expand Down
20 changes: 17 additions & 3 deletions extra/swayimgrc
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ wndpos = parent
# Window size (parent, image, or absolute size, e.g. 800,600)
wndsize = parent

# Show image info: format, size, EXIF, and current scale (yes/no)
info = no

# Slideshow image duration (seconds)
slideshow = 3

Expand Down Expand Up @@ -70,6 +67,23 @@ size = 14
# Font color
color = #cccccc

################################################################################
# Image meta info scheme (format, size, EXIF, etc)
################################################################################
[info]
# Mode on startup (off/brief/full)
mode = full
# Display scheme for the "full" mode: position = content
full.topleft = name,format,filesize,imagesize,exif
full.topright = index
full.bottomleft = scale,frame
full.bottomright = status
# Display scheme for the "brief" mode: position = content
brief.topleft = index
brief.topright = none
brief.bottomleft = none
brief.bottomright = status

################################################################################
# Key binding section: key = action [parameters]
# Use the `xkbcli` tool to get key name: `xkbcli interactive-wayland`
Expand Down
32 changes: 27 additions & 5 deletions extra/swayimgrc.5
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,28 @@ The font configuration is described in the "font" section.
.IP "\fBname\fR: font name used for printing text, default is \fImonospace\fR;"
.IP "\fBsize\fR: font size (in pt), default is \fI14\fR;"
.IP "\fBcolor\fR: color in RGB hex format, default is \fI#cccccc\fR;"
.SS [info] section: text info layout
.IP "\fBmode\fR: startup mode, \fIoff\fR, \fIbrief\fR, or [\fIfull\fR];"
.IP "\fBfull.topleft\fR: comma delimited list of content for the \fIfull\fR mode, top left corner of the window:"
.nf
\fIname\fR: file name;
\fIpath\fR: full path;
\fIfilesize\fR: file size;
\fIformat\fR: image format;
\fIimagesize\fR: image size;
\fIexif\fR: EXIF data;
\fIframe\fR: current/total frame index;
\fIindex\fR: current/total file index;
\fIscale\fR: current scale in percent;
\fIstatus\fR: status message;
\fInone\fR: empty field (ignored);
.IP "\fBfull.topright\fR: \fIfull\fR mode, top right corner of the window;"
.IP "\fBfull.bottomleft\fR: \fIfull\fR mode, bottom left corner of the window;"
.IP "\fBfull.bottomright\fR: \fIfull\fR mode, bottom right corner of the window;"
.IP "\fBbrief.topleft\fR: \fIbrief\fR mode, top right corner of the window;"
.IP "\fBbrief.topright\fR: \fIbrief\fR mode, top right corner of the window;"
.IP "\fBbrief.bottomleft\fR: \fIbrief\fR mode, bottom left corner of the window;"
.IP "\fBbrief.bottomright\fR: \fIbrief\fR mode, bottom right corner of the window;"
.SS [keys]: key bindins
.PP
The key bindings are described in the "keys" section.
Expand All @@ -92,10 +114,10 @@ Valid action are:
.IP "\fBanimation\fR: start/stop animation;"
.IP "\fBslideshow\fR: start/stop slideshow;"
.IP "\fBfullscreen\fR: switch fullscreen mode;"
.IP "\fBstep_left \fI[PERCENT]\fR\fR: move viewport left, default is 10%;"
.IP "\fBstep_right \fI[PERCENT]\fR\fR: move viewport right, default is 10%;"
.IP "\fBstep_up \fI[PERCENT]\fR\fR: move viewport up, default is 10%;"
.IP "\fBstep_down \fI[PERCENT]\fR\fR: move viewport down, default is 10%;"
.IP "\fBstep_left\fR \fI[PERCENT]\fR: move viewport left, default is 10%;"
.IP "\fBstep_right\fR \fI[PERCENT]\fR: move viewport right, default is 10%;"
.IP "\fBstep_up\fR \fI[PERCENT]\fR: move viewport up, default is 10%;"
.IP "\fBstep_down\fR \fI[PERCENT]\fR: move viewport down, default is 10%;"
.IP "\fBzoom_in\fR \fI[PERCENT]\fR: zoom in, by default increases scale by 10%;"
.IP "\fBzoom_out\fR \fI[PERCENT]\fR: zoom out, by default decreases scale by 10%;"
.IP "\fBzoom_optimal\fR: set to optimal zoom (100% or less to fit to window);"
Expand All @@ -109,7 +131,7 @@ Valid action are:
.IP "\fBflip_horizontal\fR: flip image horizontally;"
.IP "\fBreload\fR: reset cache and reload current image;"
.IP "\fBantialiasing\fR: switch antialiasing (bicubic interpolation);"
.IP "\fBinfo\fR: show/hide image info;"
.IP "\fBinfo\fR \fI[MODE]\fR: switch text info mode or set specified one (\fIoff\fR/\fIbrief\fR/\fIfull\fR);"
.IP "\fBexec\fR \fICOMMAND\fR: execute an external command, use % to substitute the path to the current image, %% to escape %;"
.IP "\fBquit\fR: quit the application."
.\" example file
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ sources = [
'src/font.c',
'src/image.c',
'src/imagelist.c',
'src/info.c',
'src/keybind.c',
'src/main.c',
'src/sway.c',
Expand Down
120 changes: 74 additions & 46 deletions src/canvas.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,61 +300,89 @@ void canvas_draw_image(bool alpha, const argb_t* img, argb_t* wnd)
}
}

void canvas_print_line(argb_t* wnd, enum canvas_corner corner, const char* text)
void canvas_print(const struct info_line* lines, size_t lines_num,
enum info_position pos, argb_t* wnd)
{
struct point pos = { 0, 0 };
size_t max_key_width = 0;
const size_t height = font_height();

switch (corner) {
case cc_top_right:
pos.x = ctx.window.width - font_print(NULL, NULL, NULL, text, 0) -
TEXT_PADDING;
pos.y = TEXT_PADDING;
break;
case cc_bottom_left:
pos.x = TEXT_PADDING;
pos.y = ctx.window.height - font_height() - TEXT_PADDING;
break;
case cc_bottom_right:
pos.x = ctx.window.width - font_print(NULL, NULL, NULL, text, 0) -
TEXT_PADDING;
pos.y = ctx.window.height - font_height() - TEXT_PADDING;
break;
// calc max width of keys
for (size_t i = 0; i < lines_num; ++i) {
const wchar_t* key = lines[i].key;
if (key && *key) {
const size_t width = font_print(NULL, NULL, NULL, key) +
font_print(NULL, NULL, NULL, L": ");
if (width > max_key_width) {
max_key_width = width;
}
}
}

font_print(wnd, &ctx.window, &pos, text, 0);
}
// draw info block
for (size_t i = 0; i < lines_num; ++i) {
const wchar_t* key = lines[i].key;
const wchar_t* val = lines[i].value;
size_t key_width = font_print(NULL, NULL, NULL, key);
const size_t val_width = font_print(NULL, NULL, NULL, val);

void canvas_print_info(argb_t* wnd, size_t num, const struct info_table* info)
{
size_t val_offset = 0;
struct point pos = { .x = TEXT_PADDING, .y = TEXT_PADDING };
struct point pt_key = { 0, 0 };
struct point pt_val = { 0, 0 };

// draw keys block
for (size_t i = 0; i < num; ++i) {
const char* key = info[i].key;
if (key && *key) {
size_t width;
struct point pos_delim;
width = font_print(wnd, &ctx.window, &pos, key, 0);
pos_delim.x = TEXT_PADDING + width;
pos_delim.y = pos.y;
width += font_print(wnd, &ctx.window, &pos_delim, ":", 0) * 3;
if (width > val_offset) {
val_offset = width;
}
if (key_width) {
key_width += font_print(NULL, NULL, NULL, L": ");
}

// calculate line position
switch (pos) {
case info_top_left:
if (key_width) {
pt_key.x = TEXT_PADDING;
pt_key.y = TEXT_PADDING + i * height;
pt_val.x = TEXT_PADDING + max_key_width;
pt_val.y = pt_key.y;
} else {
pt_val.x = TEXT_PADDING;
pt_val.y = TEXT_PADDING + i * height;
}
break;
case info_top_right:
pt_val.x = ctx.window.width - TEXT_PADDING - val_width;
pt_val.y = TEXT_PADDING + i * height;
if (key_width) {
pt_key.x = pt_val.x - key_width;
pt_key.y = pt_val.y;
}
break;
case info_bottom_left:
if (key_width) {
pt_key.x = TEXT_PADDING;
pt_key.y = ctx.window.height - TEXT_PADDING -
height * lines_num + i * height;
pt_val.x = TEXT_PADDING + max_key_width;
pt_val.y = pt_key.y;
} else {
pt_val.x = TEXT_PADDING;
pt_val.y = ctx.window.height - TEXT_PADDING -
height * lines_num + i * height;
}
break;
case info_bottom_right:
pt_val.x = ctx.window.width - TEXT_PADDING - val_width;
pt_val.y = TEXT_PADDING + i * height;
pt_val.y = ctx.window.height - TEXT_PADDING -
height * lines_num + i * height;
if (key_width) {
pt_key.x = pt_val.x - key_width;
pt_key.y = pt_val.y;
}
break;
}
pos.y += font_height();
}

// draw values block
pos.x = TEXT_PADDING + val_offset + TEXT_PADDING;
pos.y = TEXT_PADDING;
for (size_t i = 0; i < num; ++i) {
const char* value = info[i].value;
if (value && *value) {
font_print(wnd, &ctx.window, &pos, value, 0);
if (key_width) {
pt_key.x += font_print(wnd, &ctx.window, &pt_key, key);
font_print(wnd, &ctx.window, &pt_key, L": ");
}
pos.y += font_height();
font_print(wnd, &ctx.window, &pt_val, val);
}
}

Expand Down
29 changes: 7 additions & 22 deletions src/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#pragma once

#include "info.h"
#include "types.h"

/** Scaling operations. */
Expand All @@ -14,15 +15,6 @@ enum canvas_scale {
cs_real_size, ///< Real image size (100%)
};

/** Corner position. */
enum canvas_corner { cc_top_right, cc_bottom_left, cc_bottom_right };

/** Meta data info table. */
struct info_table {
const char* key;
const char* value;
};

/**
* Reset window parameters.
* @param width,height new window size
Expand Down Expand Up @@ -58,21 +50,14 @@ void canvas_clear(argb_t* wnd);
void canvas_draw_image(bool aplha, const argb_t* img, argb_t* wnd);

/**
* Print text line on canvas.
* @param wnd window buffer
* @param corner text block position
* @param text printed text
*/
void canvas_print_line(argb_t* wnd, enum canvas_corner corner,
const char* text);

/**
* Print meta info table on the left top corner.
* @param wnd window buffer
* Print information text block.
* @param line array of lines to pprint
* @param num total number of lines
* @param info meta data table to print
* @param pos block position
* @param wnd window buffer
*/
void canvas_print_info(argb_t* wnd, size_t num, const struct info_table* info);
void canvas_print(const struct info_line* lines, size_t lines_num,
enum info_position pos, argb_t* wnd);

/**
* Move viewport.
Expand Down
53 changes: 48 additions & 5 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct config_section {
const char* name;
config_loader loader;
};
static struct config_section sections[4];
static struct config_section sections[5];

static const struct location config_locations[] = {
{ "XDG_CONFIG_HOME", "/swayimg/config" },
Expand Down Expand Up @@ -183,10 +183,6 @@ static enum config_status load_general(const char* key, const char* value)
status = cfgst_ok;
}
}
} else if (strcmp(key, "info") == 0) {
if (config_parse_bool(value, &config.show_info)) {
status = cfgst_ok;
}
} else if (strcmp(key, "slideshow") == 0) {
ssize_t num;
if (config_parse_num(value, &num, 0) && num != 0) {
Expand Down Expand Up @@ -484,3 +480,50 @@ bool config_parse_color(const char* text, argb_t* color)

return false;
}

size_t config_parse_tokens(const char* text, char delimeter,
struct config_token* tokens, size_t max_tokens)
{
size_t token_num = 0;

while (*text) {
struct config_token token;

// skip spaces
while (*text && isspace(*text)) {
++text;
}
if (!*text) {
break;
}

// construct token
if (*text == delimeter) {
// empty token
token.value = "";
token.len = 0;
} else {
token.value = text;
while (*text && *text != delimeter) {
++text;
}
token.len = text - token.value;
// trim spaces
while (token.len && isspace(token.value[token.len - 1])) {
--token.len;
}
}

// add to output array
if (tokens && token_num < max_tokens) {
memcpy(&tokens[token_num], &token, sizeof(token));
}
++token_num;

if (*text) {
++text; // skip delimeter
}
}

return token_num;
}
Loading

0 comments on commit 2e52b29

Please sign in to comment.