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