1c72fcc34Sopenharmony_ci/* 2c72fcc34Sopenharmony_ci * textbox.c - show a text box for messages, files or help 3c72fcc34Sopenharmony_ci * Copyright (c) 1998,1999 Tim Janik 4c72fcc34Sopenharmony_ci * Jaroslav Kysela <perex@perex.cz> 5c72fcc34Sopenharmony_ci * Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de> 6c72fcc34Sopenharmony_ci * 7c72fcc34Sopenharmony_ci * This program is free software: you can redistribute it and/or modify 8c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by 9c72fcc34Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or 10c72fcc34Sopenharmony_ci * (at your option) any later version. 11c72fcc34Sopenharmony_ci * 12c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful, 13c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15c72fcc34Sopenharmony_ci * GNU General Public License for more details. 16c72fcc34Sopenharmony_ci * 17c72fcc34Sopenharmony_ci * You should have received a copy of the GNU General Public License 18c72fcc34Sopenharmony_ci * along with this program. If not, see <http://www.gnu.org/licenses/>. 19c72fcc34Sopenharmony_ci */ 20c72fcc34Sopenharmony_ci 21c72fcc34Sopenharmony_ci#include "aconfig.h" 22c72fcc34Sopenharmony_ci#include <stdio.h> 23c72fcc34Sopenharmony_ci#include <stdlib.h> 24c72fcc34Sopenharmony_ci#include <string.h> 25c72fcc34Sopenharmony_ci#include <errno.h> 26c72fcc34Sopenharmony_ci#include CURSESINC 27c72fcc34Sopenharmony_ci#include <alsa/asoundlib.h> 28c72fcc34Sopenharmony_ci#include "gettext_curses.h" 29c72fcc34Sopenharmony_ci#include "utils.h" 30c72fcc34Sopenharmony_ci#include "die.h" 31c72fcc34Sopenharmony_ci#include "mem.h" 32c72fcc34Sopenharmony_ci#include "colors.h" 33c72fcc34Sopenharmony_ci#include "widget.h" 34c72fcc34Sopenharmony_ci#include "textbox.h" 35c72fcc34Sopenharmony_ci#include "bindings.h" 36c72fcc34Sopenharmony_ci 37c72fcc34Sopenharmony_cistatic void create_text_box(const char *const *lines, unsigned int count, 38c72fcc34Sopenharmony_ci const char *title, int attrs); 39c72fcc34Sopenharmony_ci 40c72fcc34Sopenharmony_civoid show_error(const char *msg, int err) 41c72fcc34Sopenharmony_ci{ 42c72fcc34Sopenharmony_ci const char *lines[2]; 43c72fcc34Sopenharmony_ci unsigned int count; 44c72fcc34Sopenharmony_ci 45c72fcc34Sopenharmony_ci lines[0] = msg; 46c72fcc34Sopenharmony_ci count = 1; 47c72fcc34Sopenharmony_ci if (err) { 48c72fcc34Sopenharmony_ci lines[1] = strerror(err); 49c72fcc34Sopenharmony_ci count = 2; 50c72fcc34Sopenharmony_ci } 51c72fcc34Sopenharmony_ci create_text_box(lines, count, _("Error"), attrs.errormsg); 52c72fcc34Sopenharmony_ci} 53c72fcc34Sopenharmony_ci 54c72fcc34Sopenharmony_civoid show_alsa_error(const char *msg, int err) 55c72fcc34Sopenharmony_ci{ 56c72fcc34Sopenharmony_ci const char *lines[2]; 57c72fcc34Sopenharmony_ci unsigned int count; 58c72fcc34Sopenharmony_ci 59c72fcc34Sopenharmony_ci lines[0] = msg; 60c72fcc34Sopenharmony_ci count = 1; 61c72fcc34Sopenharmony_ci if (err < 0) { 62c72fcc34Sopenharmony_ci lines[1] = snd_strerror(err); 63c72fcc34Sopenharmony_ci count = 2; 64c72fcc34Sopenharmony_ci } 65c72fcc34Sopenharmony_ci create_text_box(lines, count, _("Error"), attrs.errormsg); 66c72fcc34Sopenharmony_ci} 67c72fcc34Sopenharmony_ci 68c72fcc34Sopenharmony_civoid show_textfile(const char *file_name) 69c72fcc34Sopenharmony_ci{ 70c72fcc34Sopenharmony_ci char *buf; 71c72fcc34Sopenharmony_ci unsigned int file_size; 72c72fcc34Sopenharmony_ci unsigned int line_count; 73c72fcc34Sopenharmony_ci unsigned int i; 74c72fcc34Sopenharmony_ci const char **lines; 75c72fcc34Sopenharmony_ci const char *start_line; 76c72fcc34Sopenharmony_ci 77c72fcc34Sopenharmony_ci buf = read_file(file_name, &file_size); 78c72fcc34Sopenharmony_ci if (!buf) { 79c72fcc34Sopenharmony_ci int err = errno; 80c72fcc34Sopenharmony_ci buf = casprintf(_("Cannot open file \"%s\"."), file_name); 81c72fcc34Sopenharmony_ci show_error(buf, err); 82c72fcc34Sopenharmony_ci return; 83c72fcc34Sopenharmony_ci } 84c72fcc34Sopenharmony_ci line_count = 0; 85c72fcc34Sopenharmony_ci for (i = 0; i < file_size; ++i) 86c72fcc34Sopenharmony_ci line_count += buf[i] == '\n'; 87c72fcc34Sopenharmony_ci lines = ccalloc(line_count, sizeof *lines); 88c72fcc34Sopenharmony_ci line_count = 0; 89c72fcc34Sopenharmony_ci start_line = buf; 90c72fcc34Sopenharmony_ci for (i = 0; i < file_size; ++i) { 91c72fcc34Sopenharmony_ci if (buf[i] == '\n') { 92c72fcc34Sopenharmony_ci lines[line_count++] = start_line; 93c72fcc34Sopenharmony_ci buf[i] = '\0'; 94c72fcc34Sopenharmony_ci start_line = &buf[i + 1]; 95c72fcc34Sopenharmony_ci } 96c72fcc34Sopenharmony_ci if (buf[i] == '\t') 97c72fcc34Sopenharmony_ci buf[i] = ' '; 98c72fcc34Sopenharmony_ci } 99c72fcc34Sopenharmony_ci create_text_box(lines, line_count, file_name, attrs.textbox); 100c72fcc34Sopenharmony_ci free(lines); 101c72fcc34Sopenharmony_ci free(buf); 102c72fcc34Sopenharmony_ci} 103c72fcc34Sopenharmony_ci 104c72fcc34Sopenharmony_civoid show_text(const char *const *lines, unsigned int count, const char *title) 105c72fcc34Sopenharmony_ci{ 106c72fcc34Sopenharmony_ci create_text_box(lines, count, title, attrs.textbox); 107c72fcc34Sopenharmony_ci} 108c72fcc34Sopenharmony_ci 109c72fcc34Sopenharmony_ci/**********************************************************************/ 110c72fcc34Sopenharmony_ci 111c72fcc34Sopenharmony_cistatic struct widget text_widget; 112c72fcc34Sopenharmony_cistatic char *title; 113c72fcc34Sopenharmony_cistatic int widget_attrs; 114c72fcc34Sopenharmony_cistatic char **text_lines; 115c72fcc34Sopenharmony_cistatic unsigned int text_lines_count; 116c72fcc34Sopenharmony_cistatic int max_line_width; 117c72fcc34Sopenharmony_cistatic int text_box_y; 118c72fcc34Sopenharmony_cistatic int text_box_x; 119c72fcc34Sopenharmony_cistatic int max_scroll_y; 120c72fcc34Sopenharmony_cistatic int max_scroll_x; 121c72fcc34Sopenharmony_cistatic int current_top; 122c72fcc34Sopenharmony_cistatic int current_left; 123c72fcc34Sopenharmony_ci 124c72fcc34Sopenharmony_cistatic void update_text_lines(void) 125c72fcc34Sopenharmony_ci{ 126c72fcc34Sopenharmony_ci int i; 127c72fcc34Sopenharmony_ci int width; 128c72fcc34Sopenharmony_ci const char *line_begin; 129c72fcc34Sopenharmony_ci const char *line_end; 130c72fcc34Sopenharmony_ci int cur_y, cur_x; 131c72fcc34Sopenharmony_ci int rest_of_line; 132c72fcc34Sopenharmony_ci 133c72fcc34Sopenharmony_ci for (i = 0; i < text_box_y; ++i) { 134c72fcc34Sopenharmony_ci width = current_left; 135c72fcc34Sopenharmony_ci line_begin = mbs_at_width(text_lines[current_top + i], &width, 1); 136c72fcc34Sopenharmony_ci wmove(text_widget.window, i + 1, 1); 137c72fcc34Sopenharmony_ci if (width > current_left) 138c72fcc34Sopenharmony_ci waddch(text_widget.window, ' '); 139c72fcc34Sopenharmony_ci if (*line_begin != '\0') { 140c72fcc34Sopenharmony_ci width = text_box_x - (width > current_left); 141c72fcc34Sopenharmony_ci line_end = mbs_at_width(line_begin, &width, -1); 142c72fcc34Sopenharmony_ci if (width) 143c72fcc34Sopenharmony_ci waddnstr(text_widget.window, line_begin, 144c72fcc34Sopenharmony_ci line_end - line_begin); 145c72fcc34Sopenharmony_ci } 146c72fcc34Sopenharmony_ci getyx(text_widget.window, cur_y, cur_x); 147c72fcc34Sopenharmony_ci if (cur_y == i + 1) { 148c72fcc34Sopenharmony_ci rest_of_line = text_box_x + 1 - cur_x; 149c72fcc34Sopenharmony_ci if (rest_of_line > 0) 150c72fcc34Sopenharmony_ci wprintw(text_widget.window, "%*s", rest_of_line, ""); 151c72fcc34Sopenharmony_ci } 152c72fcc34Sopenharmony_ci } 153c72fcc34Sopenharmony_ci} 154c72fcc34Sopenharmony_ci 155c72fcc34Sopenharmony_cistatic void update_y_scroll_bar(void) 156c72fcc34Sopenharmony_ci{ 157c72fcc34Sopenharmony_ci int length; 158c72fcc34Sopenharmony_ci int begin; 159c72fcc34Sopenharmony_ci 160c72fcc34Sopenharmony_ci if (max_scroll_y <= 0 || text_lines_count == 0) 161c72fcc34Sopenharmony_ci return; 162c72fcc34Sopenharmony_ci length = text_box_y * text_box_y / text_lines_count; 163c72fcc34Sopenharmony_ci if (length >= text_box_y) 164c72fcc34Sopenharmony_ci return; 165c72fcc34Sopenharmony_ci begin = current_top * (text_box_y - length) / max_scroll_y; 166c72fcc34Sopenharmony_ci mvwvline(text_widget.window, 1, text_box_x + 1, ' ', text_box_y); 167c72fcc34Sopenharmony_ci mvwvline(text_widget.window, begin + 1, text_box_x + 1, ACS_BOARD, length); 168c72fcc34Sopenharmony_ci} 169c72fcc34Sopenharmony_ci 170c72fcc34Sopenharmony_cistatic void update_x_scroll_bar(void) 171c72fcc34Sopenharmony_ci{ 172c72fcc34Sopenharmony_ci int length; 173c72fcc34Sopenharmony_ci int begin; 174c72fcc34Sopenharmony_ci 175c72fcc34Sopenharmony_ci if (max_scroll_x <= 0 || max_line_width <= 0) 176c72fcc34Sopenharmony_ci return; 177c72fcc34Sopenharmony_ci length = text_box_x * text_box_x / max_line_width; 178c72fcc34Sopenharmony_ci if (length >= text_box_x) 179c72fcc34Sopenharmony_ci return; 180c72fcc34Sopenharmony_ci begin = current_left * (text_box_x - length) / max_scroll_x; 181c72fcc34Sopenharmony_ci mvwhline(text_widget.window, text_box_y + 1, 1, ' ', text_box_x); 182c72fcc34Sopenharmony_ci mvwhline(text_widget.window, text_box_y + 1, begin + 1, ACS_BOARD, length); 183c72fcc34Sopenharmony_ci} 184c72fcc34Sopenharmony_ci 185c72fcc34Sopenharmony_cistatic void move_x(int delta) 186c72fcc34Sopenharmony_ci{ 187c72fcc34Sopenharmony_ci int left; 188c72fcc34Sopenharmony_ci 189c72fcc34Sopenharmony_ci left = current_left + delta; 190c72fcc34Sopenharmony_ci if (left < 0) 191c72fcc34Sopenharmony_ci left = 0; 192c72fcc34Sopenharmony_ci else if (left > max_scroll_x) 193c72fcc34Sopenharmony_ci left = max_scroll_x; 194c72fcc34Sopenharmony_ci if (left != current_left) { 195c72fcc34Sopenharmony_ci current_left = left; 196c72fcc34Sopenharmony_ci update_text_lines(); 197c72fcc34Sopenharmony_ci update_x_scroll_bar(); 198c72fcc34Sopenharmony_ci } 199c72fcc34Sopenharmony_ci} 200c72fcc34Sopenharmony_ci 201c72fcc34Sopenharmony_cistatic void move_y(int delta) 202c72fcc34Sopenharmony_ci{ 203c72fcc34Sopenharmony_ci int top; 204c72fcc34Sopenharmony_ci 205c72fcc34Sopenharmony_ci top = current_top + delta; 206c72fcc34Sopenharmony_ci if (top < 0) 207c72fcc34Sopenharmony_ci top = 0; 208c72fcc34Sopenharmony_ci else if (top > max_scroll_y) 209c72fcc34Sopenharmony_ci top = max_scroll_y; 210c72fcc34Sopenharmony_ci if (top != current_top) { 211c72fcc34Sopenharmony_ci current_top = top; 212c72fcc34Sopenharmony_ci update_text_lines(); 213c72fcc34Sopenharmony_ci update_y_scroll_bar(); 214c72fcc34Sopenharmony_ci } 215c72fcc34Sopenharmony_ci} 216c72fcc34Sopenharmony_ci 217c72fcc34Sopenharmony_cistatic void on_handle_key(int key) 218c72fcc34Sopenharmony_ci{ 219c72fcc34Sopenharmony_ci if (key >= (int)ARRAY_SIZE(textbox_bindings)) 220c72fcc34Sopenharmony_ci return; 221c72fcc34Sopenharmony_ci 222c72fcc34Sopenharmony_ci switch (textbox_bindings[key]) { 223c72fcc34Sopenharmony_ci case CMD_TEXTBOX_CLOSE: 224c72fcc34Sopenharmony_ci text_widget.close(); 225c72fcc34Sopenharmony_ci break; 226c72fcc34Sopenharmony_ci case CMD_TEXTBOX_DOWN: 227c72fcc34Sopenharmony_ci move_y(1); 228c72fcc34Sopenharmony_ci break; 229c72fcc34Sopenharmony_ci case CMD_TEXTBOX_UP: 230c72fcc34Sopenharmony_ci move_y(-1); 231c72fcc34Sopenharmony_ci break; 232c72fcc34Sopenharmony_ci case CMD_TEXTBOX_LEFT: 233c72fcc34Sopenharmony_ci move_x(-1); 234c72fcc34Sopenharmony_ci break; 235c72fcc34Sopenharmony_ci case CMD_TEXTBOX_RIGHT: 236c72fcc34Sopenharmony_ci move_x(1); 237c72fcc34Sopenharmony_ci break; 238c72fcc34Sopenharmony_ci case CMD_TEXTBOX_PAGE_DOWN: 239c72fcc34Sopenharmony_ci move_y(text_box_y); 240c72fcc34Sopenharmony_ci break; 241c72fcc34Sopenharmony_ci case CMD_TEXTBOX_PAGE_UP: 242c72fcc34Sopenharmony_ci move_y(-text_box_y); 243c72fcc34Sopenharmony_ci break; 244c72fcc34Sopenharmony_ci case CMD_TEXTBOX_TOP: 245c72fcc34Sopenharmony_ci move_x(-max_scroll_x); 246c72fcc34Sopenharmony_ci break; 247c72fcc34Sopenharmony_ci case CMD_TEXTBOX_BOTTOM: 248c72fcc34Sopenharmony_ci move_x(max_scroll_x); 249c72fcc34Sopenharmony_ci break; 250c72fcc34Sopenharmony_ci case CMD_TEXTBOX_PAGE_RIGHT: 251c72fcc34Sopenharmony_ci move_x(8); 252c72fcc34Sopenharmony_ci break; 253c72fcc34Sopenharmony_ci case CMD_TEXTBOX_PAGE_LEFT: 254c72fcc34Sopenharmony_ci move_x(-8); 255c72fcc34Sopenharmony_ci break; 256c72fcc34Sopenharmony_ci } 257c72fcc34Sopenharmony_ci} 258c72fcc34Sopenharmony_ci 259c72fcc34Sopenharmony_cistatic bool create(void) 260c72fcc34Sopenharmony_ci{ 261c72fcc34Sopenharmony_ci int len, width; 262c72fcc34Sopenharmony_ci 263c72fcc34Sopenharmony_ci if (screen_lines < 3 || screen_cols < 8) { 264c72fcc34Sopenharmony_ci text_widget.close(); 265c72fcc34Sopenharmony_ci beep(); 266c72fcc34Sopenharmony_ci return FALSE; 267c72fcc34Sopenharmony_ci } 268c72fcc34Sopenharmony_ci 269c72fcc34Sopenharmony_ci width = max_line_width; 270c72fcc34Sopenharmony_ci len = get_mbs_width(title) + 2; 271c72fcc34Sopenharmony_ci if (width < len) 272c72fcc34Sopenharmony_ci width = len; 273c72fcc34Sopenharmony_ci 274c72fcc34Sopenharmony_ci text_box_y = text_lines_count; 275c72fcc34Sopenharmony_ci if (text_box_y > screen_lines - 2) 276c72fcc34Sopenharmony_ci text_box_y = screen_lines - 2; 277c72fcc34Sopenharmony_ci max_scroll_y = text_lines_count - text_box_y; 278c72fcc34Sopenharmony_ci text_box_x = width; 279c72fcc34Sopenharmony_ci if (text_box_x > screen_cols - 2) 280c72fcc34Sopenharmony_ci text_box_x = screen_cols - 2; 281c72fcc34Sopenharmony_ci max_scroll_x = max_line_width - text_box_x; 282c72fcc34Sopenharmony_ci 283c72fcc34Sopenharmony_ci widget_init(&text_widget, text_box_y + 2, text_box_x + 2, 284c72fcc34Sopenharmony_ci SCREEN_CENTER, SCREEN_CENTER, widget_attrs, WIDGET_BORDER); 285c72fcc34Sopenharmony_ci mvwprintw(text_widget.window, 0, (text_box_x + 2 - get_mbs_width(title) - 2) / 2, " %s ", title); 286c72fcc34Sopenharmony_ci 287c72fcc34Sopenharmony_ci if (current_top > max_scroll_y) 288c72fcc34Sopenharmony_ci current_top = max_scroll_y; 289c72fcc34Sopenharmony_ci if (current_left > max_scroll_x) 290c72fcc34Sopenharmony_ci current_left = max_scroll_x; 291c72fcc34Sopenharmony_ci update_text_lines(); 292c72fcc34Sopenharmony_ci update_y_scroll_bar(); 293c72fcc34Sopenharmony_ci update_x_scroll_bar(); 294c72fcc34Sopenharmony_ci return TRUE; 295c72fcc34Sopenharmony_ci} 296c72fcc34Sopenharmony_ci 297c72fcc34Sopenharmony_cistatic void on_window_size_changed(void) 298c72fcc34Sopenharmony_ci{ 299c72fcc34Sopenharmony_ci create(); 300c72fcc34Sopenharmony_ci} 301c72fcc34Sopenharmony_ci 302c72fcc34Sopenharmony_cistatic void on_close(void) 303c72fcc34Sopenharmony_ci{ 304c72fcc34Sopenharmony_ci unsigned int i; 305c72fcc34Sopenharmony_ci 306c72fcc34Sopenharmony_ci for (i = 0; i < text_lines_count; ++i) 307c72fcc34Sopenharmony_ci free(text_lines[i]); 308c72fcc34Sopenharmony_ci free(text_lines); 309c72fcc34Sopenharmony_ci widget_free(&text_widget); 310c72fcc34Sopenharmony_ci} 311c72fcc34Sopenharmony_ci 312c72fcc34Sopenharmony_cistatic struct widget text_widget = { 313c72fcc34Sopenharmony_ci .handle_key = on_handle_key, 314c72fcc34Sopenharmony_ci .window_size_changed = on_window_size_changed, 315c72fcc34Sopenharmony_ci .close = on_close, 316c72fcc34Sopenharmony_ci}; 317c72fcc34Sopenharmony_ci 318c72fcc34Sopenharmony_cistatic void create_text_box(const char *const *lines, unsigned int count, 319c72fcc34Sopenharmony_ci const char *title_, int attrs) 320c72fcc34Sopenharmony_ci{ 321c72fcc34Sopenharmony_ci unsigned int i; 322c72fcc34Sopenharmony_ci 323c72fcc34Sopenharmony_ci text_lines = ccalloc(count, sizeof *text_lines); 324c72fcc34Sopenharmony_ci for (i = 0; i < count; ++i) 325c72fcc34Sopenharmony_ci text_lines[i] = cstrdup(lines[i]); 326c72fcc34Sopenharmony_ci text_lines_count = count; 327c72fcc34Sopenharmony_ci max_line_width = get_max_mbs_width(lines, count); 328c72fcc34Sopenharmony_ci title = cstrdup(title_); 329c72fcc34Sopenharmony_ci widget_attrs = attrs; 330c72fcc34Sopenharmony_ci 331c72fcc34Sopenharmony_ci current_top = 0; 332c72fcc34Sopenharmony_ci current_left = 0; 333c72fcc34Sopenharmony_ci 334c72fcc34Sopenharmony_ci create(); 335c72fcc34Sopenharmony_ci} 336