// -*- mode:C++ ; compile-command: "g++ -I.. -g -c Eqw.cc" -*-
#ifndef _EQW_H
#define _EQW_H
#include <vector>
#include <string>
#include "first.h"
#include "gen.h"
#include <FL/Fl_Window.H>
#include <FL/Fl_Menu.H>
#include <FL/Fl_Group.H>
#include <FL/Fl_Scrollbar.H>
#include <FL/Fl_Input.H>
#ifdef HAVE_LC_MESSAGES
#include <locale.h>
#endif
#include "giacintl.h"

#ifndef NO_NAMESPACE_GIAC
void make_new_help(const char *); // function called when tab pressed
namespace giac {
#endif // ndef NO_NAMESPACE_GIAC

#ifdef HAVE_LIBFLTK

  // utility for gen embedded widget memory desallocation
  void fltk_fl_widget_delete_function(void * ptr);
  extern bool pretty_input;
  bool is_semi_expr(const gen & g);
  extern std::vector<std::string> completion_tab;
  void Eqw_cb_scroll(Fl_Widget*, void*);

  class Eqw;
  class gen;

  class Eqw_Scrollbar : public Fl_Scrollbar {
  public:
    Eqw * eqwptr;
    bool vertical;
    Eqw_Scrollbar(int x,int y,int w,int h,Eqw * ptr,bool is_vertical):Fl_Scrollbar(x,y,w,h),eqwptr(ptr),vertical(is_vertical) { 
      Fl_Scrollbar * o= this;
      o->maximum(1000);
      o->step(10);
      o->slider_size(1);
      o->callback( (Fl_Callback*) Eqw_cb_scroll );
      if (is_vertical)
	o->type(FL_VERTICAL);
      else
	o->type(FL_HORIZONTAL);
    };
  };

  // Usage: in fluid, declare a Group, then make a Box with class Eqw
  // Make sure there is enough room in the group for the scrollbars
  class Eqw:public Fl_Window {
    virtual FL_EXPORT void draw();
    virtual FL_EXPORT int handle(int);
    virtual FL_EXPORT int in_handle(int);
    gen lastdata;
  public:
    gen data; // of type eqwdata or undef if empty
    attributs attr;
    bool modifiable;
    bool allow_immediate_eval;
    bool need_active_parse; // true if the active cell must be parsed
    int xleft,ytop; // position in pixels of the origin (global shift of image)
    int xsel,ysel; // begin mouse selection (PUSH event)
    int xcur,ycur; // position of the cursor (RELEASE event)
    int active_pos; // position of the cursor in string (active mode)
    int begin_sel,end_sel; // -1 do not take care, >=0 position of sel 
    void (* cb_enter) (Eqw * ); // callback when enter pressed
    void (* cb_escape) (Eqw * ); // callback when escape pressed
    void (* cb_backspace) (Eqw * ); // callback when full level selected and backspace pressed
    void (* cb_select) (const char * ); // callback when selection changed
    Eqw_Scrollbar * vscroll,* hscroll;
    Eqw(int x, int y, int w, int h);
    Eqw(int x, int y, int w, int h, const char* l,const gen & g);
    Eqw(int x, int y, int w, int h, const char* l,const gen & g,attributs mya);
    ~Eqw();
    void deselect();
    void select(); // Does not copy to clipboard
    void fl_select(); // Copy selection to clipboard
    void select_rectangle(int x,int y); // x,y are the end of the mouse selection
    void select_up(int mode); // mode is 1 for shifted key
    void select_down(int mode);
    void select_right(int mode);
    void select_left(int mode);
    void adjust_xy(); // recalculate xsel, ysel to begin top of selection
    // and xcur, ycur to end bottom of selection
    void adjust_xy_sel(); // same + recalc xleft
    void eval_function(const gen & f);
    // active_search is 1 if replacing active cell, 0 for selected cell
    // Active cell should always be an _EQW terminal data of type string
    bool replace_selection(const gen & f,bool active_search=false);
    void set_data(const gen & g);
    gen get_selection();
    gen get_data();
    void setscroll();
    void deselect_and_activate();
    void desactivate_and_select();
    void insure_something_selected();
    bool handle_key(unsigned char c,gen * act);
    bool handle_text(const std::string & s,gen * act);
    bool handle_text(const std::string & paste_s_orig);
    void remove_selection();
    gen * set_active(int x,int y); // activate cell at position x,y
    // return a pointer to the active cell gen or 0
    bool parse_desactivate(); // if false nothing was active, else select
    void replace_down_left_activate(const gen & g);
    unsigned max_history_size; // max number of level saved
    void save_data(); // save data to undo and undo history
    void rcl_data(); // swap data and lastdata
    // keep undo operations max_history_size times in undo_history
    vecteur undo_history; 
    bool is_selected(bool inside=false,bool active_search=false);
  };

  class Input_tab:public Fl_Input {
    int count;
    std::vector<std::string> hist;
    virtual FL_EXPORT int handle(int);    
    virtual FL_EXPORT void draw();
    public:
    FL_EXPORT Input_tab(int x,int y,int w,int h,const char * l= 0): Fl_Input(x, y, w, h, l) {count=0;};
  };

  // initialize to the inner form of a null active string
  gen Eqw_nullstring();
  gen Eqw_nullstring(const attributs & a,int windowhsize=0);
  gen Eqw_nullhistlevel();
  // function used internally
  void Eqw_select(gen & g,bool select,bool active_search=false);
  gen Eqw_compute_size(const gen & g,const attributs & a,int windowhsize);
  eqwdata Eqw_total_size(const gen & g);  
  gen Eqw_translate(const gen & g,int deltax,int deltay);
  void Eqw_vertical_adjust(int hp,int yp,int & h,int & y);
  bool Eqw_find_vector_pos(const_iterateur it,const_iterateur itend,int & i,int &nrows);
  // return -1 if not in a multistring, position otherwise
  int in_multistring(const gen & data,vecteur * & vptr);
  int in_multistring(const gen & data);
  void handle_newline(Eqw * eqwptr);
  // return a pointer to the selected object
  // it will modify g if for example a subsum of a sum is selected
  gen * Eqw_selected(gen & g,attributs & attr,int windowhsize,vecteur & position,bool active_search=false);

  // return a variable from the list of vars
  bool select_user_var(int dx,int dy,gen & ans,GIAC_CONTEXT);

#endif // HAVE_LIBFLTK

#ifndef NO_NAMESPACE_GIAC
} // namespace giac
#endif // ndef NO_NAMESPACE_GIAC

#endif // _EQW_H
