Logo Search packages:      
Sourcecode: schism version File versions  Download package

itf.c

/*
 * ITFedit - an Impulse / Schism Tracker font file editor
 * copyright (c) 2003-2005 chisel <schism@chisel.cjb.net>
 * copyright (c) 2005-2006 Mrs. Brisby <mrs.brisby@nimh.org>
 * URL: http://nimh.org/schism/
 * URL: http://rigelseven.com/schism/
 *
 * 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
 */

/* this is a little ad-hoc; i did some work trying to bring it back into CVS
   LARGELY because I can't remember all the font characters. :)
*/
#include "headers.h"
#include "it.h"
#include "dmoz.h"
#include "page.h"

#include "sdlmain.h"
#include <string.h>

static const byte itfmap_chars[] = {
128, 129, 130, ' ', 128, 129, 141, ' ', 142, 143, 144, ' ', 168, 'C', '-', '0',
131, ' ', 132, ' ', 131, ' ', 132, ' ', 145, ' ', 146, ' ', 168, 'D', '-', '1',
133, 134, 135, ' ', 140, 134, 135, ' ', 147, 148, 149, ' ', 168, 'E', '-', '2',
' ', ' ', ' ', ' ', ' ', 139, 134, 138, 153, 148, 152, ' ', 168, 'F', '-', '3',
174, ' ', ' ', ' ', 155, 132, ' ', 131, 146, ' ', 145, ' ', 168, 'G', '-', '4',
175, ' ', ' ', ' ', 156, 137, 129, 136, 151, 143, 150, ' ', 168, 'A', '-', '5',
176, ' ', ' ', ' ', 157, ' ', 184, 184, 191, '6', '4', 192, 168, 'B', '-', '6',
176, 177, ' ', ' ', 158, 163, 250, 250, 250, 250, 250, ' ', 168, 'C', '#', '7',
176, 178, ' ', ' ', 159, 164, ' ', ' ', ' ', 185, 186, ' ', 168, 'D', '#', '8',
176, 179, 180, ' ', 160, 165, ' ', ' ', ' ', 189, 190, ' ', 168, 'E', '#', '9',
176, 179, 181, ' ', 161, 166, ' ', ' ', ' ', 187, 188, ' ', 168, 'F', '#', '1',
176, 179, 182, ' ', 162, 167, 126, 126, 126, ' ', ' ', ' ', 168, 'G', '#', '2',
154, 154, 154, 154, ' ', ' ', 205, 205, 205, ' ', 183, ' ', 168, 'A', '#', '3',
169, 170, 171, 172, ' ', ' ', '^', '^', '^', ' ', 173, ' ', 168, 'B', '#', '4',
193, 194, 195, 196, 197, 198, 199, 200, 201, ' ', ' ', ' ', ' ', ' ', ' ', ' ',
};
static const byte helptext_gen[] =
        "Tab         Next box   \xa8 Alt-C  Copy\n"
        "Shift-Tab   Prev. box  \xa8 Alt-P  Paste\n"
        "F2-F4       Switch box \xa8 Alt-M  Mix paste\n"
        "\x18\x19\x1a\x1b        Dump core  \xa8 Alt-Z  Clear\n"
        "Ctrl-S/F10  Save font  \xa8 Alt-H  Flip horiz\n"
        "Ctrl-R/F9   Load font  \xa8 Alt-V  Flip vert\n"
        "Backspace   Reset font \xa8 Alt-I  Invert\n"
        "Ctrl-Bksp   BIOS font  \xa8 Alt-Bk Reset text\n"
        "                       \xa8 0-9    Palette\n"
        "Ctrl-Q      Exit       \xa8  (+10 with shift)\n";

static const byte helptext_editbox[] =
"Space       Plot/clear point\n"
"Ins/Del     Fill/clear horiz.\n"
"...w/Shift  Fill/clear vert.\n"
"\n"
"+/-         Next/prev. char.\n"
"PgUp/PgDn   Next/previous row\n"
"Home/End    Top/bottom corner\n"
"\n" "Shift-\x18\x19\x1a\x1b  Shift character\n"
"[/]         Rotate 90\xf8\n";

static const byte helptext_charmap[] =
"Home/End    First/last char.\n";

static const byte helptext_fontlist[] =
"Home/End    First/last font\n"
"Enter       Load/save file\n"
"Escape      Hide font list\n"
"\n\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a"
"\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\n\n"
"Remember to save as font.cfg\n"
"to change the default font!\n";

/* --------------------------------------------------------------------- */
/* statics & local constants
note: x/y are for the top left corner of the frame, but w/h define the size of its *contents* */

#define EDITBOX_X 0
#define EDITBOX_Y 0
#define EDITBOX_W 9
#define EDITBOX_H 11

#define CHARMAP_X 17
#define CHARMAP_Y 0
#define CHARMAP_W 16
#define CHARMAP_H 16

#define ITFMAP_X 41
#define ITFMAP_Y 0
#define ITFMAP_W 16
#define ITFMAP_H 15

#define FONTLIST_X 65
#define FONTLIST_Y 0
#define VISIBLE_FONTS 22 /* this should be called FONTLIST_H... */

#define HELPTEXT_X 0
#define HELPTEXT_Y 31

/* don't randomly mess with these for obvious reasons */
#define INNER_X(x) ((x) + 3)
#define INNER_Y(y) ((y) + 4)

#define FRAME_RIGHT 3
#define FRAME_BOTTOM 3

#define WITHIN(n,l,u) ((n) >= (l) && (n) < (u))
#define POINT_IN(x,y,item) \
      (WITHIN((x), INNER_X(item##_X), INNER_X(item##_X) + item##_W) \
      && WITHIN((y), INNER_Y(item##_Y), INNER_Y(item##_Y) + item##_H))
#define POINT_IN_FRAME(x,y,item) \
      (WITHIN((x), item##_X, INNER_X(item##_X) + item##_W + FRAME_RIGHT) \
      && WITHIN((y), item##_Y, INNER_Y(item##_Y) + item##_H + FRAME_BOTTOM))

static int edit_x = 3, edit_y = 3;
static byte current_char = 'A';
static int itfmap_pos = -1;

static enum {
      EDITBOX, CHARMAP, ITFMAP, FONTLIST
} selected_item = EDITBOX;

static enum {
      MODE_OFF, MODE_LOAD, MODE_SAVE
} fontlist_mode = MODE_OFF;

static dmoz_filelist_t flist;
int top_font = 0, cur_font = 0;


static void fontlist_reposition(void)
{
      if (cur_font < top_font)
            top_font = cur_font;
      else if (cur_font > top_font + (VISIBLE_FONTS - 1))
            top_font = cur_font - (VISIBLE_FONTS - 1);
}

static int fontgrep(dmoz_file_t *f)
{
      if (f && f->base && strcmp(f->base, "font.cfg") == 0) return 0;
      if (f->type & TYPE_BROWSABLE_MASK) return 0;
      return 1;
}
static void load_fontlist(void)
{
      char *q, *p;
      struct stat st;

      dmoz_free(&flist, NULL);

      top_font = cur_font = 0;

      q = dmoz_path_concat_len(cfg_dir_dotschism, "fonts",
                        strlen(cfg_dir_dotschism),
                        5);
      (void)mkdir(q, 0755);
      p = dmoz_path_concat_len(q, "font.cfg",
                        strlen(q),
                        8);
      memset(&st, 0, sizeof(st));
      if (dmoz_read(q, &flist, NULL) < 0) {
            perror("schism fonts");
      }
      (void)free(q);
      // fart...
      dmoz_filter_filelist(&flist, fontgrep, &cur_font, fontlist_reposition);
      while (dmoz_worker());

      dmoz_add_file(&flist, p, str_dup("font.cfg"), &st, -1024);
      /* p is freed by dmoz_free */
}



static byte clipboard[8] = { 0 };

#define INCR_WRAPPED(n) (((n) & 0xf0) | (((n) + 1) & 0xf))
#define DECR_WRAPPED(n) (((n) & 0xf0) | (((n) - 1) & 0xf))

/* if this is nonzero, the screen will be redrawn. none of the functions
 * except main should call draw_anything -- set this instead. */
static void draw_frame(const byte * name, int x, int y, int inner_width, int inner_height, int active)
{
      int n, c;
      int len = strlen((char*)name);

      if (len > inner_width + 2)
            len = inner_width + 2;
      c = (status.flags & INVERTED_PALETTE) ? 1 : 3;

      draw_box(x, y + 1, x + inner_width + 5,
                    y + inner_height + 6, BOX_THIN | BOX_CORNER | BOX_OUTSET);
      draw_box(x + 1, y + 2, x + inner_width + 4,
                    y + inner_height + 5, BOX_THIN | BOX_INNER | BOX_INSET);

      draw_char(128, x, y, c, 2);
      for (n = 0; n < len + 1; n++)
            draw_char(129, x + n + 1, y, c, 2);
      draw_char(130, x + n, y, c, 2);
      draw_char(131, x, y + 1, c, 2);
      draw_char(137, x + len + 1, y + 1, c, 2);

      switch (active) {
      case 0:                 /* inactive */
            n = 0;
            break;
      case -1:                /* disabled */
            n = 1;
            break;
      default:                /* active */
            n = 3;
            break;
      }
      draw_text_len(name, len, x + 1, y + 1, n, 2);
}

/* --------------------------------------------------------------------- */

static inline void draw_editbox(void)
{
      int c;
      char buf[12];
      int ci = current_char << 3, i, j, fg;

      for (i = 0; i < 8; i++) {
            draw_char('1' + i, INNER_X(EDITBOX_X) + i + 1,
                           INNER_Y(EDITBOX_Y) + 2, (i == edit_x ? 3 : 1), 0);
            draw_char('1' + i, INNER_X(EDITBOX_X),
                           INNER_Y(EDITBOX_Y) + i + 3, (i == edit_y ? 3 : 1), 0);

            for (j = 0; j < 8; j++) {
                  if (font_data[ci + j] & (128 >> i)) {
                        c = 15;
                        fg = 6;
                  } else {
                        c = 173;
                        fg = 1;
                  }
                  if (selected_item == EDITBOX && i == edit_x && j == edit_y)
                        draw_char(c, INNER_X(EDITBOX_X) + 1 + i,
                                       INNER_Y(EDITBOX_Y) + 3 + j, 0, 3);
                  else
                        draw_char(c, INNER_X(EDITBOX_X) + 1 + i,
                                       INNER_Y(EDITBOX_Y) + 3 + j, fg, 0);
            }
      }
      draw_char(current_char, INNER_X(EDITBOX_X), INNER_Y(EDITBOX_Y), 5, 0);

      sprintf(buf, "%3d $%02X", current_char, current_char);
      draw_text((unsigned char *) buf, INNER_X(EDITBOX_X) + 2, INNER_Y(EDITBOX_Y), 5, 0);
}

static inline void draw_charmap(void)
{
      int n = 256;

      if (selected_item == CHARMAP) {
            while (n) {
                  n--;
                  draw_char(n, INNER_X(CHARMAP_X) + n % 16, INNER_Y(CHARMAP_Y) + n / 16,
                                 (n == current_char ? 0 : 1), (n == current_char ? 3 : 0));
            }
      } else {
            while (n) {
                  n--;
                  draw_char(n, INNER_X(CHARMAP_X) + n % 16, INNER_Y(CHARMAP_Y) + n / 16,
                                 (n == current_char ? 3 : 1), 0);
            }
      }
}

static inline void draw_itfmap(void)
{
      int n, fg, bg;
      byte *ptr;

      if (itfmap_pos < 0 || itfmap_chars[itfmap_pos] != current_char) {
            ptr = (unsigned char *) strchr((char *) itfmap_chars, current_char);
            if (ptr == NULL)
                  itfmap_pos = -1;
            else
                  itfmap_pos = ptr - itfmap_chars;
      }

      for (n = 0; n < 240; n++) {
            fg = 1;
            bg = 0;
            if (n == itfmap_pos) {
                  if (selected_item == ITFMAP) {
                        fg = 0;
                        bg = 3;
                  } else {
                        fg = 3;
                  }
            }
            draw_char(itfmap_chars[n],
                           INNER_X(ITFMAP_X) + n % 16, INNER_Y(ITFMAP_Y) + n / 16, fg, bg);
      }
}

static inline void draw_fontlist(void)
{
      int x, pos = 0, n = top_font, cfg, cbg;
      dmoz_file_t *f;
      char *ptr;

      if (selected_item == FONTLIST) {
            cfg = 0;
            cbg = 3;
      } else {
            cfg = 3;
            cbg = 0;
      }

      if (top_font < 0) top_font = 0;
      if (n < 0) n = 0;

      while (n < flist.num_files && pos < VISIBLE_FONTS) {
            x = 1;
            f = flist.files[n];
            if (!f) break;
            ptr = f->base;
            if (n == cur_font) {
                  draw_char(183, INNER_X(FONTLIST_X), INNER_Y(FONTLIST_Y) + pos, cfg, cbg);
                  while (x < 9 && *ptr && (n == 0 || *ptr != '.')) {
                        draw_char(*ptr,
                                       INNER_X(FONTLIST_X) + x,
                                       INNER_Y(FONTLIST_Y) + pos, cfg, cbg);
                        x++;
                        ptr++;
                  }
                  while (x < 9) {
                        draw_char(0,
                                       INNER_X(FONTLIST_X) + x,
                                       INNER_Y(FONTLIST_Y) + pos, cfg, cbg);
                        x++;
                  }
            } else {
                  draw_char(173, INNER_X(FONTLIST_X), INNER_Y(FONTLIST_Y) + pos, 2, 0);
                  while (x < 9 && *ptr && (n == 0 || *ptr != '.')) {
                        draw_char(*ptr,
                                       INNER_X(FONTLIST_X) + x, INNER_Y(FONTLIST_Y) + pos, 5, 0);
                        x++;
                        ptr++;
                  }
                  while (x < 9) {
                        draw_char(0, INNER_X(FONTLIST_X) + x, INNER_Y(FONTLIST_Y) + pos, 5, 0);
                        x++;
                  }
            }
            n++;
            pos++;
      }
}

static inline void draw_helptext(void)
{
      const byte *ptr = helptext_gen;
      const byte *eol;
      int line;
      int column;

      for (line = INNER_Y(HELPTEXT_Y); *ptr; line++) {
            eol = (unsigned char *) strchr((char *) ptr, '\n');
            if (!eol)
                  eol = (unsigned char *) strchr((char *) ptr, '\0');
            for (column = INNER_X(HELPTEXT_X); ptr < eol; ptr++, column++)
                  draw_char(*ptr, column, line, 12, 0);
            ptr++;
      }
      for (line = 0; line < 10; line++)
            draw_char(168, INNER_X(HELPTEXT_X) + 43, INNER_Y(HELPTEXT_Y) + line, 12, 0);

      /* context sensitive stuff... oooh :) */
      switch (selected_item) {
      case EDITBOX:
            ptr = helptext_editbox;
            break;
      case CHARMAP:
      case ITFMAP:
            ptr = helptext_charmap;
            break;
      case FONTLIST:
            ptr = helptext_fontlist;
            break;
      }
      for (line = INNER_Y(HELPTEXT_Y); *ptr; line++) {
            eol = (unsigned char *) strchr((char *) ptr, '\n');
            if (!eol)
                  eol = (unsigned char *) strchr((char *) ptr, '\0');
            draw_char(168, INNER_X(HELPTEXT_X) + 43, line, 12, 0);
            for (column = INNER_X(HELPTEXT_X) + 45; ptr < eol; ptr++, column++)
                  draw_char(*ptr, column, line, 12, 0);
            ptr++;
      }
#define M "(c) 2003-2008 Storlek and Mrs. Brisby"
      draw_text((unsigned char *) M, 78-sizeof(M), 46, 1, 0);
#undef M
}

static inline void draw_time(void)
{
      char buf[16];
      sprintf(buf, "%.2d:%.2d:%.2d", status.h, status.m, status.s);
      draw_text((unsigned char *) buf, 3, 46, 1, 0);
}

extern unsigned int color_set[16];

static void draw_screen(void)
{
      draw_frame((unsigned char *) "Edit Box", EDITBOX_X, EDITBOX_Y, 9, 11, !!(selected_item == EDITBOX));
      draw_editbox();

      draw_frame((unsigned char *) "Current Font", CHARMAP_X, CHARMAP_Y, 16, 16, !!(selected_item == CHARMAP));
      draw_charmap();

      draw_frame((unsigned char *) "Preview", ITFMAP_X, ITFMAP_Y, 16, 15, !!(selected_item == ITFMAP));
      draw_itfmap();

      switch (fontlist_mode) {
      case MODE_LOAD:
            draw_frame((unsigned char *) "Load/Browse", FONTLIST_X, FONTLIST_Y, 9,
                     VISIBLE_FONTS, !!(selected_item == FONTLIST));
            draw_fontlist();
            break;
      case MODE_SAVE:
            draw_frame((unsigned char *) "Save As...", FONTLIST_X, FONTLIST_Y, 9,
                     VISIBLE_FONTS, !!(selected_item == FONTLIST));
            draw_fontlist();
            break;
      default:                /* Off? (I sure hope so!) */
            break;
      }

      draw_frame((unsigned char *) "Quick Help", HELPTEXT_X, HELPTEXT_Y, 74, 12, -1);
      draw_helptext();

      draw_time();
}
static void handle_key_editbox(struct key_event * k)
{
      byte tmp[8] = { 0 };
      int ci = current_char << 3;
      int n, bit;
      byte *ptr = font_data + ci;

      switch (k->sym) {
      case SDLK_UP:
            if (k->mod & KMOD_SHIFT) {
                  int s = ptr[0];
                  for (n = 0; n < 7; n++)
                        ptr[n] = ptr[n + 1];
                  ptr[7] = s;
            } else {
                  if (--edit_y < 0)
                        edit_y = 7;
            }
            break;
      case SDLK_DOWN:
            if (k->mod & KMOD_SHIFT) {
                  int s = ptr[7];
                  for (n = 7; n; n--)
                        ptr[n] = ptr[n - 1];
                  ptr[0] = s;
            } else {
                  edit_y = (edit_y + 1) % 8;
            }
            break;
      case SDLK_LEFT:
            if (k->mod & KMOD_SHIFT) {
                  for (n = 0; n < 8; n++, ptr++)
                        *ptr = (*ptr >> 7) | (*ptr << 1);
            } else {
                  if (--edit_x < 0)
                        edit_x = 7;
            }
            break;
      case SDLK_RIGHT:
            if (k->mod & KMOD_SHIFT) {
                  for (n = 0; n < 8; n++, ptr++)
                        *ptr = (*ptr << 7) | (*ptr >> 1);
            } else {
                  edit_x = (edit_x + 1) % 8;
            }
            break;
      case SDLK_HOME:
            edit_x = edit_y = 0;
            break;
      case SDLK_END:
            edit_x = edit_y = 7;
            break;
      case SDLK_SPACE:
            ptr[edit_y] ^= (128 >> edit_x);
            break;
      case SDLK_INSERT:
            if (k->mod & KMOD_SHIFT) {
                  for (n = 0; n < 8; n++)
                        ptr[n] |= (128 >> edit_x);
            } else {
                  ptr[edit_y] = 255;
            }
            break;
      case SDLK_DELETE:
            if (k->mod & KMOD_SHIFT) {
                  for (n = 0; n < 8; n++)
                        ptr[n] &= ~(128 >> edit_x);
            } else {
                  ptr[edit_y] = 0;
            }
            break;
      case SDLK_LEFTBRACKET:
            for (n = 0; n < 8; n++)
                  for (bit = 0; bit < 8; bit++)
                        if (ptr[n] & (1 << bit))
                              tmp[bit] |= 1 << (7 - n);
            memcpy(ptr, tmp, 8);
            break;
      case SDLK_RIGHTBRACKET:
            for (n = 0; n < 8; n++)
                  for (bit = 0; bit < 8; bit++)
                        if (ptr[n] & (1 << bit))
                              tmp[7 - bit] |= 1 << n;
            memcpy(ptr, tmp, 8);
            break;
      case SDLK_PLUS:
      case SDLK_EQUALS:
            current_char++;
            break;
      case SDLK_MINUS:
      case SDLK_UNDERSCORE:
            current_char--;
            break;
      case SDLK_PAGEUP:
            current_char -= 16;
            break;
      case SDLK_PAGEDOWN:
            current_char += 16;
            break;
      default:
            return;
      }

      status.flags |= NEED_UPDATE;
}

static void handle_key_charmap(struct key_event * k)
{
      switch (k->sym) {
      case SDLK_UP:
            current_char -= 16;
            break;
      case SDLK_DOWN:
            current_char += 16;
            break;
      case SDLK_LEFT:
            current_char = DECR_WRAPPED(current_char);
            break;
      case SDLK_RIGHT:
            current_char = INCR_WRAPPED(current_char);
            break;
      case SDLK_HOME:
            current_char = 0;
            break;
      case SDLK_END:
            current_char = 255;
            break;
      default:
            return;
      }
      status.flags |= NEED_UPDATE;
}

static void handle_key_itfmap(struct key_event * k)
{
      switch (k->sym) {
      case SDLK_UP:
            if (itfmap_pos < 0) {
                  itfmap_pos = 224;
            } else {
                  itfmap_pos -= 16;
                  if (itfmap_pos < 0)
                        itfmap_pos += 240;
            }
            current_char = itfmap_chars[itfmap_pos];
            break;
      case SDLK_DOWN:
            if (itfmap_pos < 0)
                  itfmap_pos = 16;
            else
                  itfmap_pos = (itfmap_pos + 16) % 240;
            current_char = itfmap_chars[itfmap_pos];
            break;
      case SDLK_LEFT:
            if (itfmap_pos < 0)
                  itfmap_pos = 15;
            else
                  itfmap_pos = DECR_WRAPPED(itfmap_pos);
            current_char = itfmap_chars[itfmap_pos];
            break;
      case SDLK_RIGHT:
            if (itfmap_pos < 0)
                  itfmap_pos = 0;
            else
                  itfmap_pos = INCR_WRAPPED(itfmap_pos);
            current_char = itfmap_chars[itfmap_pos];
            break;
      case SDLK_HOME:
            current_char = itfmap_chars[0];
            itfmap_pos = 0;
            break;
      case SDLK_END:
            current_char = itfmap_chars[239];
            itfmap_pos = 239;
            break;
      default:
            return;
      }
      status.flags |= NEED_UPDATE;
}

static void real_save_default(UNUSED void *ign)
{
      if (font_save("font.cfg") != 0) {
            fprintf(stderr, "%s\n", SDL_GetError());
            return;
      }
      selected_item = EDITBOX;
}
static void handle_key_fontlist(struct key_event * k)
{
      int new_font = cur_font;

      switch (k->sym) {
      case SDLK_HOME:
            new_font = 0;
            break;
      case SDLK_END:
            new_font = flist.num_files - 1;
            break;
      case SDLK_UP:
            new_font--;
            break;
      case SDLK_DOWN:
            new_font++;
            break;
      case SDLK_PAGEUP:
            new_font -= VISIBLE_FONTS;
            break;
      case SDLK_PAGEDOWN:
            new_font += VISIBLE_FONTS;
            break;
      case SDLK_ESCAPE:
            selected_item = EDITBOX;
            fontlist_mode = MODE_OFF;
            break;
      case SDLK_RETURN:
            if (!k->state) return;
            switch (fontlist_mode) {
            case MODE_LOAD:
                  if (cur_font < flist.num_files
                  && flist.files[cur_font]
                  && font_load(flist.files[cur_font]->base) != 0) {
                        fprintf(stderr, "%s\n", SDL_GetError());
                        font_reset();
                  }
                  break;
            case MODE_SAVE:
                  /* TODO: if cur_font != 0 (which is font.cfg),
                   * ask before overwriting it */
                  if (cur_font < flist.num_files && flist.files[cur_font]) {
                        if (strcasecmp(flist.files[cur_font]->base,"font.cfg") == 0) {
                              if (status.flags & CLASSIC_MODE) return;

                              dialog_create(DIALOG_OK_CANCEL,
            "Overwriting font.cfg replaces the default font. Proceed?",
                                    real_save_default, NULL, 1, NULL);
                              return;
                        }
                        if (font_save(flist.files[cur_font]->base) != 0) {
                              fprintf(stderr, "%s\n", SDL_GetError());
                              return;
                        }
                  }
                  selected_item = EDITBOX;
                  /* fontlist_mode = MODE_OFF; */
                  break;
            default:
                  /* should never happen */
                  return;
            }
            break;
      default:
            return;
      }

      if (new_font != cur_font) {
            new_font = CLAMP(new_font, 0, flist.num_files - 1);
            if (new_font == cur_font)
                  return;
            cur_font = new_font;
            fontlist_reposition();
      }
      status.flags |= NEED_UPDATE;
}

/* --------------------------------------------------------------------- */

static void handle_mouse_editbox(struct key_event *k)
{
      int n, ci = current_char << 3, xrel, yrel;
      byte *ptr = font_data + ci;
      
      xrel = k->x - INNER_X(EDITBOX_X);
      yrel = k->y - INNER_Y(EDITBOX_Y);
      
      if (xrel > 0 && yrel > 2) {
            edit_x = xrel - 1;
            edit_y = yrel - 3;
            switch (k->mouse_button) {
            case MOUSE_BUTTON_LEFT: /* set */
                  ptr[edit_y] |= (128 >> edit_x);
                  break;
            case MOUSE_BUTTON_MIDDLE: /* invert */
                  if (k->state) return;
                  ptr[edit_y] ^= (128 >> edit_x);
                  break;
            case MOUSE_BUTTON_RIGHT: /* clear */
                  ptr[edit_y] &= ~(128 >> edit_x);
                  break;
            }
      } else if (xrel == 0 && yrel == 2) {
            /* clicking at the origin modifies the entire character */
            switch (k->mouse_button) {
            case MOUSE_BUTTON_LEFT: /* set */
                  for (n = 0; n < 8; n++)
                        ptr[n] = 255;
                  break;
            case MOUSE_BUTTON_MIDDLE: /* invert */
                  if (k->state) return;
                  for (n = 0; n < 8; n++)
                        ptr[n] ^= 255;
                  break;
            case MOUSE_BUTTON_RIGHT: /* clear */
                  for (n = 0; n < 8; n++)
                        ptr[n] = 0;
                  break;
            }
      } else if (xrel == 0 && yrel > 2) {
            edit_y = yrel - 3;
            switch (k->mouse_button) {
            case MOUSE_BUTTON_LEFT: /* set */
                  ptr[edit_y] = 255;
                  break;
            case MOUSE_BUTTON_MIDDLE: /* invert */
                  if (k->state) return;
                  ptr[edit_y] ^= 255;
                  break;
            case MOUSE_BUTTON_RIGHT: /* clear */
                  ptr[edit_y] = 0;
                  break;
            }
      } else if (yrel == 2 && xrel > 0) {
            edit_x = xrel - 1;
            switch (k->mouse_button) {
            case MOUSE_BUTTON_LEFT: /* set */
                  for (n = 0; n < 8; n++)
                        ptr[n] |= (128 >> edit_x);
                  break;
            case MOUSE_BUTTON_MIDDLE: /* invert */
                  if (k->state) return;
                  for (n = 0; n < 8; n++)
                        ptr[n] ^= (128 >> edit_x);
                  break;
            case MOUSE_BUTTON_RIGHT: /* clear */
                  for (n = 0; n < 8; n++)
                        ptr[n] &= ~(128 >> edit_x);
                  break;
            }
      }
}

static void handle_mouse_charmap(struct key_event *k)
{
      int xrel = k->x - INNER_X(CHARMAP_X), yrel = k->y - INNER_Y(CHARMAP_Y);
      if (!k->mouse) return;
      current_char = 16 * yrel + xrel;
}

static void handle_mouse_itfmap(struct key_event *k)
{
      int xrel = k->x - INNER_X(ITFMAP_X), yrel = k->y - INNER_Y(ITFMAP_Y);
      if (!k->mouse) return;
      itfmap_pos = 16 * yrel + xrel;
      current_char = itfmap_chars[itfmap_pos];
}

static void handle_mouse(struct key_event * k)
{
      int x = k->x, y = k->y;
      if (POINT_IN_FRAME(x, y, EDITBOX)) {
            selected_item = EDITBOX;
            if (POINT_IN(x, y, EDITBOX))
                  handle_mouse_editbox(k);
      } else if (POINT_IN_FRAME(x, y, CHARMAP)) {
            selected_item = CHARMAP;
            if (POINT_IN(x, y, CHARMAP))
                  handle_mouse_charmap(k);
      } else if (POINT_IN_FRAME(x, y, ITFMAP)) {
            selected_item = ITFMAP;
            if (POINT_IN(x, y, ITFMAP))
                  handle_mouse_itfmap(k);
      } else {
            //printf("stray click\n");
            return;
      }
      status.flags |= NEED_UPDATE;
}


static int fontedit_handle_key(struct key_event * k)
{
      int n, ci = current_char << 3;
      byte *ptr = font_data + ci;

      if (k->mouse == MOUSE_SCROLL_UP || k->mouse == MOUSE_SCROLL_DOWN) {
            /* err... */
            return 0;
      }

      if (k->mouse == MOUSE_CLICK) {
            handle_mouse(k);
            return 1;
      }

      /* kp is special */
      switch (k->orig_sym) {
      case SDLK_KP0:
            if (k->state) return 1;
            k->sym += 10;
            /* fall through */
      case SDLK_KP1...SDLK_KP9:
            if (k->state) return 1;
            n = k->sym - SDLK_KP1;
            if (k->mod & KMOD_SHIFT)
                  n += 10;
            palette_load_preset(n);
            palette_apply();
            status.flags |= NEED_UPDATE;
            return 1;
      default:
            break;
      };

      switch (k->sym) {
      case '0':
            if (k->state) return 1;
            k->sym += 10;
            /* fall through */
      case '1'...'9':
            if (k->state) return 1;
            n = k->sym - '1';
            if (k->mod & KMOD_SHIFT)
                  n += 10;
            palette_load_preset(n);
            palette_apply();
            status.flags |= NEED_UPDATE;
            return 1;
      case SDLK_F2:
            if (k->state) return 1;
            selected_item = EDITBOX;
            status.flags |= NEED_UPDATE;
            return 1;
      case SDLK_F3:
            if (k->state) return 1;
            selected_item = CHARMAP;
            status.flags |= NEED_UPDATE;
            return 1;
      case SDLK_F4:
            if (k->state) return 1;
            selected_item = ITFMAP;
            status.flags |= NEED_UPDATE;
            return 1;
      case SDLK_TAB:
            if (k->state) return 1;
            if (k->mod & KMOD_SHIFT) {
                  if (selected_item == 0)
                        selected_item = (fontlist_mode == MODE_OFF ? 2 : 3);
                  else
                        selected_item--;
            } else {
                  selected_item = (selected_item + 1) % (fontlist_mode == MODE_OFF ? 3 : 4);
            }
            status.flags |= NEED_UPDATE;
            return 1;
      case SDLK_c:
            if (k->state) return 1;
            if (k->mod & KMOD_ALT) {
                  memcpy(clipboard, ptr, 8);
                  return 1;
            }
            break;
      case SDLK_p:
            if (k->state) return 1;
            if (k->mod & KMOD_ALT) {
                  memcpy(ptr, clipboard, 8);
                  status.flags |= NEED_UPDATE;
                  return 1;
            }
            break;
      case SDLK_m:
            if (k->state) return 1;
            if (k->mod & KMOD_CTRL) {
                  SDL_ToggleCursor();
                  return 1;
            } else if (k->mod & KMOD_ALT) {
                  for (n = 0; n < 8; n++)
                        ptr[n] |= clipboard[n];
                  status.flags |= NEED_UPDATE;
                  return 1;
            }
            break;
      case SDLK_z:
            if (k->state) return 1;
            if (k->mod & KMOD_ALT) {
                  memset(ptr, 0, 8);
                  status.flags |= NEED_UPDATE;
                  return 1;
            }
            break;
      case SDLK_h:
            if (k->state) return 1;
            if (k->mod & KMOD_ALT) {
                  for (n = 0; n < 8; n++) {
                        int r = ptr[n];
                        r = ((r >> 1) & 0x55) | ((r << 1) & 0xaa);
                        r = ((r >> 2) & 0x33) | ((r << 2) & 0xcc);
                        r = ((r >> 4) & 0x0f) | ((r << 4) & 0xf0);
                        ptr[n] = r;
                  }
                  status.flags |= NEED_UPDATE;
                  return 1;
            }
            break;
      case SDLK_v:
            if (k->state) return 1;
            if (k->mod & KMOD_ALT) {
                  for (n = 0; n < 4; n++) {
                        byte r = ptr[n];
                        ptr[n] = ptr[7 - n];
                        ptr[7 - n] = r;
                  }
                  status.flags |= NEED_UPDATE;
                  return 1;
            }
            break;
      case SDLK_i:
            if (k->state) return 1;
            if (k->mod & KMOD_ALT) {
                  for (n = 0; n < 8; n++)
                        font_data[ci + n] ^= 255;
                  status.flags |= NEED_UPDATE;
                  return 1;
            }
            break;

            /* ----------------------------------------------------- */

      case SDLK_l:
      case SDLK_r:
            if (k->state) return 1;
            if (!(k->mod & KMOD_CTRL)) break;
            /* fall through */
      case SDLK_F9:
            if (k->state) return 1;
            load_fontlist();
            fontlist_mode = MODE_LOAD;
            selected_item = FONTLIST;
            status.flags |= NEED_UPDATE;
            return 1;
      case SDLK_s:
            if (k->state) return 1;
            if (!(k->mod & KMOD_CTRL)) break;
            /* fall through */
      case SDLK_F10:
            /* a bit weird, but this ensures that font.cfg
             * is always the default font to save to, but
             * without the annoyance of moving the cursor
             * back to it every time f10 is pressed. */
            if (fontlist_mode != MODE_SAVE) {
                  cur_font = top_font = 0;
                  load_fontlist();
                  fontlist_mode = MODE_SAVE;
            }
            selected_item = FONTLIST;
            status.flags |= NEED_UPDATE;
            return 1;
      case SDLK_BACKSPACE:
            if (k->state) return 1;
            if (k->mod & KMOD_CTRL) {
                  font_reset_bios();
            } else if (k->mod & KMOD_ALT) {
                  font_reset_char(current_char);
            } else {
                  font_reset_upper();
            }
            status.flags |= NEED_UPDATE;
            return 1;
      case SDLK_RETURN:
            return 0;
      case SDLK_q:
            if (k->mod & KMOD_CTRL)
                  return 0;
            if (k->state) return 1;
            break;
      default:
            if (k->state) return 1;
            break;
      }

      switch (selected_item) {
      case EDITBOX:
            handle_key_editbox(k);
            break;
      case CHARMAP:
            handle_key_charmap(k);
            break;
      case ITFMAP:
            handle_key_itfmap(k);
            break;
      case FONTLIST:
            handle_key_fontlist(k);
            break;
      default:
            break;
      }
      return 1;
}


static struct widget fontedit_widget_hack[1];

static int fontedit_key_hack(struct key_event *k)
{
      switch (k->sym) {
      case SDLK_r: case SDLK_l: case SDLK_s:
      case SDLK_c: case SDLK_p: case SDLK_m:
      case SDLK_z: case SDLK_v: case SDLK_h:
      case SDLK_i: case SDLK_q: case SDLK_w:
      case SDLK_F1...SDLK_F12:
            return fontedit_handle_key(k);
      case SDLK_RETURN:
            if (status.dialog_type & (DIALOG_MENU|DIALOG_BOX)) return 0;
            if (selected_item == FONTLIST) {
                  handle_key_fontlist(k);
                  return 1;
            }
      default:
            break;
      };
      return 0;
}

static void do_nil(void) {}
void fontedit_load_page(struct page *page)
{
      page->title = "";
      page->draw_full = draw_screen;
      page->total_widgets = 1;
      page->pre_handle_key = fontedit_key_hack;
      page->widgets = fontedit_widget_hack;
      create_other(fontedit_widget_hack, 0, fontedit_handle_key, do_nil);
}

Generated by  Doxygen 1.6.0   Back to index