/*
* Copyright (c)2004 Cat's Eye Technologies. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Cat's Eye Technologies nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* curses_util.c
* $Id: curses_util.c,v 1.9 2005/07/22 19:44:23 cpressey Exp $
*/
#include <ctype.h>
#include <ncurses.h>
#include <panel.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "curses_util.h"
unsigned int ymax, xmax;
int monochrome = 1;
int allocated_colors = 0;
struct curses_attr {
int pair_no;
int bold;
};
struct curses_attr colors_tab[CURSES_COLORS_MAX];
int colors[8] = {
COLOR_BLACK,
COLOR_RED,
COLOR_GREEN,
COLOR_YELLOW,
COLOR_BLUE,
COLOR_MAGENTA,
COLOR_CYAN,
COLOR_WHITE
};
/*
* If there is an established color pair with the given fg and bg
* colors, return it. Else allocate a new pair with these colors
* and return that.
*/
static int
curses_colors_find(int fg, int bg)
{
int pair_no;
short fge, bge;
for (pair_no = 0;
pair_no <= allocated_colors && pair_no < COLOR_PAIRS;
pair_no++) {
pair_content(pair_no, &fge, &bge);
if (fg == fge && bg == bge)
return(pair_no);
}
/*
* No pair was found, allocate a new one.
*/
if (allocated_colors < (COLOR_PAIRS-1)) {
allocated_colors++;
init_pair(allocated_colors, fg, bg);
return(allocated_colors);
}
/*
* No space to allocate a new one, return error.
*/
return(-1);
}
static void
curses_colors_cfg(int role, int fg, int bg, int bold)
{
int pair_no;
pair_no = curses_colors_find(fg, bg);
if (pair_no != -1) {
colors_tab[role].pair_no = pair_no;
colors_tab[role].bold = bold;
} else {
colors_tab[role].pair_no = 0;
colors_tab[role].bold = bold;
}
}
void
curses_colors_init(int force_monochrome)
{
if (!force_monochrome) {
if (has_colors()) {
monochrome = 0;
start_color();
}
}
/*
* By default, make it look kinda like the default libdialog.
*/
curses_colors_cfg(CURSES_COLORS_NORMAL, COLOR_BLACK, COLOR_GREY, 0);
curses_colors_cfg(CURSES_COLORS_BACKDROP, COLOR_WHITE, COLOR_BLUE, 0);
curses_colors_cfg(CURSES_COLORS_MENUBAR, COLOR_BLACK, COLOR_GREY, 0);
curses_colors_cfg(CURSES_COLORS_STATUSBAR, COLOR_BLACK, COLOR_GREY, 0);
curses_colors_cfg(CURSES_COLORS_BORDER, COLOR_WHITE, COLOR_GREY, 1);
curses_colors_cfg(CURSES_COLORS_FORMTITLE, COLOR_YELLOW, COLOR_GREY, 1);
curses_colors_cfg(CURSES_COLORS_LABEL, COLOR_BLACK, COLOR_GREY, 0);
curses_colors_cfg(CURSES_COLORS_CONTROL, COLOR_BLACK, COLOR_GREY, 0);
curses_colors_cfg(CURSES_COLORS_TEXT, COLOR_BLACK, COLOR_GREY, 0);
curses_colors_cfg(CURSES_COLORS_FOCUS, COLOR_WHITE, COLOR_BLUE, 1);
curses_colors_cfg(CURSES_COLORS_SCROLLAREA,COLOR_GREY, COLOR_BLACK, 0);
curses_colors_cfg(CURSES_COLORS_SCROLLBAR, COLOR_WHITE, COLOR_BLUE, 1);
curses_colors_cfg(CURSES_COLORS_ACCEL, COLOR_WHITE, COLOR_GREY, 1);
curses_colors_cfg(CURSES_COLORS_ACCELFOCUS,COLOR_YELLOW, COLOR_BLUE, 1);
curses_colors_cfg(CURSES_COLORS_GHOST, COLOR_BLUE, COLOR_GREY, 0);
}
void
curses_colors_set(WINDOW *w, int a)
{
if (!monochrome)
wattrset(w, COLOR_PAIR(colors_tab[a].pair_no));
if (colors_tab[a].bold)
wattron(w, A_BOLD);
else
wattroff(w, A_BOLD);
}
void
curses_window_blank(WINDOW *w)
{
unsigned int i;
for (i = 0; i <= ymax; i++) {
wmove(w, i, 0);
whline(w, ' ', xmax);
}
wrefresh(w);
}
void
curses_frame_draw(int x, int y, int width, int height)
{
int i;
mvaddch(y, x, ACS_ULCORNER);
hline(ACS_HLINE, width - 2);
mvaddch(y, x + width - 1, ACS_URCORNER);
mvaddch(y + height - 1, x, ACS_LLCORNER);
hline(ACS_HLINE, width - 2);
mvaddch(y + height - 1, x + width - 1, ACS_LRCORNER);
move(y + 1, x);
vline(ACS_VLINE, height - 2);
move(y + 1, x + width - 1);
vline(ACS_VLINE, height - 2);
for (i = y + 1; i < y + height - 1; i++) {
move(i, x + 1);
hline(' ', width - 2);
}
}
void
curses_load_backdrop(WINDOW *w, const char *filename)
{
FILE *f;
char line[80];
int row = 1;
int my, mx;
getmaxyx(w, my, mx);
wclear(w);
curses_colors_set(w, CURSES_COLORS_BACKDROP);
curses_window_blank(w);
if ((f = fopen(filename, "r")) != NULL) {
while (fgets(line, 79, f) != NULL) {
if (row > my)
break;
if (line[strlen(line) - 1] == '\n')
line[strlen(line) - 1] = '\0';
mvwaddnstr(w, row++, 0, line, mx);
}
fclose(f);
}
}
void
curses_debug_str(const char *s)
{
char b[256];
move(1, 0);
sprintf(b, "[%77s]", s);
addstr(b);
refresh();
}
void
curses_debug_int(int i)
{
char b[256];
move(1, 0);
sprintf(b, "[%06d]", i);
addstr(b);
refresh();
}
void
curses_debug_key(int i)
{
char b[256];
move(1, 0);
sprintf(b, "[%06d] %s", i, keyname(i));
addstr(b);
refresh();
}
void
curses_debug_float(float f)
{
char b[256];
move(1, 0);
sprintf(b, "[%09.3f]", f);
addstr(b);
refresh();
}
/*
* Word wrapping.
*
* text: The text to word-wrap, as one long string. Spaces will be
* compressed, but end-of-line characters will be honoured.
* line: A buffer (must be allocated by the caller) to hold a single
* line extracted from text.
* width: The maximum width of a line.
* spos: Pointer to the source position in text. Should be initially
* set to zero, and retained between calls to this function.
* Returns: A boolean indicating whether the end of text was reached.
* Typically this function should be called repeatedly until
* it returns true.
*/
int
extract_wrapped_line(const char *text, char *line, int width, int *spos)
{
int dpos = 0;
int saved_spos, saved_dpos;
for (;;) {
/*
* Skip over whitespace. If we find a newline or the
* end of the text, return a blank line. Leave *spos
* at the position of the 1st non-whitespace character.
*/
while (isspace(text[*spos]) && text[*spos] != '\0') {
if (text[*spos] == '\n') {
line[dpos] = '\0';
(*spos)++;
return(0);
}
(*spos)++;
}
/*
* Save start position and destination position.
*/
saved_spos = *spos;
saved_dpos = dpos;
/*
* Read a word from *spos onward.
*/
while (!isspace(text[*spos]) &&
text[*spos] != '\0' &&
dpos < width) {
line[dpos++] = text[(*spos)++];
}
if (text[*spos] == '\0') {
/*
* End of string - return this word as the last.
*/
line[dpos] = '\0';
return(1);
} else if (dpos >= width) {
/*
* Last word is too long to fit on this line.
*/
if (dpos - saved_dpos >= width) {
/*
* In fact, it's too long to fit on any line!
* Truncate it.
*/
line[width - 1] = '\0';
*spos = saved_spos + (dpos - saved_dpos) - 1;
return(0);
} else {
/*
* Save it for the next pass.
*/
*spos = saved_spos;
line[saved_dpos - 1] = '\0';
return(0);
}
} else {
line[dpos++] = ' ';
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1