Blame alsamixer/textbox.c

Packit 229ac0
/*
Packit 229ac0
 * textbox.c - show a text box for messages, files or help
Packit 229ac0
 * Copyright (c) 1998,1999 Tim Janik
Packit 229ac0
 *                         Jaroslav Kysela <perex@perex.cz>
Packit 229ac0
 * Copyright (c) 2009      Clemens Ladisch <clemens@ladisch.de>
Packit 229ac0
 *
Packit 229ac0
 * This program is free software: you can redistribute it and/or modify
Packit 229ac0
 * it under the terms of the GNU General Public License as published by
Packit 229ac0
 * the Free Software Foundation, either version 2 of the License, or
Packit 229ac0
 * (at your option) any later version.
Packit 229ac0
 *
Packit 229ac0
 * This program is distributed in the hope that it will be useful,
Packit 229ac0
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 229ac0
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 229ac0
 * GNU General Public License for more details.
Packit 229ac0
 *
Packit 229ac0
 * You should have received a copy of the GNU General Public License
Packit 229ac0
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 229ac0
 */
Packit 229ac0
Packit 229ac0
#include "aconfig.h"
Packit 229ac0
#include <stdio.h>
Packit 229ac0
#include <stdlib.h>
Packit 229ac0
#include <string.h>
Packit 229ac0
#include <errno.h>
Packit 229ac0
#include CURSESINC
Packit 229ac0
#include <alsa/asoundlib.h>
Packit 229ac0
#include "gettext_curses.h"
Packit 229ac0
#include "utils.h"
Packit 229ac0
#include "die.h"
Packit 229ac0
#include "mem.h"
Packit 229ac0
#include "colors.h"
Packit 229ac0
#include "widget.h"
Packit 229ac0
#include "textbox.h"
Packit 229ac0
Packit 229ac0
#define MAX_FILE_SIZE 1048576
Packit 229ac0
Packit 229ac0
static void create_text_box(const char *const *lines, unsigned int count,
Packit 229ac0
			    const char *title, int attrs);
Packit 229ac0
Packit 229ac0
void show_error(const char *msg, int err)
Packit 229ac0
{
Packit 229ac0
	const char *lines[2];
Packit 229ac0
	unsigned int count;
Packit 229ac0
Packit 229ac0
	lines[0] = msg;
Packit 229ac0
	count = 1;
Packit 229ac0
	if (err) {
Packit 229ac0
		lines[1] = strerror(err);
Packit 229ac0
		count = 2;
Packit 229ac0
	}
Packit 229ac0
	create_text_box(lines, count, _("Error"), attr_errormsg);
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
void show_alsa_error(const char *msg, int err)
Packit 229ac0
{
Packit 229ac0
	const char *lines[2];
Packit 229ac0
	unsigned int count;
Packit 229ac0
Packit 229ac0
	lines[0] = msg;
Packit 229ac0
	count = 1;
Packit 229ac0
	if (err < 0) {
Packit 229ac0
		lines[1] = snd_strerror(err);
Packit 229ac0
		count = 2;
Packit 229ac0
	}
Packit 229ac0
	create_text_box(lines, count, _("Error"), attr_errormsg);
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static char *read_file(const char *file_name, unsigned int *file_size)
Packit 229ac0
{
Packit 229ac0
	FILE *f;
Packit 229ac0
	int err;
Packit 229ac0
	char *buf;
Packit 229ac0
	unsigned int allocated = 2048;
Packit 229ac0
	unsigned int bytes_read;
Packit 229ac0
Packit 229ac0
	f = fopen(file_name, "r");
Packit 229ac0
	if (!f) {
Packit 229ac0
		err = errno;
Packit 229ac0
		buf = casprintf(_("Cannot open file \"%s\"."), file_name);
Packit 229ac0
		show_error(buf, err);
Packit 229ac0
		free(buf);
Packit 229ac0
		return NULL;
Packit 229ac0
	}
Packit 229ac0
	*file_size = 0;
Packit 229ac0
	buf = NULL;
Packit 229ac0
	do {
Packit 229ac0
		allocated *= 2;
Packit 229ac0
		buf = crealloc(buf, allocated);
Packit 229ac0
		bytes_read = fread(buf + *file_size, 1, allocated - *file_size, f);
Packit 229ac0
		*file_size += bytes_read;
Packit 229ac0
	} while (*file_size == allocated && allocated < MAX_FILE_SIZE);
Packit 229ac0
	fclose(f);
Packit 229ac0
	if (*file_size > 0 && buf[*file_size - 1] != '\n' && *file_size < allocated) {
Packit 229ac0
		buf[*file_size] = '\n';
Packit 229ac0
		++*file_size;
Packit 229ac0
	}
Packit 229ac0
	return buf;
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
void show_textfile(const char *file_name)
Packit 229ac0
{
Packit 229ac0
	char *buf;
Packit 229ac0
	unsigned int file_size;
Packit 229ac0
	unsigned int line_count;
Packit 229ac0
	unsigned int i;
Packit 229ac0
	const char **lines;
Packit 229ac0
	const char *start_line;
Packit 229ac0
Packit 229ac0
	buf = read_file(file_name, &file_size);
Packit 229ac0
	if (!buf)
Packit 229ac0
		return;
Packit 229ac0
	line_count = 0;
Packit 229ac0
	for (i = 0; i < file_size; ++i)
Packit 229ac0
		line_count += buf[i] == '\n';
Packit 229ac0
	lines = ccalloc(line_count, sizeof *lines);
Packit 229ac0
	line_count = 0;
Packit 229ac0
	start_line = buf;
Packit 229ac0
	for (i = 0; i < file_size; ++i) {
Packit 229ac0
		if (buf[i] == '\n') {
Packit 229ac0
			lines[line_count++] = start_line;
Packit 229ac0
			buf[i] = '\0';
Packit 229ac0
			start_line = &buf[i + 1];
Packit 229ac0
		}
Packit 229ac0
		if (buf[i] == '\t')
Packit 229ac0
			buf[i] = ' ';
Packit 229ac0
	}
Packit 229ac0
	create_text_box(lines, line_count, file_name, attr_textbox);
Packit 229ac0
	free(lines);
Packit 229ac0
	free(buf);
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
void show_text(const char *const *lines, unsigned int count, const char *title)
Packit 229ac0
{
Packit 229ac0
	create_text_box(lines, count, title, attr_textbox);
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
/**********************************************************************/
Packit 229ac0
Packit 229ac0
static struct widget text_widget;
Packit 229ac0
static char *title;
Packit 229ac0
static int widget_attrs;
Packit 229ac0
static char **text_lines;
Packit 229ac0
static unsigned int text_lines_count;
Packit 229ac0
static int max_line_width;
Packit 229ac0
static int text_box_y;
Packit 229ac0
static int text_box_x;
Packit 229ac0
static int max_scroll_y;
Packit 229ac0
static int max_scroll_x;
Packit 229ac0
static int current_top;
Packit 229ac0
static int current_left;
Packit 229ac0
Packit 229ac0
static void update_text_lines(void)
Packit 229ac0
{
Packit 229ac0
	int i;
Packit 229ac0
	int width;
Packit 229ac0
	const char *line_begin;
Packit 229ac0
	const char *line_end;
Packit 229ac0
	int cur_y, cur_x;
Packit 229ac0
	int rest_of_line;
Packit 229ac0
Packit 229ac0
	for (i = 0; i < text_box_y; ++i) {
Packit 229ac0
		width = current_left;
Packit 229ac0
		line_begin = mbs_at_width(text_lines[current_top + i], &width, 1);
Packit 229ac0
		wmove(text_widget.window, i + 1, 1);
Packit 229ac0
		if (width > current_left)
Packit 229ac0
			waddch(text_widget.window, ' ');
Packit 229ac0
		if (*line_begin != '\0') {
Packit 229ac0
			width = text_box_x - (width > current_left);
Packit 229ac0
			line_end = mbs_at_width(line_begin, &width, -1);
Packit 229ac0
			if (width)
Packit 229ac0
				waddnstr(text_widget.window, line_begin,
Packit 229ac0
					 line_end - line_begin);
Packit 229ac0
		}
Packit 229ac0
		getyx(text_widget.window, cur_y, cur_x);
Packit 229ac0
		if (cur_y == i + 1) {
Packit 229ac0
			rest_of_line = text_box_x + 1 - cur_x;
Packit 229ac0
			if (rest_of_line > 0)
Packit 229ac0
				wprintw(text_widget.window, "%*s", rest_of_line, "");
Packit 229ac0
		}
Packit 229ac0
	}
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static void update_y_scroll_bar(void)
Packit 229ac0
{
Packit 229ac0
	int length;
Packit 229ac0
	int begin, end;
Packit 229ac0
	int i;
Packit 229ac0
Packit 229ac0
	if (max_scroll_y <= 0 || text_lines_count == 0)
Packit 229ac0
		return;
Packit 229ac0
	length = text_box_y * text_box_y / text_lines_count;
Packit 229ac0
	if (length >= text_box_y)
Packit 229ac0
		return;
Packit 229ac0
	begin = current_top * (text_box_y - length) / max_scroll_y;
Packit 229ac0
	end = begin + length;
Packit 229ac0
	for (i = 0; i < text_box_y; ++i)
Packit 229ac0
		mvwaddch(text_widget.window, i + 1, text_box_x + 1,
Packit 229ac0
			 i >= begin && i < end ? ACS_BOARD : ' ');
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static void update_x_scroll_bar(void)
Packit 229ac0
{
Packit 229ac0
	int length;
Packit 229ac0
	int begin, end;
Packit 229ac0
	int i;
Packit 229ac0
Packit 229ac0
	if (max_scroll_x <= 0 || max_line_width <= 0)
Packit 229ac0
		return;
Packit 229ac0
	length = text_box_x * text_box_x / max_line_width;
Packit 229ac0
	if (length >= text_box_x)
Packit 229ac0
		return;
Packit 229ac0
	begin = current_left * (text_box_x - length) / max_scroll_x;
Packit 229ac0
	end = begin + length;
Packit 229ac0
	wmove(text_widget.window, text_box_y + 1, 1);
Packit 229ac0
	for (i = 0; i < text_box_x; ++i)
Packit 229ac0
		waddch(text_widget.window, i >= begin && i < end ? ACS_BOARD : ' ');
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static void move_x(int delta)
Packit 229ac0
{
Packit 229ac0
	int left;
Packit 229ac0
Packit 229ac0
	left = current_left + delta;
Packit 229ac0
	if (left < 0)
Packit 229ac0
		left = 0;
Packit 229ac0
	else if (left > max_scroll_x)
Packit 229ac0
		left = max_scroll_x;
Packit 229ac0
	if (left != current_left) {
Packit 229ac0
		current_left = left;
Packit 229ac0
		update_text_lines();
Packit 229ac0
		update_x_scroll_bar();
Packit 229ac0
	}
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static void move_y(int delta)
Packit 229ac0
{
Packit 229ac0
	int top;
Packit 229ac0
Packit 229ac0
	top = current_top + delta;
Packit 229ac0
	if (top < 0)
Packit 229ac0
		top = 0;
Packit 229ac0
	else if (top > max_scroll_y)
Packit 229ac0
		top = max_scroll_y;
Packit 229ac0
	if (top != current_top) {
Packit 229ac0
		current_top = top;
Packit 229ac0
		update_text_lines();
Packit 229ac0
		update_y_scroll_bar();
Packit 229ac0
	}
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static void on_handle_key(int key)
Packit 229ac0
{
Packit 229ac0
	switch (key) {
Packit 229ac0
	case 10:
Packit 229ac0
	case 13:
Packit 229ac0
	case 27:
Packit 229ac0
	case KEY_CANCEL:
Packit 229ac0
	case KEY_ENTER:
Packit 229ac0
	case KEY_CLOSE:
Packit 229ac0
	case KEY_EXIT:
Packit 229ac0
		text_widget.close();
Packit 229ac0
		break;
Packit 229ac0
	case KEY_DOWN:
Packit 229ac0
	case KEY_SF:
Packit 229ac0
	case 'J':
Packit 229ac0
	case 'j':
Packit 229ac0
	case 'X':
Packit 229ac0
	case 'x':
Packit 229ac0
		move_y(1);
Packit 229ac0
		break;
Packit 229ac0
	case KEY_UP:
Packit 229ac0
	case KEY_SR:
Packit 229ac0
	case 'K':
Packit 229ac0
	case 'k':
Packit 229ac0
	case 'W':
Packit 229ac0
	case 'w':
Packit 229ac0
		move_y(-1);
Packit 229ac0
		break;
Packit 229ac0
	case KEY_LEFT:
Packit 229ac0
	case 'H':
Packit 229ac0
	case 'h':
Packit 229ac0
	case 'P':
Packit 229ac0
	case 'p':
Packit 229ac0
		move_x(-1);
Packit 229ac0
		break;
Packit 229ac0
	case KEY_RIGHT:
Packit 229ac0
	case 'L':
Packit 229ac0
	case 'l':
Packit 229ac0
	case 'N':
Packit 229ac0
	case 'n':
Packit 229ac0
		move_x(1);
Packit 229ac0
		break;
Packit 229ac0
	case KEY_NPAGE:
Packit 229ac0
	case ' ':
Packit 229ac0
		move_y(text_box_y);
Packit 229ac0
		break;
Packit 229ac0
	case KEY_PPAGE:
Packit 229ac0
	case KEY_BACKSPACE:
Packit 229ac0
	case 'B':
Packit 229ac0
	case 'b':
Packit 229ac0
		move_y(-text_box_y);
Packit 229ac0
		break;
Packit 229ac0
	case KEY_HOME:
Packit 229ac0
	case KEY_BEG:
Packit 229ac0
		move_x(-max_scroll_x);
Packit 229ac0
		break;
Packit 229ac0
	case KEY_LL:
Packit 229ac0
	case KEY_END:
Packit 229ac0
		move_x(max_scroll_x);
Packit 229ac0
		break;
Packit 229ac0
	case '\t':
Packit 229ac0
		move_x(8);
Packit 229ac0
		break;
Packit 229ac0
	case KEY_BTAB:
Packit 229ac0
		move_x(-8);
Packit 229ac0
		break;
Packit 229ac0
	}
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static bool create(void)
Packit 229ac0
{
Packit 229ac0
	int len, width;
Packit 229ac0
Packit 229ac0
	if (screen_lines < 3 || screen_cols < 8) {
Packit 229ac0
		text_widget.close();
Packit 229ac0
		beep();
Packit 229ac0
		return FALSE;
Packit 229ac0
	}
Packit 229ac0
Packit 229ac0
	width = max_line_width;
Packit 229ac0
	len = get_mbs_width(title) + 2;
Packit 229ac0
	if (width < len)
Packit 229ac0
		width = len;
Packit 229ac0
Packit 229ac0
	text_box_y = text_lines_count;
Packit 229ac0
	if (text_box_y > screen_lines - 2)
Packit 229ac0
		text_box_y = screen_lines - 2;
Packit 229ac0
	max_scroll_y = text_lines_count - text_box_y;
Packit 229ac0
	text_box_x = width;
Packit 229ac0
	if (text_box_x > screen_cols - 2)
Packit 229ac0
		text_box_x = screen_cols - 2;
Packit 229ac0
	max_scroll_x = max_line_width - text_box_x;
Packit 229ac0
Packit 229ac0
	widget_init(&text_widget, text_box_y + 2, text_box_x + 2,
Packit 229ac0
		    SCREEN_CENTER, SCREEN_CENTER, widget_attrs, WIDGET_BORDER);
Packit 229ac0
	mvwprintw(text_widget.window, 0, (text_box_x + 2 - get_mbs_width(title) - 2) / 2, " %s ", title);
Packit 229ac0
Packit 229ac0
	if (current_top > max_scroll_y)
Packit 229ac0
		current_top = max_scroll_y;
Packit 229ac0
	if (current_left > max_scroll_x)
Packit 229ac0
		current_left = max_scroll_x;
Packit 229ac0
	update_text_lines();
Packit 229ac0
	update_y_scroll_bar();
Packit 229ac0
	update_x_scroll_bar();
Packit 229ac0
	return TRUE;
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static void on_window_size_changed(void)
Packit 229ac0
{
Packit 229ac0
	create();
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static void on_close(void)
Packit 229ac0
{
Packit 229ac0
	unsigned int i;
Packit 229ac0
Packit 229ac0
	for (i = 0; i < text_lines_count; ++i)
Packit 229ac0
		free(text_lines[i]);
Packit 229ac0
	free(text_lines);
Packit 229ac0
	widget_free(&text_widget);
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static struct widget text_widget = {
Packit 229ac0
	.handle_key = on_handle_key,
Packit 229ac0
	.window_size_changed = on_window_size_changed,
Packit 229ac0
	.close = on_close,
Packit 229ac0
};
Packit 229ac0
Packit 229ac0
static void create_text_box(const char *const *lines, unsigned int count,
Packit 229ac0
			    const char *title_, int attrs)
Packit 229ac0
{
Packit 229ac0
	unsigned int i;
Packit 229ac0
Packit 229ac0
	text_lines = ccalloc(count, sizeof *text_lines);
Packit 229ac0
	for (i = 0; i < count; ++i)
Packit 229ac0
		text_lines[i] = cstrdup(lines[i]);
Packit 229ac0
	text_lines_count = count;
Packit 229ac0
	max_line_width = get_max_mbs_width(lines, count);
Packit 229ac0
	title = cstrdup(title_);
Packit 229ac0
	widget_attrs = attrs;
Packit 229ac0
Packit 229ac0
	current_top = 0;
Packit 229ac0
	current_left = 0;
Packit 229ac0
Packit 229ac0
	create();
Packit 229ac0
}