1 /*
2  * Schism Tracker - a cross-platform Impulse Tracker clone
3  * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com>
4  * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org>
5  * copyright (c) 2009 Storlek & Mrs. Brisby
6  * copyright (c) 2010-2012 Storlek
7  * URL: http://schismtracker.org/
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 /* It's lo-og, lo-og, it's big, it's heavy, it's wood!
25  * It's lo-og, lo-og, it's better than bad, it's good! */
26 
27 #include "headers.h"
28 
29 #include "it.h"
30 #include "page.h"
31 
32 #include "sdlmain.h"
33 
34 #include <stdarg.h>
35 #include <errno.h>
36 
37 struct log_line {
38 	int color;
39 	const char *text;
40 	int bios_font;
41 	/* Set this flag if the text should be free'd when it is scrolled offscreen.
42 	DON'T set it if the text is going to be modified after it is added to the log (e.g. for displaying
43 	status information for module loaders like IT); in that case, change the text pointer to some
44 	constant value such as "". Also don't try changing must_free after adding a line to the log, since
45 	there's a chance that the line scrolled offscreen, and it'd never get free'd. (Also, ignore this
46 	comment since there's currently no interface for manipulating individual lines in the log after
47 	adding them.) */
48 	int must_free;
49 };
50 
51 /* --------------------------------------------------------------------- */
52 
53 static struct widget widgets_log[1];
54 
55 #define NUM_LINES 1000
56 static struct log_line lines[NUM_LINES];
57 static int top_line = 0;
58 static int last_line = -1;
59 
60 /* --------------------------------------------------------------------- */
61 
62 static void log_draw_const(void)
63 {
64 	draw_box(1, 12, 78, 48, BOX_THICK | BOX_INNER | BOX_INSET);
65 	draw_fill_chars(2, 13, 77, 47, 0);
66 }
67 
68 static int log_handle_key(struct key_event * k)
69 {
70 	switch (k->sym) {
71 	case SDLK_UP:
72 		if (k->state == KEY_RELEASE)
73 			return 1;
74 		top_line--;
75 		break;
76 	case SDLK_PAGEUP:
77 		if (k->state == KEY_RELEASE)
78 			return 1;
79 		top_line -= 15;
80 		break;
81 	case SDLK_DOWN:
82 		if (k->state == KEY_RELEASE)
83 			return 1;
84 		top_line++;
85 		break;
86 	case SDLK_PAGEDOWN:
87 		if (k->state == KEY_RELEASE)
88 			return 1;
89 		top_line += 15;
90 		break;
91 	case SDLK_HOME:
92 		if (k->state == KEY_RELEASE)
93 			return 1;
94 		top_line = 0;
95 		break;
96 	case SDLK_END:
97 		if (k->state == KEY_RELEASE)
98 			return 1;
99 		top_line = last_line;
100 		break;
101 	default:
102 		if (k->state == KEY_PRESS) {
103 			if (k->mouse == MOUSE_SCROLL_UP) {
104 				top_line -= MOUSE_SCROLL_LINES;
105 				break;
106 			} else if (k->mouse == MOUSE_SCROLL_DOWN) {
107 				top_line += MOUSE_SCROLL_LINES;
108 				break;
109 			}
110 		}
111 
112 		return 0;
113 	};
114 	top_line = CLAMP(top_line, 0, (last_line-32));
115 	if (top_line < 0) top_line = 0;
116 	status.flags |= NEED_UPDATE;
117 	return 1;
118 }
119 
120 static void log_redraw(void)
121 {
122 	int n, i;
123 
124 	i = top_line;
125 	for (n = 0; n <= last_line && n < 33; n++, i++) {
126 		if (!lines[i].text) continue;
127 		if (lines[i].bios_font) {
128 			draw_text_bios_len(lines[i].text,
129 					74, 3, 14 + n,
130 					lines[i].color, 0);
131 		} else {
132 			draw_text_len(lines[i].text,
133 					74, 3, 14 + n,
134 					lines[i].color, 0);
135 		}
136 	}
137 }
138 
139 /* --------------------------------------------------------------------- */
140 
141 void log_load_page(struct page *page)
142 {
143 	page->title = "Message Log Viewer (Ctrl-F11)";
144 	page->draw_const = log_draw_const;
145 	page->total_widgets = 1;
146 	page->widgets = widgets_log;
147 	page->help_index = HELP_COPYRIGHT; /* I guess */
148 
149 	create_other(widgets_log + 0, 0, log_handle_key, log_redraw);
150 }
151 
152 /* --------------------------------------------------------------------- */
153 
154 inline void log_append2(int bios_font, int color, int must_free, const char *text)
155 {
156 	if (last_line < NUM_LINES - 1) {
157 		last_line++;
158 	} else {
159 		if (lines[0].must_free)
160 			free((void *) lines[0].text);
161 		memmove(lines, lines + 1, last_line * sizeof(struct log_line));
162 	}
163 	lines[last_line].text = text;
164 	lines[last_line].color = color;
165 	lines[last_line].must_free = must_free;
166 	lines[last_line].bios_font = bios_font;
167 	top_line = CLAMP(last_line - 32, 0, NUM_LINES-32);
168 
169 	if (status.current_page == PAGE_LOG)
170 		status.flags |= NEED_UPDATE;
171 }
172 inline void log_append(int color, int must_free, const char *text)
173 {
174 	log_append2(0, color, must_free, text);
175 }
176 inline void log_nl(void)
177 {
178 	log_append(0,0,"");
179 }
180 void log_appendf(int color, const char *format, ...)
181 {
182 	char *ptr;
183 	va_list ap;
184 
185 	va_start(ap, format);
186 	if (vasprintf(&ptr, format, ap) == -1) {
187 		perror("asprintf");
188 		exit(255);
189 	}
190 	va_end(ap);
191 
192 	if (!ptr) {
193 		perror("asprintf");
194 		exit(255);
195 	}
196 
197 	log_append(color, 1, ptr);
198 }
199 
200 void log_underline(int chars)
201 {
202 	char buf[75];
203 
204 	chars = CLAMP(chars, 0, (int) sizeof(buf) - 1);
205 	buf[chars--] = '\0';
rtrim(char * str)206 	do
207 		buf[chars] = 0x81;
208 	while (chars--);
209 	log_appendf(2, "%s", buf);
210 }
211 
212 void log_perror(const char *prefix)
213 {
214 	char *e = strerror(errno);
215 	perror(prefix);
216 	log_appendf(4, "%s: %s", prefix, e);
217 }
218 
219