/*******************************************************************************
+
+  LEDA 3.5
+
+  _x_basic.c
+
+  This file is part of the LEDA research version (LEDA-R) that can be 
+  used free of charge in academic research and teaching. Any commercial
+  use of this software requires a license which is distributed by the
+  LEDA Software GmbH, Postfach 151101, 66041 Saarbruecken, FRG
+  (fax +49 681 31104).
+
+  Copyright (c) 1991-1997  by  Max-Planck-Institut fuer Informatik
+  Im Stadtwald, 66123 Saarbruecken, Germany     
+  All rights reserved.
+ 
*******************************************************************************/

// defines the BASE_WINDOW operations declared in <LEDA/base_window.h>
// using the basic graphics routines from <LEDA/impl/x_basic.h>

#include <LEDA/base_window.h>
#include <LEDA/impl/x_basic.h>

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>

#if defined(unix)
#include <signal.h>
#include <sys/time.h>
#endif

inline double HyPot(double x, double y) { return sqrt(x*x + y*y); }

void BASE_WINDOW::REDRAW_FUNC(void* p)
{ BASE_WINDOW* w = (BASE_WINDOW*)p;
  w->clipping(0);
  w->draw_frame();
  w->clipping(2);
  drawing_mode save_mode = w->set_mode(src_mode);
  if (w->redraw2) w->redraw2(w,w->xreal(0),w->yreal(0), w->xreal(w->xdots),
                                                        w->yreal(w->ydots));
  else if (w->redraw1) w->redraw1(w);
       else if (w->redraw0) w->redraw0();

  w->set_mode(save_mode);
  if (w->mesg_count > 0) w->draw_messages();
 }


char* BASE_WINDOW::access_str(void*)
{ fprintf(stderr, "Use of BASE_WINDOW::access_str() is illegal.");
  return 0;
 }

void BASE_WINDOW::assign_str(void*,const char*)
{ fprintf(stderr, "Use of BASE_WINDOW::assign_str() is illegal.");
 }


int BASE_WINDOW::set_bg_color(int c) 
{ int save = bg_color; 
  bg_color = c; 
  return save;
 }


int BASE_WINDOW::set_fg_color(int c)
{ int save = fg_color; 
  fg_color = c; 
  return save;
 }

int  BASE_WINDOW::mono() { return x_display_depth() == 1; }


void BASE_WINDOW::set_buttons(int b0, int b1, int b2, int b3,
                              int s0, int s1, int s2, int s3)
{ button_table[0] = b0;
  button_table[1] = b1;
  button_table[2] = b2;
  button_table[3] = b3;
  shift_table[0]  = s0;
  shift_table[1]  = s1;
  shift_table[2]  = s2;
  shift_table[3]  = s3;
}


void BASE_WINDOW::set_buttons(int* new_value, int* save_values)
{ for(int i=0; i<4; i++) 
  { if (save_values)
    { save_values[i]   = button_table[i];
      save_values[i+4] = shift_table[i];
     }
    button_table[i] = new_value[i];
    shift_table[i]  = new_value[i+4];
  }
}

void BASE_WINDOW::std_buttons(int* save_values)
{ if (save_values)
    for(int i=0; i<4; i++) 
    { save_values[i]   = button_table[i];
      save_values[i+4] = shift_table[i];
     }
   set_buttons(NO_BUTTON,MOUSE_BUTTON(1),MOUSE_BUTTON(2),MOUSE_BUTTON(3),
               NO_BUTTON,MOUSE_BUTTON(1),MOUSE_BUTTON(2),MOUSE_BUTTON(3));
}

void BASE_WINDOW::old_buttons(int* save_values)
{ if (save_values)
    for(int i=0; i<4; i++) 
    { save_values[i]   = button_table[i];
      save_values[i+4] = shift_table[i];
     }
   set_buttons(0,1,2,3,0,-1,-2,-3);
}



void BASE_WINDOW::flush() { x_flush_display(); }


void BASE_WINDOW::clipping(int mode)
{ 
   switch (mode) {

   case 0: // entire window
           x_set_clip_rect(draw_win,0,0,window_width,window_height);
           break;

   case 1: // panel area
           x_set_clip_rect(draw_win,1,1,panel_width-2,panel_height-1);
           break;

   case 2: // drawing area
           x_set_clip_rect(draw_win,1,panel_height+1,window_width-2,
                             window_height-panel_height-2);
           break;
   }
}



void BASE_WINDOW::set_color(int c) 
{ if (!is_open()) display(-3,-1,0); // open if not open
  if (c == DEF_COLOR) c = fg_color;
  x_set_color(draw_win,c); 
 }


int BASE_WINDOW::is_open() 
{ return x_window_opened(draw_win); }

int BASE_WINDOW::is_closed() 
{ return x_window_opened(draw_win)==0; }


void BASE_WINDOW::set_frame_label(const char* label) 
{ x_set_header(draw_win,label); }

int BASE_WINDOW::load_text_font(const char* fname) 
{ return x_load_text_font(fname); }

int BASE_WINDOW::load_bold_font(const char* fname) 
{ return x_load_bold_font(fname); }

int BASE_WINDOW::load_fixed_font(const char* fname) 
{ return x_load_fixed_font(fname); }

int BASE_WINDOW::set_font(const char* fname) 
{ return x_set_font(draw_win,fname); }

void BASE_WINDOW::reset_frame_label() 
{ x_set_header(draw_win,default_frame_label); }

void BASE_WINDOW::set_grid_mode(int i) 
{ if (i != grid_mode) init(xmin(),xmax(),ymin(),i); }

int BASE_WINDOW::set_node_width(int w)
{ if (w < 1) w = 1;
  int save = node_width;
  node_width = w;
  return save;
 }


drawing_mode BASE_WINDOW::set_mode(drawing_mode m) 
{ return x_set_mode(draw_win,m); }

int BASE_WINDOW::set_line_width(int w)
{ if (w < 1) w = 1;
  return x_set_line_width(draw_win,w);
 }

line_style BASE_WINDOW::set_line_style(line_style s)
{ return x_set_line_style(draw_win,s); }


int BASE_WINDOW::set_join_style(int js)
{ return x_set_join_style(draw_win,js); }

text_mode BASE_WINDOW::set_text_mode(text_mode m)
{ return x_set_text_mode(draw_win,m); }

 
void BASE_WINDOW::set_redraw(win_redraw_func2 f) 
{ redraw2 = f;  
  redraw0 = 0;
  redraw1 = 0;
}

void BASE_WINDOW::set_redraw(win_redraw_func1 f) 
{ redraw1 = f; 
  redraw0 = 0;
  redraw2 = 0;
}

void BASE_WINDOW::set_redraw(win_redraw_func0 f) 
{ redraw0 = f;
  redraw1 = 0;
  redraw2 = 0;
}


int BASE_WINDOW::get_line_width() 
{ return x_get_line_width(draw_win); }

line_style BASE_WINDOW::get_line_style() 
{ return x_get_line_style(draw_win); }

text_mode BASE_WINDOW::get_text_mode()       
{ return x_get_text_mode(draw_win);  }

drawing_mode BASE_WINDOW::get_mode()       
{ return x_get_mode(draw_win);       }

double  BASE_WINDOW::text_width(const char* s)
{ return x_text_width(draw_win,s)/scaling; }
 
double  BASE_WINDOW::text_height(const char* s)
{ return x_text_height(draw_win,s)/scaling; }
 


int BASE_WINDOW::read_event(int& k, double& x, double& y)
{ BASE_WINDOW* w=0;
  x_set_read_gc(draw_win);
  int e = event_handler(w,1);
  while (w != this) e = event_handler(w,1);
  x_reset_gc(draw_win);
  x = mouse_xreal;
  y = mouse_yreal;
  k = mouse_key;
  return e;
 }

int BASE_WINDOW::read_event(int& k, double& x, double& y, unsigned long& t)
{ BASE_WINDOW* w=0;
  x_set_read_gc(draw_win);
  int e = event_handler(w,1);
  while (w != this) e = event_handler(w,1);
  x_reset_gc(draw_win);
  x = mouse_xreal;
  y = mouse_yreal;
  k = mouse_key;
  t = event_time;
  return e;
 }


int BASE_WINDOW::read_event(int& k, double& x, double& y, unsigned long& t,
                                                          int timeout)
{ BASE_WINDOW* w=this;
  x_set_read_gc(draw_win);
  int e = event_handler(w,timeout);
  x_reset_gc(draw_win);
  if (w == this) 
  { x = mouse_xreal;
    y = mouse_yreal;
    k = mouse_key;
    t = event_time;
   }
  else e = no_event;
  return e;
 }


int BASE_WINDOW::get_event(int& k, double& x, double& y)
{ BASE_WINDOW* w=0;
  int e = event_handler(w,0);
  while (e != no_event && w != this) e = event_handler(w,0);
  x = mouse_xreal;
  y = mouse_yreal;
  k = mouse_key;
  return e;
 }


int BASE_WINDOW::event_handler(BASE_WINDOW*& w, int blocking)
{
  int win;
  int val,x,y,e;
  unsigned long t;

  if (blocking == 1)
     e = x_get_next_event(&win, &val, &x, &y, &t);
  else
     if (blocking > 1)
        { win = w->draw_win;
          e = x_get_next_event(&win, &val, &x, &y, &t,blocking);
         }
     else
        e = x_check_next_event(&win, &val, &x, &y, &t);

  //printf("w = %d k = %d  x = %d y = %d v = %d t = %d \n",win,e,x,y,val,t);

  if (win == 0 || e == no_event) 
  { w = 0;
    return no_event;
   }

  w = (BASE_WINDOW*)x_window_inf(win);

  if (e == timer_event) 
  { if (w->timer_action) 
    { drawing_mode save = x_set_mode(w->draw_win,src_mode);
      w->timer_action(w);
      x_set_mode(w->draw_win,save);
     }
    return e;
   }


  if (e != configure_event && e != exposure_event) 
  { 
    int panel_closed = 0;

    BASE_WINDOW* wp = BASE_WINDOW::active_window;

    while (wp && wp->p_win)
    { 
      if (e == motion_event && wp->p_win->panel_menu_mode == 0) break;

      if (x>=0 && x<=w->window_width && y>=0 && y<=w->window_height) break;

      if (e != button_press_event &&
          x>=w->hotx1 && x<=w->hotx2 && y>=w->hoty1 && y<=w->hoty2) break;

      panel_closed++;
      x_window_to_screen(wp->draw_win,&x,&y);
      wp = wp->p_win;
      x_screen_to_window(wp->draw_win,&x,&y);
      x_grab_pointer(wp->draw_win);
      w = wp;
      BASE_WINDOW::active_window = wp;
    }

   int v = w->panel_event_handler(w->draw_win,e,val,x,y,t); 

   if (v >= 0)
   { w = w->p_root;
     w->mouse_key = v;
     w->mouse_press_time = t;
     return button_press_event;
    }

   if (panel_closed || (y > 0 && y < w->panel_height)) return no_event;
  }


  switch (e) {

  case exposure_event:
      {  

         int wi = val;
         int he = (int)t;

         //printf("EXPOSE x0 = %d  y0 = %d w = %d h = %d \n",x,y,wi,he);
         //char text[256];
         //sprintf(text,"EXPOSE x0 = %d  y0 = %d w = %d h = %d \n",x,y,wi,he);
         //x_set_header(w->draw_win,text);


         // call configure() if window size has changed
         if (w->window_width  != x_window_width(w->draw_win) || 
             w->window_height != x_window_height(w->draw_win)) 
            w->configure();  

         x_set_clip_rect(w->draw_win,x,y,wi,he);

         if (y <= w->panel_height) 
         { w->draw_frame();
           x_flush_display();
           y = w->panel_height + 1;
           x_set_clip_rect(w->draw_win,x,y,wi,he);
          }


         if (w->redraw0 || w->redraw1 || w->redraw2) 
         { 
           drawing_mode save_mode = x_set_mode(w->draw_win,src_mode);
           int save_col = x_set_color(w->draw_win, w->bg_color);

           x_box(w->draw_win,x,y,x+wi,y+he);
           if (w->grid_mode) w->draw_grid(x,y,x+wi,y+he);


           //x_set_mode(w->draw_win,save_mode);
           x_set_color(w->draw_win,save_col);

           if (w->redraw2) 
              w->redraw2(w,w->xreal(x-1),w->yreal(y-1), w->xreal(x+wi+1), 
                                                        w->yreal(y+he+1));
           else 
              if (w->redraw1) w->redraw1(w);
                else if (w->redraw0) w->redraw0();


           x_set_color(w->draw_win, (w->win_parent==0) ? black : w->bg_color);
           x_set_mode(w->draw_win,src_mode);

           x_rect(w->draw_win,0,w->panel_height,w->window_width-1,
                                                w->window_height-1);
           x_set_mode(w->draw_win,save_mode);
           x_set_color(w->draw_win,save_col);
          }

         if (w->mesg_count > 0) {
           w->draw_messages();
         }

         w->clipping(2);

        break; 
       }


 case configure_event: // window position changed
           w->window_xpos = x;
           w->window_ypos = y;
           break; 

  case key_press_event:
  case key_release_event:
           w->mouse_key = val;
           w->mouse_xpix = x;
           w->mouse_ypix = w->ydots-y-1;
           break;



  case button_press_event:
           if (val >> 8)
              w->mouse_key = w->shift_table[val & 0xFF];
           else
              w->mouse_key = w->button_table[val & 0xFF];
           w->shift_key_state = val >> 8;
           w->mouse_xpix = x;
           w->mouse_ypix = w->ydots-y-1;
           w->mouse_press_time = t;
           break;

  case button_release_event:
           if (val >>8 )
              w->mouse_key = w->shift_table[val & 0xFF];
           else
              w->mouse_key = w->button_table[val & 0xFF];
           w->shift_key_state = val >> 8;
           w->mouse_xpix = x;
           w->mouse_ypix = w->ydots-y-1;
           w->mouse_release_time = t;
           break;

  case motion_event:

         w->mouse_xpix = x;
         w->mouse_ypix = w->ydots-y-1;
         break;
    }

  if (e==motion_event || e==button_press_event || e==button_release_event)
  { if (w->grid_mode) w->cursor();
    w->mouse_xreal =  w->min_xcoord + ((double)w->mouse_xpix)/w->scaling;
    w->mouse_yreal =  w->min_ycoord + ((double)w->mouse_ypix)/w->scaling;
          
    if (blocking)
    { if (w->grid_mode)
      { int g = w->grid_mode;
        w->mouse_xreal=g*(int)(w->mouse_xreal/g+((w->mouse_xreal>0)?0.5:-0.5));
        w->mouse_yreal=g*(int)(w->mouse_yreal/g+((w->mouse_yreal>0)?0.5:-0.5));
        w->cursor();
      }
       
      if (w->show_coord && blocking) w->show_coordinates();
            
      if (w->mouse_action && w == read_window) /* user defined action */
      { w->mouse_action(w->mouse_last_xreal,w->mouse_last_yreal);
        w->mouse_action(w->mouse_xreal,w->mouse_yreal);
      }
    }
    
    w->mouse_last_xreal = w->mouse_xreal;
    w->mouse_last_yreal = w->mouse_yreal;
  }

  w->event_time = t;

  return e;
}


int BASE_WINDOW::read_mouse(int kind, double xstart, double ystart, double &x, double &y)
{ 
  // 0: point, 1: segment, 2:rectangle, 3: circle 

  switch(kind) {
  case  0: return read_mouse_action(mouse_default_action,xstart,ystart,x,y);
  case  1: return read_mouse_action(mouse_segment_action,xstart,ystart,x,y);
  case  2: return read_mouse_action(mouse_rect_action,xstart,ystart,x,y);
  case  3: return read_mouse_action(mouse_circle_action,xstart,ystart,x,y);
  default: return read_mouse_action(mouse_default_action,xstart,ystart,x,y);
  }

}


int BASE_WINDOW::get_mouse(double& x, double& y)
{ 
  if (!is_open()) display(-3,-1,0); // open if not open

  int but = button_table[0]; // no button

  BASE_WINDOW* w;

  int e = event_handler(w,0);

  while ((w != this || e != button_press_event) && e != no_event) 
   e = event_handler(w,0);

  if (e != no_event) but = mouse_key;

  x = mouse_xreal;
  y = mouse_yreal;

  return but;
 }


unsigned long BASE_WINDOW::button_press_time()  { return mouse_press_time; }
unsigned long BASE_WINDOW::button_release_time(){ return mouse_release_time; }

int BASE_WINDOW::shift_key_down() { return shift_key_state == 1; }
int BASE_WINDOW::ctrl_key_down()  { return shift_key_state == 2; }
int BASE_WINDOW::alt_key_down()   { return 0; }




#if defined(unix)
static BASE_WINDOW* timer_win;
 
#if !defined(SIG_PF) && !defined(sgi)
typedef void (*SIG_PF)(int);
#endif

void BASE_WINDOW::timer_handler(int)
{ drawing_mode save_mode = timer_win->set_mode(src_mode);
  timer_win->timer_action(timer_win);
  timer_win->set_mode(save_mode);
  signal(SIGALRM,(SIG_PF)timer_handler);
 }
#endif


void BASE_WINDOW::start_timer(int msec, win_redraw_func1 F)
{ timer_action = F;
  x_start_timer(draw_win,msec); 
#if defined(unix)
  timer_win = this;
  signal(SIGALRM,(SIG_PF)timer_handler);

  static itimerval it;
  float fsec  = msec/1000.0;
  float usec  = 1000000*(fsec - int(fsec));
  it.it_interval.tv_sec  = int(fsec);
  it.it_interval.tv_usec = int(usec);
  it.it_value.tv_sec  = int(fsec);
  it.it_value.tv_usec = int(usec);
  setitimer(ITIMER_REAL, &it, NULL);
#endif
}

void BASE_WINDOW::stop_timer() 
{ timer_action = 0;
  x_stop_timer(draw_win); 
#if defined(unix)
  static itimerval it;
  setitimer(ITIMER_REAL, &it, NULL);
#endif
}


int BASE_WINDOW::read_mouse_action(mouse_action_func action, double xstart, 
                                                             double ystart, 
                                                             double &x, 
                                                             double &y)
{
  if (!is_open()) display(-3,-1,0); // open if not open

  read_window = this;

  mouse_action = action;

  drawing_mode s = x_set_mode(draw_win,xor_mode);
  x_set_read_gc(draw_win);

  mouse_key = 0;

  mouse_start_xreal = xstart;
  mouse_start_yreal = ystart;

  if (grid_mode) cursor();

  if (show_coord) show_coordinates();

  if (mouse_action) mouse_action(mouse_last_xreal,mouse_last_yreal);

  BASE_WINDOW* w;
  while (event_handler(w,1) != button_press_event || w != this);

  if (mouse_action) mouse_action(mouse_xreal,mouse_yreal);

  if (grid_mode) cursor();

  x = mouse_xreal;
  y = mouse_yreal;

  x_reset_gc(draw_win);
  x_set_mode(draw_win,s);

  mouse_action = mouse_default_action;

  return mouse_key;
}


void BASE_WINDOW::close() 
{ // recursively close sub-windows
 if (this == active_window) active_window = 0;
 for(int i=0; i<item_count; i++)
 { panel_item it=Item[i];
   if (it->kind == Button_Item && it->ref)
   { BASE_WINDOW* wp = (BASE_WINDOW*)it->ref;
     if (wp->is_open()) wp->close();
    }
  }
 if (is_open()) x_close_window(draw_win); 
}


BASE_WINDOW::BASE_WINDOW(float width, float height, const char* frame_label)
{ create(width,height,frame_label); }


BASE_WINDOW::BASE_WINDOW(const char* frame_label)
{ int l  =  screen_height() - 30;
  if (l > 600) l = 600;
  create(l,l,frame_label); 
 }

BASE_WINDOW::BASE_WINDOW()
{ int l  =  screen_height() - 30;
  if (l > 600) l = 600;
  create(l,l,""); 
 }


BASE_WINDOW::~BASE_WINDOW() 
{ close();
  for(int i = 0; i<item_count; i++) delete Item[i];
  x_destroy_window(draw_win);
  if (owner_item) owner_item->ref = 0;
  if (--win_count==0) x_close_display(); 
 }



void BASE_WINDOW::create(float w_width, float w_height, const char* label)
{
  //LEDA::write_log(string("window (%s)",label));

  if (win_count==0) x_open_display();
  win_count++;

  float fy = (x_display_height()-28)/w_height;
  if (0 < fy && fy < 1)
  { w_height *= fy;
    //w_width  *= (fy+2)/3;
   }

  float fx = (x_display_width()-16)/w_width;
  if (0 < fx && fx < 1)
  { w_height *= fx;
    w_width  *= fx;
   }


  active_window = this;
  p_root = this;
  p_win = 0;

  win_parent = 0;

  state = 1;
  window_width  = int(w_width);
  window_height = int(w_height);
  bg_color = white;
  fg_color = black;
  strcpy(default_frame_label,label);

  panel_init();

/*
  draw_win = x_create_window(this, window_width, window_height, bg_color, 
                             default_frame_label,"LEDA WINDOW",0,REDRAW_FUNC);
*/

  draw_win = x_create_window(this, window_width, window_height, bg_color, 
                             default_frame_label,default_frame_label,0,REDRAW_FUNC);

  x_set_color(draw_win,black);
  x_set_text_font(draw_win);
  x_set_mode(draw_win,src_mode);
  x_set_line_style(draw_win,solid);
  x_set_line_width(draw_win,1);
  x_set_text_mode(draw_win,transparent);

  set_show_coordinates(0);
  set_show_cursor(1);
  set_node_width(11);

  redraw0 = 0;
  redraw1 = 0;
  redraw2 = 0;

  timer_action = 0;

  hotx1 = 0;
  hotx2 = 0;
  hoty1 = 0;
  hoty2 = 0;

  mesg_count = 0;
  win_flush = 1;

  scaling = 1;
  min_xcoord = 0;
  min_ycoord = 0;
  max_xcoord = 100;
  max_ycoord = 100;
  mouse_xpix = 0;
  mouse_ypix = 0;
  shift_key_state = 0;
  grid_mode  = 0;
  owner_item = 0;
  set_buttons(NO_BUTTON,MOUSE_BUTTON(1),MOUSE_BUTTON(2),MOUSE_BUTTON(3),
              NO_BUTTON,MOUSE_BUTTON(1),MOUSE_BUTTON(2),MOUSE_BUTTON(3));
}



void BASE_WINDOW::display(int w_xpos, int w_ypos, BASE_WINDOW* w)
{
  if (x_window_opened(draw_win)) 
  { clipping(0);
    redraw_panel();
    clipping(2);
    return;
   }

  x_open_display();

  int pw = 0;

  if (w)
  { if (w != this)  
      pw = w->draw_win;
    else
     { pw = -1;
       w = 0;
      }
   }


  // open parent if closed
  if (w && w->is_closed()) w->display(-3,-1,0);

  win_parent = w;

  if (item_count > 0)
  { 
    panel_width = window_width;
    place_panel_items();
    window_width  = panel_width;
    if (window_height == -1)  window_height = panel_height;
   }


  int parent_width = (w==0) ? screen_width() : w->width();
  int parent_height= (w==0) ? screen_height() : w->height() - w->panel_height;


  int yshift = 0;

  if (w && w->window_height > w->panel_height && w_ypos == -2) 
  { // center on drawing area
    yshift =  w->panel_height;
    //parent_width -= yshift;
   }


  if (w_xpos < 0)
    switch (w_xpos) {
    case -1 : w_xpos = 0;
              break;
    case -2 : w_xpos = (parent_width - window_width - 10)/2;
              break;
    case -3 : w_xpos = parent_width - window_width;
              if (w==0) w_xpos -=10;
              break;
    }

  if (w_ypos < 0)
    switch (w_ypos) {
    case -1 : w_ypos = 0;
              break;
    case -2 : w_ypos = (parent_height - window_height - 30)/2;
              break;
    case -3 : w_ypos = parent_height - window_height;
              if (w==0) w_ypos -=30;
              break;
    }

  if (w_xpos < 0) w_xpos = -w_xpos - window_width  - 12;
  if (w_ypos < 0) w_ypos = -w_ypos - window_height - 24;

  window_xpos = w_xpos;
  window_ypos = w_ypos + yshift;

  x_open_window(draw_win,window_xpos,window_ypos,window_width,window_height,pw);

  if (pw == 0)  // frame
  { window_xpos += 6;
    window_ypos += 24;
   }


  configure();
  clipping(0);
  draw_frame();
  clipping(2);
  clear(bg_color);
}



void BASE_WINDOW::quit_action(int)
{ x_close_display();
  exit(0);
 }


int BASE_WINDOW::panel_open(int x, int y, BASE_WINDOW* w)
{ 
  if (but_count==0) // panel without buttons
  { button("continue",0,panel_action_func(0));
    button("quit",1,quit_action);
   }
  //if (w == 0) w = this;
  display(x,y,w);
  int b = read_mouse();
  close();
  return b;
 }




void BASE_WINDOW::draw_frame()
{ drawing_mode save_mode  = x_set_mode(draw_win,src_mode);
  line_style   save_style = x_set_line_style(draw_win,solid);
  draw_panel_items();
  clipping(0);
  if (window_height > panel_height)
  { x_set_color(draw_win, (win_parent == 0) ? black : bg_color);
    x_rect(draw_win,0,panel_height,window_width-1,window_height-1);
   }
  x_set_line_style(draw_win,save_style);
  x_set_mode(draw_win,save_mode);
}



void BASE_WINDOW::configure()
{
  int panel_only = (panel_height == window_height); 

  window_width  = x_window_width(draw_win);
  window_height = x_window_height(draw_win);

  if (item_count > 0) 
  { panel_width = window_width;
    place_panel_items();
   }

  if (panel_only) panel_height = window_height;

  xdots = window_width;
  ydots = window_height;

  scaling = ((double)xdots)/(max_xcoord-min_xcoord);

  if ((grid_mode) && (grid_mode*scaling < 4))
  { // at least grid distance of 4 pixels
    grid_mode=0; 
    fprintf(stderr,"warning: grid distance to small.\n");
   }

  if (grid_mode)
    { max_xcoord = min_xcoord+int(xdots/scaling);
      max_ycoord = min_ycoord+int((ydots-panel_height)/scaling);
     }
  else
    { max_xcoord = min_xcoord+xdots/scaling;
      max_ycoord = min_ycoord+(ydots-panel_height)/scaling;
     }

  xorigin = (int)(-min_xcoord*scaling);
  yorigin = (int)(ydots+min_ycoord*scaling);

  mouse_xreal = 0;
  mouse_yreal = 0;
}



void BASE_WINDOW::init(double x0, double x1, double y0, int g_mode)
{ if (x0 >= x1)
  { fprintf(stderr,"illegal arguments in W.init: x0 (%f) >= x1 (%f)\n",x0,x1);
    abort();
  }
  min_xcoord = x0;
  max_xcoord = x1;
  min_ycoord = y0;
  grid_mode  = g_mode;
  configure();
  clear(bg_color);
 }




void BASE_WINDOW::show_coordinates()
{ char s[128];
  sprintf(s,"%8.2f %8.2f", mouse_xreal,mouse_yreal);
  text_mode save_tm = x_set_text_mode(draw_win,opaque);
  drawing_mode save_dm = x_set_mode(draw_win,src_mode);
  int save_col = x_set_color(draw_win, black);
  x_text(draw_win,window_width-x_text_width(draw_win,s)-2, panel_height+2,s);
  x_set_text_mode(draw_win,save_tm);
  x_set_mode(draw_win,save_dm);
  x_set_color(draw_win, save_col);
}

int BASE_WINDOW::query_pix(double x, double y)
{ return x_get_pixel(draw_win,xpix(x),ypix(y)); }


void BASE_WINDOW::draw_pix(double x, double y, int col)
{ set_color(col);
  x_pixel(draw_win,xpix(x),ypix(y));
  if (win_flush) flush();
}

void BASE_WINDOW::draw_pixels(int n, double* xcoord, double* ycoord, int col)
{ set_color(col);
  int* x = new int[n];
  int* y = new int[n];
  int i;
  for(i=0;i<n;i++)
  { x[i] = xpix(xcoord[i]);
    y[i] = ypix(ycoord[i]);
   }
  x_pixels(draw_win,n,x,y); 
  delete[] x;
  delete[] y;
  if (win_flush) flush();
}



void BASE_WINDOW::draw_point(double x, double y, int col)
{ set_color(col);
  x_point(draw_win,xpix(x),ypix(y));
  if (win_flush) flush();
}


void BASE_WINDOW::draw_segment(double x1, double y1, double x2, double y2, int col)
{ set_color(col);
  x_line(draw_win, xpix(x1), ypix(y1), xpix(x2), ypix(y2));
  if (win_flush) flush();
}


void BASE_WINDOW::draw_segments(int n, double* xcoord1, double* ycoord1, 
                                       double* xcoord2, double* ycoord2, int col)
{ set_color(col);

  int* x1 = new int[n];
  int* y1 = new int[n];
  int* x2 = new int[n];
  int* y2 = new int[n];
  int i;

  for(i=0;i<n;i++)
  { x1[i] = xpix(xcoord1[i]);
    y1[i] = ypix(ycoord1[i]);
    x2[i] = xpix(xcoord2[i]);
    y2[i] = ypix(ycoord2[i]);
   }

  x_lines(draw_win,n,x1,y1,x2,y2); 

  delete[] x1;
  delete[] y1;
  delete[] x2;
  delete[] y2;
  if (win_flush) flush();
}


void BASE_WINDOW::draw_line(double x1, double y1, double x2, double y2, int col)
{
  double dx = x2 - x1;
  double dy = y2 - y1;

  if (dx == 0 && dy == 0)
  { draw_pix(x1,y1,col);
    return;
   }

  double xl = xmin();
  double yl = ymin();
  double xr = xmax();
  double yr = ymax();

  if (fabs(dy) < fabs(dx))
  { yl = y1 + (xl-x1)*dy/dx;
    yr = y1 + (xr-x1)*dy/dx;
   }
  else
  { xl = x1 + (yl-y1)*dx/dy;
    xr = x1 + (yr-y1)*dx/dy;
   }

  BASE_WINDOW::draw_segment(xl,yl,xr,yr,col);

}



void BASE_WINDOW::draw_ray(double x1, double y1, double x2, double y2, int col)
{
  double dx = x2 - x1;
  double dy = y2 - y1;

  if (dx == 0 && dy == 0)
  { draw_pix(x1,y1,col);
    return;
   }

  double x,y;

  if (fabs(dy) < fabs(dx))
    { x = (x1 < x2) ? xmax() : xmin();
      y = y1 + (x-x1)*dy/dx;
     }
  else
    { y = (y1 < y2) ? ymax() : ymin();
      x = x1 + (y-y1)*dx/dy;
     }

  BASE_WINDOW::draw_segment(x1,y1,x,y,col);

}



void BASE_WINDOW::draw_arc(double x0, double y0, double r1, double r2, 
                                                            double start, 
                                                            double angle, 
                                                            int col)
{  set_color(col);
  int R1 = (int)(r1*scaling);
  int R2 = (int)(r2*scaling);
  x_arc(draw_win,xpix(x0),ypix(y0),R1,R2,start,angle);
  if (win_flush) flush();
}

void BASE_WINDOW::draw_filled_arc(double x0, double y0, double r1, double r2, 
                                                                   double start,
                                                                   double angle,
                                                                   int col)
{ set_color(col);
  int R1 = (int)(r1*scaling);
  int R2 = (int)(r2*scaling);
  x_fill_arc(draw_win,xpix(x0),ypix(y0),R1,R2,start,angle);
  if (win_flush) flush();
}


void BASE_WINDOW::draw_node(double x0, double y0, int col)
{ int save = x_set_line_width(draw_win,1);
  double R = node_width/scaling;
  draw_circle(x0,y0,R,col);
  x_set_line_width(draw_win,save);
 }

void BASE_WINDOW::draw_filled_node(double x0, double y0, int col)
{ int X = xpix(x0);
  int Y = ypix(y0);
  set_color(col);
  x_fill_circle(draw_win,X,Y,node_width);
  int save = x_set_line_width(draw_win,1);
  x_circle(draw_win,X,Y,node_width);
  set_color(black);
  x_circle(draw_win,X,Y,node_width);
  x_set_line_width(draw_win,save);
  if (win_flush) flush();
 }


void BASE_WINDOW::draw_text_node(double x0, double y0, const char *s, int col)
{ text_mode t_save = x_set_text_mode(draw_win,transparent);
  x_set_bold_font(draw_win);

  if (col == DEF_COLOR) col = bg_color;

  if (mono() && col!=black) col = white;
  draw_filled_node(x0,y0,col);
  
  draw_ctext(x0,y0,s,col);

  if (col == black || col == blue || col == violet || col == brown) 
     draw_ctext(x0,y0,s,white);
  else
     draw_ctext(x0,y0,s,black);

  x_set_text_mode(draw_win,t_save);
  x_set_text_font(draw_win);
}

void BASE_WINDOW::draw_int_node(double x0, double y0, int i, int col)
{ char buf[16];
  sprintf(buf,"%d",i);
  draw_text_node(x0,y0,buf,col);
 }


void BASE_WINDOW::draw_edge(double x1, double y1, double x2, double y2, int col)
{ 
  double dx = x2-x1;
  double dy = y2-y1;
  double L  = scaling*HyPot(dx,dy);

  if (L > 2*node_width)
  { set_color(col);
    double l  = double(node_width+1)/L;
    x1 += l*dx;
    x2 -= l*dx;
    y1 += l*dy;
    y2 -= l*dy;
    x_line(draw_win,xpix(x1),ypix(y1),xpix(x2),ypix(y2));
    if (win_flush) flush();
   }
}
 

void BASE_WINDOW::draw_circle(double x0, double y0, double r, int col)
{ set_color(col);
  int R = (int)(r*scaling);
  x_circle(draw_win,xpix(x0),ypix(y0),R);
  if (win_flush) flush();
 }


void BASE_WINDOW::draw_filled_circle(double x0, double y0, double r, int col)
{ set_color(col);
  int R = (int)(r*scaling);
  if (R > 0)
     x_fill_circle(draw_win,xpix(x0),ypix(y0),R);
  else
     x_pixel(draw_win,xpix(x0),ypix(y0));
  if (win_flush) flush();
 }


void BASE_WINDOW::draw_ellipse(double x0, double y0, double a, double b, int col)
{ set_color(col);
  int R1 = (int)(a*scaling);
  int R2 = (int)(b*scaling);
  x_ellipse(draw_win,xpix(x0),ypix(y0),R1,R2);
  if (win_flush) flush();
 }


void BASE_WINDOW::draw_filled_ellipse(double x0, double y0, double a, double b, int col)
{ set_color(col);
  int R1 = (int)(a*scaling);
  int R2 = (int)(b*scaling);
  x_fill_ellipse(draw_win,xpix(x0),ypix(y0),R1,R2);
  if (win_flush) flush();
 }



void BASE_WINDOW::plot_xy(double x0, double x1, win_draw_func f, int col)
{
  set_color(col);

  int *xcoord;
  int *ycoord;

  int x = xpix(x0);
  int y_old = ypix((*f)(x0));
  int i,y_new;
  int size = 0;
  int n = 0;


  for(x = xpix(x0)+1; x <= xpix(x1); x++)
  { y_new = ypix((*f)(xreal(x)));
    if (y_new > y_old)
       size += (y_new-y_old+1);
    else
       size += (y_old-y_new+1);
    y_old = y_new;
   }

  xcoord = new int[size];
  ycoord = new int[size];

  y_old = ypix((*f)(x0));

  for(x = xpix(x0)+1; x <= xpix(x1); x++)
  { y_new = ypix((*f)(xreal(x)));
    if (y_new > y_old)
      for(i=y_old; i<=y_new; i++) 
      { xcoord[n] = x;
        ycoord[n] = i;
        n++;
       }
    else
      for(i=y_old; i>=y_new; i--) 
      { xcoord[n] = x;
        ycoord[n] = i;
        n++;
       }
    y_old = y_new;
  }

 x_pixels(draw_win,size,xcoord,ycoord);
 
 delete[] xcoord;
 delete[] ycoord;

  if (win_flush) flush();
}


void BASE_WINDOW::plot_yx(double y0, double y1, win_draw_func f, int col)
{
  set_color(col);

  int *xcoord;
  int *ycoord;

  int y;
  int i,x_new;
  int x_old = xpix((*f)(y0));
  int size = 0;
  int n = 0;


  for(y = ypix(y0)-1; y >= ypix(y1); y++)
  { x_new = xpix((*f)(yreal(y)));
    if (x_new > x_old)
       size += (x_new-x_old+1);
    else
       size += (x_old-x_new+1);
    x_old = x_new;
   }

  xcoord = new int[size];
  ycoord = new int[size];

  x_old = xpix((*f)(y0));

  for(y = ypix(y0)-1; y >= ypix(y1); y--)
  {
    x_new = xpix((*f)(yreal(y)));
    if (x_new > x_old)
      for(i=x_old; i<=x_new; i++) 
      { xcoord[n] = i;
        ycoord[n] = y;
        n++;
       }
    else
      for(i=x_old; i>=x_new; i--) 
      { xcoord[n] = i;
        ycoord[n] = y;
        n++;
       }
    x_old = x_new;
  }

 x_pixels(draw_win,size,xcoord,ycoord);
 
 delete[] xcoord;
 delete[] ycoord;

 if (win_flush) flush();
}


void BASE_WINDOW::draw_filled_polygon(int n, double *xcoord, double *ycoord, int col)
{
 set_color(col);

 int* x = new int[n];
 int* y = new int[n];
 int i;

 for(i=0;i<n;i++)
 { x[i] = xpix(xcoord[i]);
   y[i] = ypix(ycoord[i]);
  }


 x_fill_polygon(draw_win,n,x,y);

 delete[] x;
 delete[] y;

  if (win_flush) flush();
}

void BASE_WINDOW::draw_polygon(int n, double *xcoord, double *ycoord, int col)
{
 set_color(col);

 int* x = new int[n];
 int* y = new int[n];
 int i;

 for(i=0;i<n;i++)
 { x[i] = xpix(xcoord[i]);
   y[i] = ypix(ycoord[i]);
  }


 x_polygon(draw_win,n,x,y);

 delete[] x;
 delete[] y;

  if (win_flush) flush();
}


/*
void BASE_WINDOW::draw_polygon(int n, double *xcoord, double *ycoord, int col)
{ int i;

  for(i=0;i<n-1;i++)
    draw_segment(xcoord[i],ycoord[i], xcoord[i+1],ycoord[i+1],col);

  draw_segment(xcoord[n-1],ycoord[n-1],xcoord[0],ycoord[0],col);

  if (win_flush) flush();

 }
*/


void BASE_WINDOW::draw_rectangle(double x1, double y1, double x2, double y2, int col)
{ set_color(col);
  x_rect(draw_win,xpix(x1),ypix(y1),xpix(x2),ypix(y2));
  if (win_flush) flush();
 }


void BASE_WINDOW::draw_filled_rectangle(double x1, double y1, double x2, double y2, int col)
{ set_color(col);
  x_box(draw_win,xpix(x1),ypix(y1),xpix(x2),ypix(y2));
  if (win_flush) flush();
 }


char* BASE_WINDOW::create_bitmap(int w, int h, char* pr_data)
{ return x_create_bitmap(draw_win,w,h,pr_data); }

char* BASE_WINDOW::create_pixrect(int w,int h,char* pr_data,int fcol,int bcol)
{ return x_create_pixrect(draw_win,w,h,pr_data,fcol,bcol); }

char* BASE_WINDOW::create_pixrect(char** xpm)
{ return x_create_pixrect(draw_win,xpm); }


char* BASE_WINDOW::get_pixrect(double x1, double y1, double x2, double y2)
{ clipping(0);
  drawing_mode save_mode = x_set_mode(draw_win,src_mode);
  x_set_color(draw_win,white);
  x_rect(draw_win,0,panel_height,window_width-1,window_height-1);
  char* pr = x_create_pixrect(draw_win, xpix(x1), ypix(y2), xpix(x2), ypix(y1));
  x_set_color(draw_win,black);
  x_rect(draw_win,0,panel_height,window_width-1,window_height-1);
  x_set_mode(draw_win,save_mode);
  clipping(2);
  return pr;
 }


char* BASE_WINDOW::get_window_pixrect()
{ clipping(0);
  drawing_mode save_mode = x_set_mode(draw_win,src_mode);
  x_set_color(draw_win,white);
  x_rect(draw_win,0,panel_height,window_width-1,window_height-1);
  char* pr = x_create_pixrect(draw_win,0,0, window_width-1, window_height-1);
  x_set_color(draw_win,black);
  x_rect(draw_win,0,panel_height,window_width-1,window_height-1);
  x_set_mode(draw_win,save_mode);
  clipping(2);
  return pr;
 }



char* BASE_WINDOW::get_buffer_pixrect() 
{ return x_get_buffer_pixrect(draw_win); }



void BASE_WINDOW::put_bitmap(double x, double y, char* bm, int col)
{ x_set_color(draw_win,col);
  x_insert_bitmap(draw_win, xpix(x), ypix(y), bm); 
  if (win_flush) flush();
 }


void  BASE_WINDOW::put_pixrect(double x, double y, char* rect)
{ x_insert_pixrect(draw_win, xpix(x), ypix(y), rect); 
  if (win_flush) flush();
 }

void  BASE_WINDOW::put_pixrect(double x, double y, char* rect, int x0, 
                                                               int y0, 
                                                               int width, 
                                                               int height)
{ x_insert_pixrect(draw_win, xpix(x), ypix(y), rect, x0, y0, width,height);
  if (win_flush) flush();
 }


void  BASE_WINDOW::put_pixrect(char* rect)
{ x_insert_pixrect(draw_win,rect); 
  if (win_flush) flush();
 }

void  BASE_WINDOW::del_bitmap(char* rect) { x_delete_bitmap(rect); }
void  BASE_WINDOW::del_pixrect(char* rect) { x_delete_pixrect(rect); }

int BASE_WINDOW::get_width(char* rect)
{ int w,h;
  x_pixrect_dimensions(rect,&w,&h);
  return w;
}

int BASE_WINDOW::get_height(char* rect)
{ int w,h;
  x_pixrect_dimensions(rect,&w,&h);
  return h;
}


void BASE_WINDOW::copy_rect(double x1, double y1, double x2, double y2, double x, double y)
{ x_copy_pixrect(draw_win,xpix(x1),ypix(y2),xpix(x2),ypix(y1),xpix(x),ypix(y));
  if (win_flush) flush();
 }

void BASE_WINDOW::draw_grid()
{ draw_grid(0,panel_height,window_width,window_height); }

void BASE_WINDOW::draw_grid(int xmin, int ymin, int xmax, int ymax)
{
  int  n = (int)((max_xcoord - min_xcoord)/grid_mode + 1) *
           (int)((max_ycoord - min_ycoord)/grid_mode + 1);

  int  x0 = ((int)(min_xcoord/grid_mode))*grid_mode;
  int  y0 = ((int)(min_ycoord/grid_mode))*grid_mode;

  int* xcoord = new int[n];
  int* ycoord = new int[n];

  x_set_color(draw_win,black);

  int i = 0;
   for(double x = x0; x<=max_xcoord; x+=grid_mode)
     for(double y = y0; y<=max_ycoord; y+=grid_mode)
       { int xpi = xpix(x);
         int ypi = ypix(y);
         if (xmin <= xpi && xpi <= xmax && ymin <= ypi && ypi <= ymax)
         { xcoord[i] = xpi;
           ycoord[i] = ypi;
           i++;
          }
        }

   x_pixels(draw_win,i,xcoord,ycoord);

   delete[] xcoord;
   delete[] ycoord;
 }


void BASE_WINDOW::clear(int col)
{ 
  del_messages();

  drawing_mode save_mode = x_set_mode(draw_win,src_mode);

  if (col == DEF_COLOR) col = bg_color;
  if (mono() && col != black) col = white;

  set_color(col);
  x_box(draw_win,0,panel_height,window_width,window_height);

  if (grid_mode) 
    draw_grid(0,panel_height,window_width,window_height);

  x_set_mode(draw_win,save_mode);

 flush();
}




#define DRAW_MESSAGE(i,th)\
{ x_text(draw_win,10,panel_height+2+th*i,mesg_list[i]); }


void BASE_WINDOW::message(const char *s)
{ drawing_mode save_dm = x_set_mode(draw_win,xor_mode);
  text_mode    save_tm = x_set_text_mode(draw_win,transparent);

  mesg_list[mesg_count] = new char[strlen(s)+1];
  strcpy(mesg_list[mesg_count],s);

  set_color(black);
  int h = int(1.2 * x_text_height(draw_win,"H"));

  DRAW_MESSAGE(mesg_count,h);
  mesg_count++;

  x_set_text_font(draw_win);
  x_set_mode(draw_win,save_dm);
  x_set_text_mode(draw_win,save_tm);
  flush();
}

void BASE_WINDOW::draw_messages(void)
{ drawing_mode save_dm = x_set_mode(draw_win,xor_mode);
  text_mode    save_tm = x_set_text_mode(draw_win,transparent);
  set_color(black);
  int h = int(1.2 * x_text_height(draw_win,"H"));
  for(int i=0; i<mesg_count; i++) DRAW_MESSAGE(i,h);
  x_set_text_font(draw_win);
  x_set_mode(draw_win,save_dm);
  x_set_text_mode(draw_win,save_tm);
  flush();
}


void BASE_WINDOW::del_messages(void)
{ if (mesg_count > 0) draw_messages();
  while(mesg_count > 0) delete[] mesg_list[--mesg_count];
 }



void BASE_WINDOW::draw_text(double x, double y, const char *s, int col)
{ set_color(col);
  x_text(draw_win,xpix(x),ypix(y),s);
  if (win_flush) flush();
}


void BASE_WINDOW::draw_ctext(double x, double y, const char *s, int col)
{ set_color(col);
  x_ctext(draw_win,xpix(x),ypix(y),s);
  if (win_flush) flush();
}

void BASE_WINDOW::cursor(void)
{ if (show_grid_cursor && this == read_window)
  { x_set_read_gc(draw_win);
    int X = xpix(mouse_xreal);
    int Y = ypix(mouse_yreal);
    x_line(draw_win, X,Y,X+8,Y);
    x_line(draw_win, X,Y,X-8,Y);
    x_line(draw_win, X,Y,X,Y+8);
    x_line(draw_win, X,Y,X,Y-8);
   }
}

// define static members

BASE_WINDOW* BASE_WINDOW::active_window = 0;
BASE_WINDOW* BASE_WINDOW::read_window = 0;
int          BASE_WINDOW::win_count = 0;

int  BASE_WINDOW::screen_width(void)  { return x_display_width(); }
int  BASE_WINDOW::screen_height(void) { return x_display_height(); }

void BASE_WINDOW::mouse_default_action(double,double) 
{ /* do nothing */}

void BASE_WINDOW::mouse_segment_action(double x, double y) 
{ double x0 = read_window->mouse_start_xreal;
  double y0 = read_window->mouse_start_yreal;
  read_window->draw_segment(x0,y0,x,y,black); 
 }

void BASE_WINDOW::mouse_rect_action(double x, double y)
{ double x0 = read_window->mouse_start_xreal;
  double y0 = read_window->mouse_start_yreal;
  read_window->draw_rectangle(x0,y0,x,y,black);
 }

void BASE_WINDOW::mouse_circle_action(double x, double y)
{ double x0 = read_window->mouse_start_xreal;
  double y0 = read_window->mouse_start_yreal;
  read_window->draw_circle(x0,y0,HyPot(x-x0,y-y0),black);
 }


#include <fstream.h>

char* Read_Leda_Bitmap(const char* fname, int& w, int& h)
{
  ifstream bitmap(fname);

  unsigned char c1;
  unsigned char c2;

  bitmap.get(c1);
  bitmap.get(c2);

  w = 256*c2 + c1;

  bitmap.get(c1);
  bitmap.get(c2);

  h = 256*c2 + c1;

  int l = (w+7)/8;

  int n = l*h;

  char* map = new char[n];

  int i = 0;
  while(i<n && bitmap) 
  { char c;
    bitmap.get(c);
    if (c == char(0xff) || c == char(0x00))
       { unsigned char j;
         bitmap.get(j);
         while (j--) map[i++] = c;
        }
    else 
       map[i++] = c;
   }

  if (l % 2)
  { w += 8;
    char* map1 = new char[(l+1)*h];
    char* p = map1;
    char* q = map;
    for(i=0; i<n; i++)
    { *p++ = *q++;
      if (i % l == l-1) *p++ = char(0x00);
     }
  
    delete[] map;
    map = map1;
  }

  return map;
}




void BASE_WINDOW::start_buffering() { x_start_buffering(draw_win); }

void BASE_WINDOW::start_buffering(int w, int h) 
{ h += panel_height;
  x_start_buffering(draw_win,w,h);
  window_width  = w;
  window_height = h;
  clipping(0);
 }

void BASE_WINDOW::stop_buffering()  
{ x_stop_buffering(draw_win); 
  window_width  = x_window_width(draw_win);
  window_height = x_window_height(draw_win);
  clipping(2);
}

int  BASE_WINDOW::create_buffer()   { return x_create_buffer(draw_win); }
void BASE_WINDOW::delete_buffer()   { x_delete_buffer(draw_win); }


void BASE_WINDOW::flush_buffer(double x0, double y0, double x1, double y1)
{ x_flush_buffer(draw_win,xpix(x0),ypix(y0),xpix(x1),ypix(y1)); }

void BASE_WINDOW::flush_buffer() 
{ x_flush_buffer(draw_win,0,panel_height,window_width,window_height); }

void BASE_WINDOW::flush_buffer(double dx, double dy) 
{ x_flush_buffer(draw_win,0,panel_height,window_width,window_height,
                                         int(dx*scaling),int(-dy*scaling)); 
 }

void BASE_WINDOW::flush_buffer(double dx, double dy, 
                               double x0, double y0, double x1, double y1)
{ x_flush_buffer(draw_win,xpix(x0),ypix(y0),xpix(x1),ypix(y1),
                                         int(dx*scaling),int(-dy*scaling)); 
 }



// static members

int BASE_WINDOW::read_event(BASE_WINDOW*& wp, int& k, double& x, double& y)
{ 
  int e = BASE_WINDOW::event_handler(wp,1);
  if (wp)
  { x = wp->mouse_xreal;
    y = wp->mouse_yreal;
    k = wp->mouse_key;
   }
  return e;
 }


int BASE_WINDOW::get_event(BASE_WINDOW*& wp, int& k, double& x, double& y)
{ int e = BASE_WINDOW::event_handler(wp,0);
  if (wp)
  { x = wp->mouse_xreal;
    y = wp->mouse_yreal;
    k = wp->mouse_key;
   }
  return e;
 }


void BASE_WINDOW::put_back_event() 
{ x_put_back_event(); }


int BASE_WINDOW::read_mouse(BASE_WINDOW*& w, double& x, double& y)
{
  int e = BASE_WINDOW::event_handler(w,1);
 
  while (e != button_press_event && e != key_press_event) 
      e = BASE_WINDOW::event_handler(w,1);

  x = w->mouse_xreal;
  y = w->mouse_yreal;
  return w->mouse_key;
}


int BASE_WINDOW::get_mouse(BASE_WINDOW*& w, double& x, double& y)
{ 
  int but;

  if (BASE_WINDOW::event_handler(w,0) == button_press_event) 
      but = w->mouse_key;
  else
      but = w->button_table[0];  // no button

  x = w->mouse_xreal;
  y = w->mouse_yreal;

  return but;
}

void BASE_WINDOW::grab_mouse()   { x_grab_pointer(draw_win); }

void BASE_WINDOW::ungrab_mouse() { x_ungrab_pointer(); }



void* BASE_WINDOW::get_inf() { return data[0]; }

void* BASE_WINDOW::set_inf(void* x) 
{ void* tmp = data[0]; 
  data[0] = x; 
  return tmp; 
}



void BASE_WINDOW::set_icon_pixrect(char* pr) { x_set_icon_pixmap(draw_win,pr); }

