Mercurial > hg > forks > yadex
view src/lists.cc @ 80:2f1ecc1c5f72
Huge cleanup -- move some global variables into a struct.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 26 Sep 2011 17:39:49 +0300 |
parents | a68786b9c74b |
children | 20aa5a515896 |
line wrap: on
line source
/* * lists.cc * Pick an item from a list. * AYM 1998-08-22 */ /* This file is part of Yadex. Yadex incorporates code from DEU 5.21 that was put in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. The rest of Yadex is Copyright © 1997-2003 André Majorel and others. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #include "yadex.h" #include "gfx.h" #include "lists.h" #include "wadfile.h" // FIXME Move this in a more public place void lump_loc_string(char *buf, size_t buf_size, const Lump_loc & lump_loc) { if (buf_size < 1) return; int len = buf_size - 1 - (1 + 8 + 1 + 1); // %08lXh if (len < 1) { *buf = '\0'; return; } y_filename(buf, len + 1, lump_loc.wad->pathname()); sprintf(buf + strlen(buf), "(%08lXh)", (unsigned long) lump_loc.ofs & 0xffffffff); } /* ask for a name in a given list and call a function (for displaying objects, etc.) Arguments: x0, y0 : where to draw the box. prompt : text to be displayed. listsize: number of elements in the list. list : list of names (picture names, level names, etc.). listdisp: minimum number of names that should be displayed. name : what we are editing... width : \ width and height of an optional window where a picture height : / can be displayed (used to display textures, sprites, etc.). hookfunc: function that should be called to display a picture. (x1, y1, x2, y2 = coordinates of the window in which the picture must be drawn, name = name of the picture). AYM 1998-02-12 : if hookfunc is <> NULL, a message "Press shift-F1 to save image to file" is displayed and shift-F1 does just that. */ #ifdef DEBUG static bool disp_lump_loc = false; #endif void InputNameFromListWithFunc(int x0, int y0, const char *prompt, size_t listsize, const char *const *list, size_t listdisp, char *name, int width, int height, void (*hookfunc) (hookfunc_comm_t *), char flags_to_pass_to_callback) { const char *msg1 = "Press Shift-F1 to"; const char *msg2 = "save image to file"; int key; size_t n; size_t win_height; int win_columns; int win_width; int l0; int x1, y1, x2, y2; size_t maxlen; int xlist; bool picture_size_drawn = false; #ifdef DEBUG bool lump_loc_drawn = false; #endif bool ok, firstkey; int entry_out_x0; /* Edge of name entry widget including border */ int entry_out_y0; int entry_out_x1; int entry_out_y1; int entry_text_x0; /* Edge of text area of name entry widget */ int entry_text_y0; int entry_text_x1; int entry_text_y1; // Sanity if (width < 0) { nf_bug("inflwf1"); width = 0; } if (height < 0) { nf_bug("inflwf2"); height = 0; } // Compute maxlen, the length of the longest item in the list maxlen = 1; for (n = 0; n < listsize; n++) if (strlen(list[n]) > maxlen) maxlen = strlen(list[n]); for (n = strlen(name) + 1; n <= maxlen; n++) name[n] = '\0'; char *namedisp = new char[maxlen + 1]; memset(namedisp, '\xff', maxlen + 1); // Always != from name // Compute the minimum width of the dialog box l0 = 12; if (hookfunc != NULL) { if ((int) (strlen(msg1) + 2) > l0) // (int) to prevent GCC warning l0 = strlen(msg1) + 2; if ((int) (strlen(msg2) + 2) > l0) // (int) to prevent GCC warning l0 = strlen(msg2) + 2; } xlist = 10 + l0 * FONTW; win_columns = l0 + maxlen; if ((int) (strlen(prompt)) > win_columns) // (int) to prevent GCC warning win_columns = strlen(prompt); win_width = 10 + FONTW * win_columns; x1 = win_width + 8; y1 = 10 + 1; if (width > 0) win_width += 16 + width; // (int) to prevent GCC warning win_height = y_max(height + 20, (int) (listdisp * FONTH + 10 + 28)); if (x0 < 0) x0 = (cfg.ScrMaxX - win_width) / 2; if (y0 < 0) y0 = (cfg.ScrMaxY - win_height) / 2; x1 += x0; y1 += y0; if (x1 + width - 1 < cfg.ScrMaxX) x2 = x1 + width - 1; else x2 = cfg.ScrMaxX; if (y1 + height - 1 < cfg.ScrMaxY) y2 = y1 + height - 1; else y2 = cfg.ScrMaxY; entry_out_x0 = x0 + 10; entry_text_x0 = entry_out_x0 + HOLLOW_BORDER + NARROW_HSPACING; entry_text_x1 = entry_text_x0 + 10 * FONTW - 1; entry_out_x1 = entry_text_x1 + HOLLOW_BORDER + NARROW_HSPACING; entry_out_y0 = y0 + 28; entry_text_y0 = entry_out_y0 + HOLLOW_BORDER + NARROW_VSPACING; entry_text_y1 = entry_text_y0 + FONTH - 1; entry_out_y1 = entry_text_y1 + HOLLOW_BORDER + NARROW_VSPACING; listdisp = y_max(listdisp, (win_height - (entry_out_y0 - y0) - BOX_BORDER - WIDE_VSPACING) / FONTH); // Draw the dialog box DrawScreenBox3D(x0, y0, x0 + win_width, y0 + win_height); DrawScreenBoxHollow(entry_out_x0, entry_out_y0, entry_out_x1, entry_out_y1, BLACK); set_colour(WINTITLE); DrawScreenText(x0 + 10, y0 + 8, prompt); set_colour(WINFG); if (hookfunc != NULL) { DrawScreenText(x0 + 10, y0 + win_height - BOX_BORDER - WIDE_VSPACING - 2 * FONTH, msg1); DrawScreenText(x0 + 10, y0 + win_height - BOX_BORDER - WIDE_VSPACING - FONTH, msg2); } if (width > 0) DrawScreenBoxHollow(x1 - 1, y1 - 1, x2 + 1, y2 + 1, BLACK); firstkey = true; // Another way of saying "nothing to rub out" int disp_x0 = (x2 + x1) / 2; int disp_y0 = (y2 + y1) / 2; int disp_x1 = disp_x0 - 1; int disp_y1 = disp_y0 - 1; int maxpatches = 0; // The event loop for (;;) { hookfunc_comm_t c; // Reset maxpatches every time when change texture if (strcmp(name, namedisp) != 0) maxpatches = 0; // Is "name" in the list ? for (n = 0; n < listsize; n++) if (y_stricmp(name, list[n]) <= 0) break; ok = n < listsize ? !y_stricmp(name, list[n]) : false; if (n >= listsize) n = listsize - 1; // Display the <listdisp> next items in the list { size_t l; // Current line int y = entry_out_y0; // Y-coord of current line int xmin = x0 + xlist; int xmax = xmin + FONTW * maxlen - 1; for (l = 0; l < listdisp && n + l < listsize; l++) { if (false && has_input_event()) // TEST { putchar('.'); // TEST fflush(stdout); // TEST goto shortcut; // TEST } set_colour(WINBG); DrawScreenBox(xmin, y, xmax, y + FONTH - 1); set_colour(WINFG); DrawScreenText(xmin, y, list[n + l]); y += FONTH; } if (l < listdisp) // Less than <listdisp> names to display { set_colour(WINBG); DrawScreenBox(xmin, y, xmax, entry_out_y0 + listdisp * FONTH - 1); } } // Display the entry box and the current text set_colour(BLACK); DrawScreenBox(entry_text_x0, entry_text_y0, entry_text_x1, entry_text_y1); if (ok) // FIXME this colour scheme should be changed. set_colour(WHITE); else set_colour(WINFG); DrawScreenText(entry_text_x0, entry_text_y0, name); // Call the function to display the picture, if any if (hookfunc) { // Display the picture name c.x0 = x1; c.y0 = y1; c.x1 = x2; c.y1 = y2; c.name = name; c.xofs = 0; c.yofs = 0; c.flags = flags_to_pass_to_callback; const int BAD_VALUE = INT_MAX; c.disp_x0 = BAD_VALUE; // Catch faulty callbacks c.disp_y0 = BAD_VALUE; // Catch faulty callbacks c.disp_x1 = BAD_VALUE; // Catch faulty callbacks c.disp_y1 = BAD_VALUE; // Catch faulty callbacks c.maxpatches = maxpatches; if (ok) { hookfunc(&c); } else { // No picture. Null width & height. Erase everything. c.disp_x0 = (x2 + x1) / 2; c.disp_y0 = (y2 + y1) / 2; c.disp_x1 = c.disp_x0 - 1; c.disp_y1 = c.disp_y0 - 1; } strcpy(namedisp, name); // Display the (unclipped) size of the picture { const size_t size_chars = 11; const int size_x0 = x0 + 10; const int size_y0 = y0 + 50; if (picture_size_drawn) { set_colour(WINBG); DrawScreenBoxwh(size_x0, size_y0, size_chars * FONTW, FONTH); picture_size_drawn = false; } if ((c.flags & HOOK_SIZE_VALID) && (c.flags & HOOK_DISP_SIZE)) { set_colour(WINFG); char size_buf[100]; // Slack y_snprintf(size_buf, sizeof size_buf, "%dx%d", c.width, c.height); if (strlen(size_buf) > size_chars) strcpy(size_buf + size_chars - 1, ">"); DrawScreenString(size_x0, size_y0, size_buf); picture_size_drawn = true; } } #ifdef DEBUG // Display the file name and file offset of the picture { const size_t loc_chars = win_width / FONTW; const int loc_x0 = x0; const int loc_y0 = y0 + win_height; if (lump_loc_drawn) { set_colour(WINBG); DrawScreenBoxwh(loc_x0, loc_y0, loc_chars * FONTW, FONTH); lump_loc_drawn = false; } if (disp_lump_loc && (c.flags & HOOK_LOC_VALID)) { set_colour(WINFG); char buf[150]; // Slack lump_loc_string(buf, sizeof buf, c.lump_loc); DrawScreenString(loc_x0, loc_y0, buf); lump_loc_drawn = true; } } #endif /* If the new picture does not completely obscure the previous one, rub out the old pixels. */ set_colour(BLACK); if (c.disp_x0 == BAD_VALUE || c.disp_y0 == BAD_VALUE || c.disp_x1 == BAD_VALUE || c.disp_y1 == BAD_VALUE) nf_bug("Callback %p did not set disp_", hookfunc); else { /* +-WINDOW------------------------+ Erase the dots... | | | +-OLD IMAGE---------------+ | (this is for the case where | | . . : . . . . . . : . . | | the image is centred but the | |. . .:. . . 3 . . .:. . .| | principle is the same if it's | | . . : . . . . . . : . . | | E.G. in the top left corner) | |. . .+-NEW IMAGE---+. . .| | | | . . | | . . | | | |. 1 .| |. 2 .| | | | . . | | . . | | | |. . .+-------------+. . .| | | | . . : . . . . . . : . . | | | |. . .:. . . 4 . . .:. . .| | | | . . : . . . . . . : . . | | | +-------------------------+ | | | +-------------------------------+ */ if (c.disp_x0 > disp_x0) DrawScreenBox(disp_x0, disp_y0, c.disp_x0 - 1, disp_y1); // (1) if (c.disp_x1 < disp_x1) DrawScreenBox(c.disp_x1 + 1, disp_y0, disp_x1, disp_y1); // (2) if (c.disp_y0 > disp_y0) DrawScreenBox(y_max(c.disp_x0, disp_x0), disp_y0, y_min(c.disp_x1, disp_x1), c.disp_y0 - 1); // (3) if (c.disp_y1 < disp_y1) DrawScreenBox(y_max(c.disp_x0, disp_x0), c.disp_y1 + 1, y_min(c.disp_x1, disp_x1), disp_y1); // (4) } disp_x0 = c.disp_x0; disp_y0 = c.disp_y0; disp_x1 = c.disp_x1; disp_y1 = c.disp_y1; } // Process user input shortcut: key = get_key(); if (firstkey && is_ordinary(key) && key != ' ') { for (size_t i = 0; i <= maxlen; i++) name[i] = '\0'; } firstkey = false; size_t len = strlen(name); if (len < maxlen && key >= 'a' && key <= 'z') { name[len] = key + 'A' - 'a'; name[len + 1] = '\0'; } else if (len < maxlen && is_ordinary(key) && key != ' ') { name[len] = key; name[len + 1] = '\0'; } else if (len > 0 && key == YK_BACKSPACE) // BS name[len - 1] = '\0'; else if (key == 21 || key == 23) // ^U, ^W *name = '\0'; else if (key == YK_DOWN) // [Down] { /* Look for the next item in the list that has a different name. Why not just use the next item ? Because sometimes the list has duplicates (for example when editing a Doom II pwad in Doom mode) and then the viewer gets "stuck" on the first duplicate. */ size_t m = n + 1; while (m < listsize && !y_stricmp(list[n], list[m])) m++; if (m < listsize) strcpy(name, list[m]); else Beep(); } else if (key == YK_UP) // [Up] { // Same trick as for [Down] int m = n - 1; while (m >= 0 && !y_stricmp(list[n], list[m])) m--; if (m >= 0) strcpy(name, list[m]); else Beep(); } else if (key == YK_PD || key == 6 || key == 22) // [Pgdn], ^F, ^V { if (n < listsize - listdisp) strcpy(name, list[y_min(n + listdisp, listsize - 1)]); else Beep(); } else if ((key == YK_PU || key == 2) && n > 0) // [Pgup], ^B { if (n > listdisp) strcpy(name, list[n - listdisp]); else strcpy(name, list[0]); } else if (key == 14) // ^N { if (n + 1 >= listsize) { Beep(); goto done_with_event; } while (n + 1 < listsize) { n++; if (y_strnicmp(list[n - 1], list[n], 4)) break; } strcpy(name, list[n]); } else if (key == 16) // ^P { if (n < 1) { Beep(); goto done_with_event; } // Put in <n> the index of the first entry of the current // group or, if already at the beginning of the current // group, the first entry of the previous group. if (n > 0) { if (y_strnicmp(list[n], list[n - 1], 4)) n--; while (n > 0 && !y_strnicmp(list[n], list[n - 1], 4)) n--; } strcpy(name, list[n]); } else if (key == (YK_CTRL | YK_PD) || key == YK_END) // [Ctrl][Pgdn], [End] { if (n + 1 >= listsize) { Beep(); goto done_with_event; } strcpy(name, list[listsize - 1]); } else if (key == (YK_CTRL | YK_PU) || key == YK_HOME) // [Ctrl][Pgup], [Home] { if (n < 1) { Beep(); goto done_with_event; } strcpy(name, list[0]); } else if (key == YK_TAB) // [Tab] strcpy(name, list[n]); else if (key == YK_F1 && c.flags & HOOK_LOC_VALID) // [F1]: print location { printf("%.8s: %s(%08lXh)\n", name, c.lump_loc.wad->pathname(), (unsigned long) c.lump_loc.ofs); } else if (key == YK_F1 + YK_SHIFT // [Shift][F1] : dump image to file && hookfunc != NULL && (c.flags & HOOK_DRAWN)) { const size_t size = strlen(name) + 4 + 1; char *filename = new char[size]; al_scpslower(filename, name, size - 1); al_saps(filename, ".ppm", size - 1); if (c.img.save(filename) != 0) { if (errno == ECHILD) err("Error loading PLAYPAL"); else err("%s: %s", filename, strerror(errno)); } else { printf("Saved %s as %s\n", name, filename); } delete[]filename; } else if (key == 1) // ^A: more patches { if (maxpatches + 1 < c.npatches) maxpatches++; else maxpatches = 0; printf("maxpatches %d\n", maxpatches); } else if (key == 24) // ^X: less patches { if (maxpatches == 0) maxpatches = c.npatches - 1; else maxpatches--; printf("maxpatches %d\n", maxpatches); } else if (ok && key == YK_RETURN) // [Return] break; /* return "name" */ else if (key == YK_ESC) // [Esc] { name[0] = '\0'; /* return an empty string */ break; } else Beep(); done_with_event: ; } delete[]namedisp; } /* ask for a name in a given list */ void InputNameFromList(int x0, int y0, const char *prompt, size_t listsize, const char *const *list, char *name) { InputNameFromListWithFunc(x0, y0, prompt, listsize, list, 5, name, 0, 0, NULL); }