readr

Minimal Terminal RSS Reader
Log | Files | Refs | README | LICENSE

render.c (3579B)




#include "termbox2.h"
#include "tui.h"
#include "config.h"
#include "utils.h"

#define HORIZ_LINE 0x2500
#define VERT_LINE 0x2502

static void
draw_bars(void)
{
	int i;
	const int width = tb_width();
	const int height = tb_height();

	// verticals first

	for (i = 2; i < height - 2; i++) {
		tb_set_cell(0, i, VERT_LINE, LINE_COLOR, BACK_COLOR);
		tb_set_cell(FEED_CAP + 2, i, VERT_LINE, LINE_COLOR, BACK_COLOR); /* separator line */
		tb_set_cell(width - 1, i, VERT_LINE, LINE_COLOR, BACK_COLOR);
	}

	for (i = 0; i < width; i++) {
		tb_set_cell(i, 1, HORIZ_LINE, LINE_COLOR, BACK_COLOR);
		tb_set_cell(i, height - 2, HORIZ_LINE, LINE_COLOR, BACK_COLOR);
	}

	tb_print(1, 0, LOGO_COLOR, BACK_COLOR, "readr");
	tb_print(width - 6, 0, TEXT_COLOR, BACK_COLOR, VERSION);
	tb_print(width - 66,
		height - 1,
		TEXT_COLOR,
		BACK_COLOR,
		"[arrows] move  [enter] open link  [space] open comments  [q] quit");

	// corners top

	tb_set_cell(0, 1, 0x250C, LINE_COLOR, BACK_COLOR);
	tb_set_cell(FEED_CAP + 2, 1, 0x252C, LINE_COLOR, BACK_COLOR);
	tb_set_cell(width - 1, 1, 0x2510, LINE_COLOR, BACK_COLOR);

	// corners bottom

	tb_set_cell(0, height - 2, 0x2514, LINE_COLOR, BACK_COLOR);
	tb_set_cell(FEED_CAP + 2, height - 2, 0x2534, LINE_COLOR, BACK_COLOR);
	tb_set_cell(width - 1, height - 2, 0x2518, LINE_COLOR, BACK_COLOR);
}

static void
draw_background(void)
{
	tb_set_clear_attrs(TEXT_COLOR, BACK_COLOR);
	tb_clear();
}

void
render(app_t* app)
{
	size_t i;
	uintattr_t color;
	char title[TITLE_CAP] = { 0 };
	char domain[DOMAIN_CAP] = { 0 };
	db_post_t* post;
	feed_t* feed;
	feed_t* selected_feed = app->feeds[app->selected_feed];
	int buffer_height = tb_height() - 3 - 3;
	int width = tb_width();

	draw_background();
	draw_bars();

	for (i = 0; i < app->feeds_len; i++) {
		feed = app->feeds[i];

		if (app->selected_panel == 0 && i == app->selected_feed)
			color = (FEED_COLOR | TB_REVERSE | TB_BRIGHT | TB_BOLD);
		else if (i == app->selected_feed)
			color = (FEED_COLOR | TB_BOLD);
		else
			color = (FEED_COLOR | TB_DIM);

		tb_print(2, 3 + (int)i, color, BACK_COLOR, feed->title ? feed->title : "N/A");
	}

	// posts

	int visible_len = MIN(buffer_height, selected_feed->posts_len);
	char title_suffix[10];

	for (int j = 0; j < visible_len; j++) {
		post = selected_feed->posts[j];

		const char* title_src = post->title ? post->title : "(bad title)";
		const char* url_filetype = filetype_from_url(post->link);

		if (url_filetype) {
			snprintf(title_suffix, 10, "[%s]", url_filetype);
			// don't add [video] if the title already ends with [video] etc.
			if (!contains(title_src, title_suffix)) {
				snprintf(title, TITLE_CAP, "%s %s", title_src, title_suffix);
			} else {
				snprintf(title, TITLE_CAP, "%s", title_src);
			}
		} else {
			snprintf(title, TITLE_CAP, "%s", title_src);
		}

		// domain
		const char* domain_host = host_from_url(post->link);
		snprintf(domain, DOMAIN_CAP, "%s", domain_host ? domain_host : "(bad domain)");
		int domain_len = (int)strlen(domain);

		// chop title to fit within its column and not overlap the domain
		snprintf(title, width - domain_len - FEED_CAP - 6, "%s", title);

		if (app->selected_panel == 1 && j == app->selected_post)
			if (post->seen)
				color = (POST_COLOR | TB_REVERSE | TB_DIM);
			else
				color = (POST_COLOR | TB_REVERSE | TB_BRIGHT | TB_BOLD);
		else if (post->seen)
			color = (SEEN_COLOR);
		else
			color = (POST_COLOR);

		tb_print(width - domain_len - 2, 3 + (int)j, DOMAIN_COLOR, BACK_COLOR, domain);
		tb_print(FEED_CAP + 4, 3 + (int)j, color, BACK_COLOR, title);
	}

	tb_present();
}