Subversion Repositories DIN Is Noise

Rev

Rev 2097 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
* font_editor.cc
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/


#include <fstream>
#include <iostream>
#include "font_editor.h"
#include "font.h"
#include "input.h"
#include "console.h"

using namespace std;

font_editor::font_editor (font& f, const string& settingsf, const string& helpf) :
  curve_editor (settingsf),
  fn (f),
  glyphs (f.get_chars()),
  moving(false) {
  prep_edit ();
  edit_char (0);
}

font_editor::~font_editor () {
  leave ();
}

void font_editor::leave () {
  save_font ();
}

void font_editor::save_font () {
  save_char (ichar);
  prep_save ();
}

void font_editor::edit_char (int i) {
  if (i > -1 && i < (int) glyphs.size()) {
    char c = chars[i];
    gl = glyphs[c];
    lines = gl.lines;
    cons << "char = " << c << " nlines = " << lines.size () << eol;
  }
}

void font_editor::save_char (int i) {
  if (i > -1 && i < (int)glyphs.size()) {
    gl.lines = lines;
    glyphs[chars[i]] = gl;
  }
}

void font_editor::prep_edit () {
  chars.clear ();
  for (map<char, glyph>::iterator i = glyphs.begin (), j = glyphs.end(); i != j; ++i) {
    const pair<char, glyph>& p = *i;
    glyph g (p.second);
    vector<line>& lines = g.lines;
    for (int s = 0, t = lines.size(); s < t; ++s) {
      vector < point<int> >& points = lines[s].points;
      for (int m = 0, n = points.size(); m < n; ++m) {
        point<int>& pt = points[m];
        float wx, wy;
        basic_editor::obj2win (pt.x / fnt.cellsize.x, pt.y / fnt.cellsize.x, wx, wy);
        pt.x = wx;
        pt.y = wy;
      }
    }
    chars.push_back (p.first);
    glyphs[p.first] = g;
  }
}

void font_editor::prep_save () {
  map<char, glyph> fg (glyphs);
  for (map<char, glyph>::iterator i = fg.begin (), j = fg.end(); i != j; ++i) {
    const pair<char, glyph>& p = *i;
    glyph g(p.second);
    vector<line>& lines = g.lines;
    for (int s = 0, t = lines.size(); s < t; ++s) {
      vector < point<int> >& points = lines[s].points;
      for (int m = 0, n = points.size(); m < n; ++m) {
        point<int>& pt = points[m];
        float ox, oy;
        basic_editor::win2obj (pt.x, pt.y, ox, oy);
        pt.x = ox * fnt.cellsize.x;
        pt.y = oy * fnt.cellsize.y;
      }
    }
    g.find_width_height ();
    fg[p.first] = g;

  }
  fn.set_chars (fg);
}

int font_editor::handle_input () {

  basic_editor::handle_input ();

  if (keypressed (SDLK_F1)) helptext ();

  if (keypressed (SDLK_f)) {
    float x, y; snap (x, y);
    scratch_points.push_back (point<float>(x, y));
  }

  if (keypressed (SDLK_g)) {
    if (scratch_points.size() > 1) lines.push_back (line(scratch_points));
    scratch_points.clear ();
  }

  if (keypressed (SDLK_r)) {
    if (moving) moving = false;
    else {
      cur = hittest ();
      if (cur()) moving = true; else cons << "no hit" << eol;
    }
  } else if (moving) move ();

  if (keypressed (SDLK_i)) {
    if (ins()) {
      float x, y; snap (x, y);
      lines[ins.l].insert (ins.v, x, y);
      ins = line_hit();
    } else ins = hittest ();
  }

  if (keypressed (SDLK_v)) {
    del = hittest ();
    if (del()) {
      if (keydown (SDLK_LSHIFT))
        lines.erase (lines.begin() + del.l);
      else {
        if (lines[del.l].remove (del.v) < 2) lines.erase (lines.begin() + del.l);
      }
    }
  }

  if (keypressedd (SDLK_LEFTBRACKET)) {
    if (ichar > 0) {
      save_char (ichar--);
      edit_char (ichar);
    }
  }

  if (keypressedd (SDLK_RIGHTBRACKET)) {
    if (ichar < ((int)chars.size() - 1)) {
      save_char (ichar++);
      edit_char (ichar);
    }
  }

  if (keypressed (SDLK_RETURN)) {
    save_font ();
  }

  return true;
}

void font_editor::draw () {
  project ();
    basic_editor::draw ();
    mark_area ();
    draw_lines ();
    draw_scratch_line ();
  unproject ();
}

line_hit font_editor::hittest () {
  float x, y; snap (x, y);
  cons << x << ' ' << y << eol;
  for (int i = 0, j = lines.size(); i < j; ++i) {
    const line& l = lines[i];
    for (int p = 0, q = l.points.size(); p < q; ++p) {
      const point<int>& pt = l.points[p];
      if ((pt.x == x) && (pt.y == y)) return line_hit (i, p);
    }
  }
  return line_hit ();
}

void font_editor::draw_scratch_line () {
  if (int npts = scratch_points.size ()) {
    float x, y; snap (x, y);
    glColor3f (0.7, 0.4, 0);
    glBegin (GL_LINE_STRIP);
      for (int i = 0; i < npts; ++i) glVertex2f (scratch_points[i].x, scratch_points[i].y);
      glVertex2f (x, y);
    glEnd();
  }
}

void font_editor::draw_lines () {
  glColor3f (1, 0.8, 0);
  for (int i = 0, j = lines.size(); i < j; ++i) lines[i].draw ();
}

void font_editor::move () {
  float x, y;
  snap (x, y);
  lines[cur.l].set (cur.v, x, y);
}

void font_editor::mark_area () {
  glColor3f (0.5, 0.25, 0.25);
  float wx, wy, ox = 0, oy = 2, owx, owy;
  basic_editor::obj2win (fnt.charwidth.max / fnt.cellsize.x, fnt.charheight.max / fnt.cellsize.y, wx, wy);
  basic_editor::obj2win (ox, oy, owx, owy);
  glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
    glRectf (0, 0, wx, wy);
  glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
  glBegin (GL_LINES);
    glVertex2f (owx, owy);
    glVertex2f (wx, owy);
  glEnd ();
}