Subversion Repositories DIN Is Noise

Rev

Rev 1479 | Rev 1713 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
* field.cc
* DIN Is Noise is copyright (c) 2006-2020 Jagannathan Sampath
* For more information, please visit https://dinisnoise.org/
*/



#include "field.h"
#include "font.h"
#include "utils.h"
#include "input.h"
#include "utils.h"
#include "tcl_interp.h"
#include "log.h"
#include "console.h"

#include <string>
#include <sstream>
#include <list>
#include <cstdlib>

using namespace std;
extern int lmb;
extern int mousex, mouseyy;
char get_typed_char ();
extern tcl_interp interpreter;
extern char BUFFER [];

int field::handle_input () {

  widget::handle_input ();

  // locate mouse in field
  if (lmb) {
    if (lmb_clicked == 0) {
      lmb_clicked = 1;
      if (hittest (mousex, mouseyy)) {
        calc_cursor ();
        edited |= 0;
        widget::focus = this;
      } else {
        if (widget::focus == this) {
          //call_listener ();
          defocus (this);
          lmb_clicked = 0;
          return 1;
        }
      }
    }
  } else {
    lmb_clicked = 0;
  }

  if (focus) { // can edit text

    char c = get_typed_char ();

    if (c != 0) {

      edited = 1;

      if (mode == pushback)
        text.push_back (c);
      else
        text.insert (text.begin() + cursor, c);

      ++len;
      ++last;
      ++cursor;

      calc_cursor ();

      if (typing_lsnr) typing_lsnr->typing (*this);

    }

    if (keypressed (SDLK_ESCAPE)) { // abort editing
      focus = 0;
      defocus (this);
      return 1;
    } else
    if (keypressed (SDLK_RETURN)) { // finished editing
      focus = 0;
      call_listener ();
      defocus(this);
      return 1;
    }
    else if (keypressedd (SDLK_LEFT)) { // move cursor left
      mode = insert;
      if (--cursor < 0) cursor = 0;
      calc_cursor ();
    } else if (keypressedd (SDLK_RIGHT)) { // move cursor right
      mode = insert;
      if (++cursor >= len) {
        cursor = len;
        mode = pushback;
      }
      calc_cursor ();
    } else if (keypressedd (SDLK_BACKSPACE)) { // delete
      if (cursor) {
        --cursor;
        --len;
        if (--last < 0) {
          last = 0;
          len = 0;
          mode = pushback;
        }
        string::iterator e = text.begin () + cursor;
        if (e != text.end()) text.erase (e);
        calc_cursor ();
        if (typing_lsnr) typing_lsnr->typing (*this);
        edited = 1;
      }
    }
  }
  return focus;

}

void field::set_text (const string& txt, int _edited) {
  edited = _edited;
  text = txt;
  len = text.length ();
  if (len == 0) {
    last = 0;
    cursor = 0;
  } else {
    last = len - 1;
    cursor = len;
  }
  mode = pushback;
  calc_cursor ();
}

void field::set_text (int i, int _edited) {
  sprintf (BUFFER, "%d", i);
  set_text (BUFFER, _edited);
}

void field::set_text (float f, int _edited) {
  sprintf (BUFFER, fmts[fmt], f);
  set_text (BUFFER, _edited);
}

void field::calc_cursor () {
  string cstr (text.substr (0, cursor));
  offset = get_char_width (cstr) - 2;
  update ();
}

void field::update () {
  const box<int>& e = extents;
  set_extents (e.left, e.bottom, e.left + get_char_width (text) + 2 * fnt.avg_char_width, e.bottom + fnt.max_char_height);
}

void field::draw_cursor (int x, int y) {
  static int pts [4] = {0};
  int cx = x + offset;
  pts[0]=cx;pts[1]=y;
  pts[2]=cx;pts[3]=y+fnt.max_char_height;
  glVertexPointer (2, GL_INT, 0, pts);
  glDrawArrays (GL_LINES, 0, 2);
}

void field::draw () {
  draw_and_fill_bbox ();
  int x = posx, y = posy;
  x += fnt.avg_char_width;
  if (focus) draw_cursor (x, y);
  draw_string (text, x, y);
}

void field::init () {
  lmb_clicked = 0;
  focus = 0;
  edited = 0;
  change_lsnr = 0;
  typing_lsnr = 0;
  type = "";
  expr = 1;
  fmt = dec3;
}

field::field () {
  set_text ("");
  init ();
}

field::field (int x, int y, const string& txt) {
  set_text (txt);
  set_pos (x, y);
  init ();
}

field::operator int() const {
  return (atoi (text.c_str()));
}

field::operator float() const {
  return ((float) atof (text.c_str()));
}

field::operator double() const {
  return atof (text.c_str());
}

field::operator short() const {
  return ((short) atoi(text.c_str()));
}

int field::hittest (int x, int y) {

  const box<int>& e = extents;

  if (hover) { // in the box

    focus = 1; // so got focus

    int n = text.length ();

    if (n == 0) {
      cursor = 0;
      mode = pushback;
      return focus;
    }

    // locate cursor in text
    //
    int l = e.left + fnt.avg_char_width, r;
    if (x <= l) {
      cursor = 0;
      mode = insert;
      return focus;
    }

    cursor = 0;
    int r0 = l;
    for (int i = 0; i < n; ++i) {
      r = r0 + get_char_width (text.substr (0, i + 1));
      if (inrange (l, x, r)) { // found!
        int rn = r - fnt.charspc;
        int xl = x - l, xr = rn - x;
        if (xl <= xr) cursor = i; else cursor = i + 1;
        if (cursor > last) {
          cursor = len;
          mode = pushback;
        } else mode = insert;
        return focus;
      }
      l = r;
    }
    cursor = len;
    mode = pushback;
    return focus;
  }

  focus = 0;
  return focus;

}

void field::call_listener () {
  if (edited) {
    if (expr) {
      sprintf (BUFFER, "eval-expr %s %s", text.c_str(), type.c_str());
      interpreter (BUFFER);
      if (interpreter.result_status == 0) {
        set_text (interpreter.result, 1);
        if (change_lsnr) change_lsnr->changed (*this);
      }
    } else {
      if (change_lsnr) change_lsnr->changed (*this);
    }
    edited = 0;
  }
}