Article 2715 of comp.sources.unix:
Path: nntpd.lkg.dec.com!crl.dec.com!crl.dec.com!caen!hookup!uwm.edu!vixen.cso.uiuc.edu!newsfeed.internetmci.com!in1.uu.net!vixie!vixie!not-for-mail
From: wolf@prosun.first.gmd.de (Wolfgang Koehler)
Newsgroups: comp.sources.unix
Subject: v29i055: grafix-1.2 - a C++ library for easy X11 GUI apps, Part01/05
Date: 1 Dec 1995 11:59:03 -0800
Organization: Vixie Enterprises
Lines: 2944
Sender: vixie@vix.com
Approved: vixie@gw.home.vix.com
Message-ID: <1.817847834.9257@gw.home.vix.com>
NNTP-Posting-Host: gw.home.vix.com

Submitted-By: wolf@prosun.first.gmd.de (Wolfgang Koehler)
Posting-Number: Volume 29, Issue 55
Archive-Name: grafix-1.2/part01

Short Readme 
============
- Grafix is a C++-library that makes it very easy to write C++-programs 
  with graphic user interfaces for X-window. 

- Grafix is based on Unix and the X Window system.

- Grafix does not use any commercial code, like Motif, so it is totally free.

- Grafix is been ported and tested for Linux, SunOS and HP with X11R5/R6
  
- Grafix is small and fast since it is pure functionality without any 
  superfluous additives. 

- Grafix is written in C++ and to compile with g++ on all platforms.

- Grafix comes with all sources, so you can peek into implementation details
  and modify everything you don't like.

- Grafix includes classes for the basic window operations :
   - windows with automatic restoring for complex drawings (backing store)
   - several types of predefined button classes for different purposes :
     quit_button, delete_button, help_button, callback_button, toggle_button,
     instance_button, dump_button, hardcopy_button, ...
     all the buttons have a Motif-like three dimensional shape
   - popup-windows and pulldown-menus for selecting discrete values
   - help popups can be bound to any window
   - scrollbars for selecting contiguous values
   - windows with real-valued co-ordinate systems where the user has not to 
     worry about pixel co-ordinates
   - a simple edit window for entering strings
   - file selection boxes for openening files interactively
   - a predefined palette manager for color definitions 
   - a complete manager to handle the display of 2-dim functions 
     (given on a equidistant grid) as lattice or body
     in arbitrary perpective, shadowing and details zooming.

- Grafix has some example programs to show the basic functions,eg 
  "win-demo", "edit-demo", "file-browser", "calc", "pal-demo", etc.
     
- Grafix has several realistic demos, eg. the programs "one-dim" and "two-dim"
  which give a complete model of some numerical integration methods for the one
  or two dimensional advection equation.

- Grafix now has a graphical class browser

- There are some other applications of Grafix, eg. a driver for a frame grabber
  card with online viewing available.

To install the package
======================
1. unshar it 

2. check "grafix.mk" for the correct paths for Xlib (X11R6 or X11R5) -> XPATH
   and some include directories on your system. 
   Please, read README.txt if you have any problems.

3. gmake all : to build all demo programs

4. gmake demorun : to invoke a run of all demos

please read the files README.txt and HOWTO.txt for further infos !

#!/bin/sh
# This is Grafix, a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 11/08/1995 15:26 UTC by wolf@first.gmd.de
# Source directory /tmp_mnt/home/lisp/wolf/X/grafix
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#  47152 -rw-r--r-- window.c
#  34405 -rw-r--r-- window.h
#  14496 -rw-r--r-- lat_win.c
#  12071 -rw-r--r-- lat_man.c
#   6420 -rw-r--r-- reg_man.c
#   5700 -rw-r--r-- lattice.h
#   4571 -rw-r--r-- palette.c
#    484 -rw-r--r-- palette.h
#  20582 -rw-r--r-- files.c
#   1819 -rw-r--r-- files.h
#   7088 -rw-r--r-- smolark.c
#    249 -rw-r--r-- smolark.h
#   3405 -rw-r--r-- solver.c
#   7329 -rw-r--r-- animator.h
#  16979 -rw-r--r-- animator.c
#   1242 -rw-r--r-- wave.c
#     48 -rw-r--r-- three-nxnynz.h
#    875 -rw-r--r-- icon.h
#    576 -rw-r--r-- eventnames.h
#   7763 -rw-r--r-- README.txt
#  27886 -rw-r--r-- HOWTO.txt
#  17976 -rw-r--r-- COPYING
#   8540 -rw-r--r-- LOG.txt
#   1255 -rw-r--r-- TODO.txt
#   2263 -rw-r--r-- FAQ.txt
#   2469 -rw-r--r-- Makefile
#    967 -rw-r--r-- grafix.mk
#   3512 -rw-r--r-- calc.icon
#   3843 -rw-r--r-- tree.h
#  10325 -rw-r--r-- tree.c
#    890 -rw-r--r-- tree_icon.h
#   4186 -rw-r--r-- gccinc/features.h
#     16 -rw-r--r-- gccinc/regex.h
#  97336 -rw-r--r-- gccinc/rx.h
#   3859 -rw-r--r-- gccinc/sys/cdefs.h
#  15255 -rw-r--r-- class-browser.c
#    215 -rw-r--r-- hello.c
#   5505 -rw-r--r-- win-demo.c
#    696 -rw-r--r-- edit-demo.c
#   2123 -rw-r--r-- file-browser.c
#   2646 -rw-r--r-- cursors.c
#   5026 -rw-r--r-- calc.c
#   2455 -rw-r--r-- dir-tree.c
#    336 -rwxr-xr-x pal-demo.c
#   1914 -rw-r--r-- lat-demo.c
#   1283 -rw-r--r-- lat2demo.c
#   8600 -rw-r--r-- one-dim.c
#   8900 -rw-r--r-- two-dim.c
#   1215 -rw-r--r-- clock-demo.c
#   2910 -rw-r--r-- three-dim.c
#   6038 -rw-r--r-- replay.c
#    727 -rw-r--r-- scrolled_demo.c
#
# ============= window.c ==============
if test -f 'window.c' -a X"$1" != X"-c"; then
	echo 'x - skipping window.c (File already exists)'
else
echo 'x - extracting window.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'window.c' &&
// window.c : basic source file for the Grafix package
// the "GNU Public Lincense" policy applies to all programs of this package
// (c) Wolfgang Koehler, wolf@first.gmd.de, Dec. 1994
//     Kiefernring 15
//     14478 Potsdam, Germany
//     0331-863238
X
#include <assert.h>
#include "window.h"
#include "X11/Xutil.h"
#include "X11/cursorfont.h"
X
#include "eventnames.h" // from Xlib Manual
X
void error(char * message) {
X  fprintf(stderr,"fatal error: %s\n",message); exit(1); 
}
X
// linked list with pair (XID, window *)
class xlist {
public:
X  unsigned XW; // the XWindow ID = Win member of window
X  window *tw;  // the this pointer of associated window
X  xlist *next;
X  // constructor pushes a new entry in front of the rest list
X  xlist(unsigned XW, window *tw, xlist *rest) : XW(XW), tw(tw) { next = rest; }
};
X
// hash table mechanism used to map XWindow IDs to window pointers
// is needed to get a fast and flexible even handling
// implemented as a vector of xlist* (xltab)
// which is indexed with (WID % TABSIZE)
// each index is a simple linked list that stores the this pointer
// of the associated window 
X
// class for hash table with xlist entries
// constructor takes tabsize as argument; but size should not matter 
// unless we have really huge numbers of windows (event handling could be slow)
// public methods : xhadd, xhget, xhdel
class xhash {
X  xlist **xltab; // the actual hash table
X  unsigned tabsize;
X  unsigned Wind(unsigned Win) { return (Win % tabsize); }
public:
X  xhash(unsigned size) : tabsize(size) {
X    xltab = new (xlist*) [tabsize];
X    for (int i = 0; i < tabsize; i++) xltab[i] = NULL;
X  }
X  ~xhash() { delete[] xltab; }
X
X  // add a new entry in the hash table
X  void xhadd(unsigned Win, window *tw) {
X    // printf(" new win %x %p\n",Win,tw);
X    xltab[Wind(Win)] = new xlist(Win, tw, xltab[Wind(Win)]);
X  }
X  
X  // get the xlist pointer for Win
X  xlist *xhget(unsigned Win) { 
X    xlist *xptr;
X    for (xptr = xltab[Wind(Win)]; xptr; xptr = xptr->next)
X      if (xptr->XW == Win) break;
X    return xptr; // returns NULL if not found (usually deleted)
X  }
X
X  // delete the entry in the hash table : remove the cell by relinking
X  void xhdel(unsigned Win) { 
X    // printf("delete %x \n",Win);
X    xlist *xptr,*xxp = NULL; // the previous xlist pointer (points to -> xptr)
X    for (xptr = xltab[Wind(Win)]; xptr; xptr = xptr->next) {
X      if (xptr->XW == Win) break; xxp = xptr;
X    }
X    if (xxp) xxp->next = xptr->next; // relink the list (exclude xptr)
X    else xltab[Wind(Win)] = xptr->next; // it was the first entry to remove
X    delete (xptr); // the deleted entry 
X  }
X  // only for tests : read the hash table
X  xlist *xhread(int i) { return (xltab[i]); }
X
};
X
static xhash *xhatab; // the one and only xhash table for event handling
X  
// eg. for menu_bars : make place for picture in the Name-string !
char * ext_string(char * Name) { 
X  // printf("%s %d -> ",Name,strlen(Name)); fflush(stdout);
X  char * nn = new char[strlen(Name) + 3]; // delete not needed, marginal
X  sprintf(nn," %s ",Name); 
X  return nn; // _Name_
}
X
Display * display;
int screen;
GC gc_copy, gc_but_xor, gc_clear, gc_inv, gc_rubber; // some often used gcs
XXFontStruct * fixed_fn;       // and fonts
Cursor watch_cursor;
Cursor text_cursor;  // for edit_windows
Cursor hs_cursor, vs_cursor; // special cursors for scrollbars
X
unsigned depth;
unsigned black, white;
X
// convinience functions
GC CreateGC(unsigned long mask, XGCValues * gcv)
{ return XCreateGC(display, DefaultRootWindow(display), mask, gcv); }
X
// set default gc for line drawing etc.
void set_color(int color) {
X   static XGCValues values; 
X   values.foreground = color;
X   XChangeGC(display,gc_copy, GCForeground, &values);
}
X
Colormap def_cmap;
X
int alloc_color(unsigned red, unsigned green, unsigned blue) {
X  // allocation of a cmap-entry for given color -> returns pixel-value
X  // -1 failure : no free entry
X  XColor col = { 0, red, green, blue };
X  if (XAllocColor(display,def_cmap,&col) == 0) {   
X    printf(" Warning : Color map full (%x,%x,%x) \n",red,green,blue); 
X    return(-1); }
X  return col.pixel;
}
X
int alloc_named_color(char *colname) {
X  XColor col;
X  if (XAllocNamedColor(display,def_cmap,colname,&col,&col) == 0)
X    { error(" Color map full"); }
X  return col.pixel;
}
X
// the GCs for the button-representation
GC button_fg_gc, button_br_gc, button_lw_gc; 
int button_fg_pix, button_br_pix, button_lw_pix; // the button colors
X
Bool True_Color_Visual; // only for TrueColor -> no XAllocColorCells will work
X
// init global used screen values
void init_globals(char * DISP) { 
X  if (DISP == NULL) DISP = getenv("DISPLAY");
X  display = XOpenDisplay(DISP);   
X  if (display == NULL) { 
X    char s[100]; 
X    sprintf(s,"cannot open display '%s'",DISP);
X    error(s);
X  }
X
X  Visual *visual = DefaultVisual(display,screen);
X  int cl = visual->c_class;
X  True_Color_Visual = (cl == TrueColor);
X  // printf("Visual Class = %d  True_Col = %d\n",cl,  True_Color_Visual );
X  
X  screen = DefaultScreen(display);    
X  depth = XDefaultDepth(display,screen);
X  def_cmap = DefaultColormap(display,screen);
X  black = BlackPixel(display,screen);
X  white = WhitePixel(display,screen);
X
X  button_fg_pix = alloc_color(0x6180,0xa290,0xc300); // buttons inner part 
X  button_br_pix = alloc_color(0x8a20,0xe380,0xffff); // bright rim
X  button_lw_pix = alloc_color(0x30c0,0x5144,0x6180); // dark rim
X
X  XGCValues gcv; gcv.function = GXcopy ;     
X  gcv.foreground = black; gcv.background = white; 
X  gc_copy = CreateGC(GCFunction | GCForeground , &gcv);
X  
X  gcv.foreground = button_fg_pix ^ black; 
X  gcv.function = GXxor;
X  gc_but_xor = CreateGC(GCFunction | GCForeground , &gcv); 
X  // for xor-ing with button color (used in edit_window) 
X
X  gcv.function = GXcopy; 
X  gc_clear= CreateGC(GCFunction, &gcv);
X  // use white as *background* for clear !!!
X  // should be changed to custom color !
X  XSetForeground(display, gc_clear, white);
X  
X  gcv.function = GXinvert;
X  gc_inv = CreateGC(GCFunction, &gcv);
X
X //XGCValues={function,plane_mask,foreground,background,linewidth,linestyle,..}
X  XGCValues val_rubber = { GXinvert, AllPlanes,0,0,2, LineOnOffDash}; 
X
X  // rubberband for temp. coordinate lines
X  gc_rubber= CreateGC(GCFunction | GCPlaneMask | GCLineWidth | GCLineStyle, 
X		      &val_rubber); 
X
X  fixed_fn = XLoadQueryFont(display,"fixed");
X 
X  XGCValues values;
X  values.foreground = button_fg_pix;
X  button_fg_gc = CreateGC(GCForeground, &values);
X  values.foreground = button_br_pix;
X  button_br_gc =  CreateGC(GCForeground, &values);
X  values.foreground = button_lw_pix;
X  button_lw_gc =  CreateGC(GCForeground, &values);
X
X  watch_cursor = XCreateFontCursor(display,XC_watch);
X  text_cursor = XCreateFontCursor(display,XC_xterm);
X  hs_cursor = XCreateFontCursor(display, XC_sb_h_double_arrow); 
X  vs_cursor = XCreateFontCursor(display, XC_sb_v_double_arrow); 
X
}
X
#define TABSIZE 7 // the tabsize is really arbitrary ( > 0)
// if you think the buttons react too slowly you could increase this 
X 
window::window(char * DISP) { // constructor for root window
X  init_globals(DISP);
X  width = DisplayWidth(display,screen);
X  height = DisplayHeight(display,screen);
X  Win = DefaultRootWindow(display);  
X  children = NULL; // own children List = empty
X  parentw = NULL; // has no parent
X  xhatab = new xhash(TABSIZE);  
X  xhatab->xhadd(Win,this); // for safety reasons ; should not be needed
X  // printf(" root Window %x %d %d \n",Win, width, height);
};
X
int debug_create = False; // not defined in window.h (private)
X
window::window(window & parent, int w, int h, int x, int y, int bw) { 
X  width = (w ? w : parent.width) - 2*bw;
X  height = (h ? h : parent.height) - 2*bw;
X  border_width = bw;
X  parentw = &parent;
X  hidden = False;  CB_info = False;
X  mainw = parent.mainw; // simply pass through
X  children = NULL; // own children List = empty
X
X  parent.add_child(this,x,y);
X  help = NULL;
X  type = SimpleType;
X  Win = XCreateSimpleWindow(display, parent.Win, x,y, width, height,
X			    border_width,black,white); 
X 
X  if (debug_create) printf(" Window %lx %d %d \n",Win,width, height);
X  
X  gc = gc_copy; // default gc
X  text_gc = gc_copy; // gc for DrawString, PlaceText; temoprarily changed
X
X  xhatab->xhadd(Win,this); // set hash table entry
X
X  //  default mask, modified by subclasses if needed
X  selection_mask =  StructureNotifyMask | ExposureMask ;
};
X  
// to update children list (and possibly fit the parent geometry) :
void window::add_child(window *ch, int x, int y) { 
X  children = new win_list(ch,x,y,children);
}
X
void window::remove_child(window *chrem) { // remove from my children list
X  win_list *chpp = NULL, *chp;
X  for (chp = children; chp; chp = chp->next) {
X    if (chrem == chp->child) break; chpp = chp;
X  } 
X  assert(chp); // loop completed -> child not in parent list, 
X  // this should never happen, else list is corrupted
X  
X  // now re-link the pointers in the children list : 
X  if (chpp) chpp->next = chp->next; else children = chp->next;
X  delete (chp); // delete old win_list structure
}
X
window root_window; // **** definition ****
X
void safe_delete(window *w) { // delete only, if not yet deleted !
X  // look children list of root_window -> only main_windows are catched !
X  for (win_list *ch = root_window.children; ch; ch = ch->next) 
X    if (ch->child == w) { delete (w); return; }
}
X
Bool debug_delete = False; // debugging printf for destructors
X
window::~window() {
X  if (debug_delete) printf("destr %lx %p\n",Win,this); 
X
X  xhatab->xhdel(Win);  // remove from the hash table
X
X  // correct new version (11/95) :
X  // first : search parents child list for my own entry and remove it
X  if (this != &root_window) // for root parentw is not defined
X    parentw->remove_child(this);
X
X  // now delete my own children :
X  // *** attn : this is called recursively ***
X  // ie. the list - itself - is destructed from the children 
X  // via above mechanism; after this it must be empty !
X  for (win_list *ch = children; ch;) { 
X    win_list *next = ch->next; // store here because ch is deleted implicitely
X    delete (ch->child); 
X    ch = next;
X  }
X  assert(children == NULL); // list must be empty now !!
X
X  if (debug_delete && this == &root_window) {
X    for (int i= 0; i < TABSIZE ; i++) printf("%x ",xhatab->xhread(i));
X    printf("\n");
X  } 
}
X
void window::Map() { 
X  if (hidden) return; 
X  draw_interior();  
X  XMapWindow(display, Win);
}
X
/* remarks to ResizeRequest : 
X   if the bit in the SelectMask is set the window manager does no further
X   process XResizeRequestEvents because they are managed from 
X   application window !
*/
void window::Realize() {  
X  // printf("Realize %x %d %d\n",Win,width,height);
X  XSelectInput(display, Win, selection_mask);
X  Map(); // the proper sequence (Select, Map) is essential !!
};
X
void window::Unmap() { XUnmapWindow(display,Win); };
X
// Realize the whole Window tree from this root
void window::RealizeChildren() { 
X  Realize();
X  for (win_list *cc = children; cc; cc = cc->next) { 
X    window *ch = cc->child;
X    ch->RealizeChildren();
X  }
}
X
void window::set_backing_store() {
X  XSetWindowAttributes attr; attr.backing_store = WhenMapped;
X  XChangeWindowAttributes(display,Win,CWBackingStore,&attr);
}
X
void window::set_save_under() {
X  XSetWindowAttributes attr; attr.save_under = TRUE;
X  XChangeWindowAttributes(display,Win,CWSaveUnder,&attr);
}
X
void window::clear() { 
X  XFillRectangle(display, Win, gc_clear, 0,0,width,height); 
}
X
void window::DrawString(int x, int y, char * string) { 
X  XDrawString(display,Win,text_gc,x,y, string, strlen(string)); 
}
X
void window::PlaceText(char * string, int x, int y, XFontStruct * fn) { 
X  XSetFont(display, gc, fn->fid);
X  int tw = XTextWidth(fn, string, strlen(string));   
X  int th = fn->ascent; // + fn->descent;
X  if (x == 0) x = (eff_width() - tw) / 2;  // horizontal centred
X  if (y == 0) y = (height + th) / 2; // vertical centred
X  DrawString(x,y,string); 
}
X
void window::line(int x0, int y0, int x1, int y1) {
X  XDrawLine(display, Win, gc_copy, x0, y0, x1, y1); 
}
X
void window::DrawPoint(int x, int y) {
X  XDrawPoint(display, Win, gc_copy, x, y); 
}
X
void window::BPress_1_CB(XButtonEvent) { }; 
void window::BPress_3_CB(XButtonEvent ev) { 
X  if (help) help->do_popup(ev.x_root,ev.y_root + 20);
X  //  popup below cursor pos. else use:   help->RealizeChildren();
}
X
void window::Expose_CB(XExposeEvent ev) { 
X  if (CB_info) 
X    printf("expose %d %d %d %d %d\n",ev.count,ev.x,ev.y,ev.width,ev.height);
X  if (ev.count == 0) redraw();
}
X
/* definitions from /usr/include/X11/X.h : 
X   see -> eventnames.h 
X   KeyPress		2   KeyRelease		3
X   ButtonPress		4   ButtonRelease	5
X   MotionNotify		6   EnterNotify		7
X   LeaveNotify		8   FocusIn		9
X   FocusOut		10  KeymapNotify	11
X   Expose		12  GraphicsExpose	13
X   NoExpose		14  VisibilityNotify	15
X   CreateNotify		16  DestroyNotify	17
X   UnmapNotify		18  MapNotify		19
X   MapRequest		20  ReparentNotify	21
X   ConfigureNotify	22  ConfigureRequest	23
X   GravityNotify	24  ResizeRequest	25
X   CirculateNotify	26  CirculateRequest	27
X   PropertyNotify	28  SelectionClear	29
X   SelectionRequest	30  SelectionNotify	31
X   ColormapNotify	32  ClientMessage	33
X   MappingNotify	34  LASTEvent		35
*/
X
// the main callback function
pulldown_button * active_button = NULL;
X
// global list : used to destroy an pulldown window 
// with the next button release 
// in the CallBack function; not very nice though
window * pulldown_mapped = NULL; 
X
void window::CallBack(XEvent &event) 
{ if (CB_info) printf("Event %s (%d) in Win %lx\n",event_names[event.type],
X		       event.type,event.xany.window);
X  if (hidden) return;
X  if ((event.type == ButtonRelease))
X    { if (pulldown_mapped) // hat ein pulldown menu gemapped -> unmap it
X	{ pulldown_mapped->Unmap(); pulldown_mapped = NULL; }  
X      
X      if (active_button) // restore invoker button
X	{ active_button->default_frame(); active_button = NULL;}
X    }
X  switch (event.type) 
X    { 
X    case ButtonPress:    
X        BPress_CB(event.xbutton); // allgemeiner BPress-handler, zB. buttons   
X	switch (event.xbutton.button) {
X	  case 1: BPress_1_CB(event.xbutton); break;
X	  case 3: BPress_3_CB(event.xbutton); break;
X	}
X        break;
X    case ButtonRelease:
X        BRelease_CB(event.xbutton);  break;
X    case EnterNotify: 
X	Enter_CB(event.xcrossing); break;
X    case LeaveNotify:
X	Leave_CB(event.xcrossing); break;
X    case Expose:
X	Expose_CB(event.xexpose); break;
X    case KeyPress:
X	KeyPress_CB(event.xkey);  break;
X    case MotionNotify: 
X	Motion_CB(event.xmotion); break;
X    case ConfigureNotify:
X        Configure_CB(event.xconfigure); break;
X    case ClientMessage:
X	ClientMsg_CB(event.xclient); break;
X    default: break;
X    }; 
}
X
void window::add_help(char * WMName,char * text[]) { 
X  int lines, cols;
X  compute_text_size(text,cols,lines);
X  help = new text_popup(WMName,6*cols + 10, 20*lines + 30,text);
}
X
void window::WatchCursor() { // set main window to watch
X  XDefineCursor(display,mainw->Win,watch_cursor); 
X  XFlush(display);
X  //  watch_main = mainw;
}
X
void window::ResetCursor() { // temporarily set, in event-loop reset
X  XUndefineCursor(display,mainw->Win);
}
X
// static float xf_res,yf_res; // resize-factors: either global (in CB) or 
// computed locally inside resize itself
X
void window::resize(int w, int h) {
X  // printf("resize %x: w,h = %d %d (%d %d)\n",Win,w,h,width,height); 
X  if (width == w && height == h) return; // evtl. only move Events
X  float xf_res = float(w)/width, yf_res = float(h)/height;
X  width = w; height = h;  
X  XResizeWindow(display,Win,w,h);
X  win_list *ch = children; 
X  while (ch) { 
X    window * cw = ch->child;
X    int xn = irint(xf_res * ch->x), yn = irint(yf_res * ch->y);
X    ch->x = xn; ch->y = yn;  // new x,y - coordinatec of the child-window
X    XMoveWindow(display,cw->Win, xn, yn);
X    cw->resize(irint(xf_res * cw->width), irint(yf_res * cw->height)); 
X    ch = ch->next; 
X  } 
} 
X
// ##################     main_window class    ###########################
#include "icon.h"
X
main_window *top_main = 0; // used to handle client messages : 
/* it becomes the first created main_window
X   for this window will the close button (from the window manager)
X   exit the application. Other main_windows will only be unmapped
X   Therefore the main application window should be created first
*/
X
main_window::main_window(char * WMName, int w, int h,int fix_pos,int x,int y) 
X  : window(root_window, w, h, x, y, 0) { // no border
X  mainw = this; // its me myself !
X  name = WMName; // mainly for debugging used
X  polling_mode = False;     // default : use XNextEvent in main_loop
X
X  XStoreName(display, Win, WMName);  // set name in WM-frame
X
X  Cursor main_cursor = XCreateFontCursor(display,XC_left_ptr);
X  // printf("1.main %s %d\n", WMName, fix_pos);
X  XDefineCursor(display, Win, main_cursor);
X  set_icon(icon_bits,icon_width,icon_height);
X 
X  switch (fix_pos) {       
X  case 2: 
X    x = (DisplayWidth(display,screen) - w)/2;
X    y = (DisplayHeight(display,screen)- h)/2;  // centre window
X    XMoveWindow(display,Win, x, y); // XSetWMNormalHints doesnt work here ?!
X    // thats why the explicit move is inserted
X    // no break;  
X  case 1:  // x,y have been given explicitely
X    XSizeHints *sz_hints = XAllocSizeHints(); 
X    sz_hints->flags = PPosition;
X    sz_hints->x = x;
X    sz_hints->y = y;
X    XSetWMNormalHints(display,Win,sz_hints);
X    XFree(sz_hints);      
X    break;
X  }
X  // this protocoll is used from the window manager (mwm) when the 
X  // close button is pushed (f.kill). If not set the whole application
X  // is killed when any main window is closed !
X  Atom p = XInternAtom(display,"WM_DELETE_WINDOW",0); 
X  XSetWMProtocols(display,Win,&p,1);
X
X  if (top_main == 0) top_main = this; // the first created should be the app.
}
X
// up to now only invoked from window manager upon "close"
void main_window::ClientMsg_CB(XClientMessageEvent) {
X  if (this == top_main) exit(0); else Unmap();
}
X
main_window::~main_window() {
X  XDestroyWindow(display,Win); // also destroys the Subwindows 
X  if (debug_delete) printf("main_window '%s' -> ", name);
X  // window::~window(); 
X  // explicite destr. for basis class not needed
}
X
// only for popup windows : show them at given x,y : old version :
// 1. make it small before moving it, 2. realize, 3. move to x,y-position
// not quite convinient
// this version -> does not work !
void main_window::do_popup(int x , int y)
{ XMoveWindow(display, Win, x,y); // -> does not work here
X  RealizeChildren(); 
X  // XMoveResizeWindow(display, Win, x, y, width, height); // -> too slow 
}
X	
void main_window::Configure_CB(XConfigureEvent ev) {  
X  // printf("config %d %d %d \n",ev.type,ev.width,ev.height);
X  // xf_res = float(ev.width)/width; yf_res = float(ev.height)/height;
X  resize(ev.width, ev.height); 
}
X
// the event loop :
// from the window-id the this-pointer of the window is computed (table)
// then the "CallBack" function invokes the virtual handler to the 
// corresponding derived class from window
X
void handle_event(XEvent &event) {
X  unsigned wid = event.xany.window;
X
X  xlist *xw = xhatab->xhget(wid);
X  if (xw) xw->tw->CallBack(event); 
X  // else : the window is deleted, but some events can occur nevertheless 
X  //  eg. LeaveNotify-Events (type = 8) 
}
X
// for event loop in polling_mode
static Bool predicate(Display *, XEvent *, char *) { return TRUE; } 
X
void main_window::main_loop() {
X  exit_flag = False;
X  RealizeChildren(); 
X  while (1) { 
X    XEvent event;   
X    if (polling_mode) { // polling : used only for special applications
X      if (! XCheckIfEvent(display,&event,predicate,"loop")) {
X	polling_handler(); 
X	continue;  // no event handling needed
X      }
X    } else XNextEvent(display, &event);
X    handle_event(event);
X    // in case of the queue has filled during handling -> flush events 
X    while (XCheckMaskEvent(display, KeyPressMask | KeyReleaseMask 
X			   | PointerMotionMask,&event));
X    if (exit_flag) break; // is set by quit buttons
X  }
X  Unmap();
X  // printf("main_loop exited\n");
}
X
void main_window::set_icon(char *ibits, int iwidth, int iheight) {
X  // printf("set_icon %x %d %d %x %x\n",ibits,iwidth,iheight,display,Win); 
X  Pixmap icon_pixmap = XCreateBitmapFromData(display,Win,ibits,iwidth,iheight);
X  // printf("set_icon %x \n",icon_pixmap); 
X  XWMHints *wm_hints = XAllocWMHints();
X  // printf("set_icon %x \n",wm_hints); 
X  wm_hints->icon_pixmap = icon_pixmap;
X  wm_hints->flags = IconPixmapHint;
X
X  XSetWMHints(display,Win,wm_hints);
X  XFree((void *) wm_hints);
}
X
// ####################      pixmap_window    ############################
X
pixmap_window::pixmap_window(window & parent,int w,int h,int x,int y,int bw) : 
window(parent, w, h,x, y, bw) {
X  pix = XCreatePixmap(display, Win, width, height, depth);
X  clear();
}
X
pixmap_window::~pixmap_window() {
X  XFreePixmap(display,pix);
}  
X
void pixmap_window::clear() { 
X  XFillRectangle(display, pix, gc_clear, 0,0, width, height); 
}
X 
void pixmap_window::Map() { 
X  draw_interior(); 
X  XCopyArea(display,pix, Win, gc_copy, 0, 0, width, height, 0, 0);
X  XMapWindow(display, Win); 
}
X
void pixmap_window::DrawString(int x, int y, char * string) {
X  XDrawString(display,pix,gc_copy,x,y, string, strlen(string)); }
X
void pixmap_window::line(int x0, int y0, int x1, int y1) {
X  XDrawLine(display, pix, gc_copy, x0, y0, x1, y1); }
X
void pixmap_window::DrawPoint(int x, int y) {
X    XDrawPoint(display, pix, gc_copy, x, y); 
X  }
X
void pixmap_window::Expose_CB(XExposeEvent ev) { 
X  // restore the exposed area from pixmap onto screen
X  XCopyArea(display, pix, Win,gc_copy,ev.x,ev.y,ev.width,ev.height,ev.x,ev.y);
}
X
void pixmap_window::resize(int w, int h) {
X  // printf("resize %dx%d -> %dx%d\n",width,height,w,h);
X  if (width == w && height == h) return; // evtl. nur move Events
X  XFreePixmap(display,pix);
X  pix = XCreatePixmap(display,Win,w,h,depth);
X  window::resize(w,h);
X  clear(); // erst hier (braucht width, height !)
X  Map();
}
X
// ****************** 3d-shapes ********  
// draw rectangle in 3d-look with two distinct GCs
// mode = up3d, flat3d (background pix), down3d
void rect3d(Window Win, int mode, short x, short y, short w, short h) {
X  int i, thickness = 2;  
X  GC left_top,right_bot; // colors for both border parts
X  switch (mode) { 
X  case up3d:   left_top = button_br_gc; right_bot = button_lw_gc; break;
X  case down3d: left_top = button_lw_gc; right_bot = button_br_gc; break;
X  case flat3d: 
X  default: left_top = button_fg_gc; right_bot = button_fg_gc; break;
X  }
X  for (i = 0; i < thickness; i++) {
X    short xa = x+i, ya = y+i, xe = x+w-i, ye = y+h-i ; 
X    XPoint xp[5] = { {xa,ye}, {xa,ya}, {xe,ya}, {xe,ye}, {xa,ye}}; // short x,y
X    XDrawLines(display,Win, left_top, xp, 3, CoordModeOrigin);
X    XDrawLines(display,Win, right_bot, xp+2, 3, CoordModeOrigin);
X  }
}
X
// analog triangle, points downwards, x,y = left edge
// mode = up3d, flat3d (background pix), down3d
void tri3d_s(Window Win, int mode, short x, short y, short w, short h) {
X  int i, thickness = 2;  
X  GC left_top,right_bot; 
X  switch (mode) { 
X  case up3d:   left_top = button_br_gc; right_bot = button_lw_gc; break;
X  case down3d: left_top = button_lw_gc; right_bot = button_br_gc; break;
X  case flat3d: 
X  default: left_top = button_fg_gc; right_bot = button_fg_gc; break;
X  }
X  for (i = 0; i < thickness; i++) {
X    short xa = x+i, ya = y+i, xe = x+w-i, ye = y+h-i, xm = x+w/2; 
X    XPoint xp[4] = { {xm,ye}, {xa,ya}, {xe,ya}, {xm,ye}}; 
X    XDrawLines(display,Win, left_top, xp, 3, CoordModeOrigin); 
X    XDrawLines(display,Win, right_bot, xp+2, 2, CoordModeOrigin);
X  }
}
X
// plates are pseudo-3d-windows
plate::plate(window & parent, int w, int h, int x, int y,int mode3d)  
: window(parent, w, h, x, y, 0), mode3d(mode3d) { 
X  selection_mask |= EnterWindowMask | LeaveWindowMask; 
}
void plate::redraw() {
X  XFillRectangle(display,Win,button_fg_gc,0,0,width,height); 
X  default_frame(); // virtual function !
}
X
// --------------------------- BUTTONS  -------------------------------
// ##################         button class      ###########################
X
void button::init_button(window *parent) {  
X  in_pulldown = (parent->type == PulldownType);
X  selection_mask |= ButtonPressMask | ButtonReleaseMask;
} 
void button::redraw() {
X  plate::redraw(); 
X  PlaceText(Name); 
}
X
button::~button() {
X  if (debug_delete) printf("button %s -> ",Name); 
}
X
void button::add_help(char **help_text) {
X    char * WMName = new char[strlen(Name) + 12]; 
X    sprintf(WMName,"Help : '%s'",Name);
X    window::add_help(WMName,help_text); }
X
// ##################      popup_button        #########################
// realize the popup menu when BPress (make it visibel) 
// if pressed again : make it unvisible 
X
void popup_button::BPress_1_CB(XButtonEvent ev) { 
X  XWindowAttributes attr;
X  XGetWindowAttributes(display,popup_menu->Win,&attr);
X  if (attr.map_state == IsViewable) popup_menu->Unmap(); 
X  else popup_menu->do_popup(ev.x_root + 10,ev.y_root + 20); 
}  
X
// ##################     help_button class    ############################
X
void help_button::make_popup(char *text[]) {
X  // Berechnung der noetigen Windowgroesse fuer popup
X int ln, cols; 
X compute_text_size(text,cols,ln);
X popup_menu = new text_popup("help", 6*cols + 10, ln*15 + 30, text); 
X // leave room for OK button (bottom)!
}
X
// ##################   function_button class    ############################
X
function_button::function_button (window & parent, char * Name,  
X                                 int w, int h, int x, int y, CB cb,  ...) : 
X      button (parent, Name, w, h, x, y), callback(cb) {
X    int i; va_list ap; va_start(ap,cb);
X    for (i=0;i<10;i++) values[i] = va_arg(ap,void*);
X    va_end(ap);
X  }
X
function_button::function_button (menu_bar & parent, char * Name, CB cb, ...) :
X  button (parent, Name), callback(cb) { 
X    int i; va_list ap; va_start(ap,cb);
X    for (i=0;i<10;i++) values[i] = va_arg(ap,void*);
X    va_end(ap);
X  }
X
// --------------  switch_button ------------------  
// a button with 2 states of display, which switch on click
// the 2. string should be <= the first (= initial)
switch_button::switch_button(menu_bar & parent, char *Name1, char *Name2, 
X			     Bool *toggle,
X		 VVP inf, void * toinf) : button(parent,Name1), toggle(toggle) 
{ callbck = inf; instptr = toinf; Narr[0] = Name1; Narr[1] = Name2; }
X
switch_button::switch_button(window & parent, char *Name1, char *Name2, Bool *toggle,
X		 VVP inf, void * toinf, int w, int h, int x, int y) : 
X		 button(parent,Name1,w,h,x,y) ,toggle(toggle) 
X    { callbck = inf; instptr = toinf; Narr[0] = Name1; Narr[1] = Name2; }
X
void switch_button::switch_it() {
X    *toggle = ! *toggle;  // switch
X    Name = Narr[*toggle]; // use as index ! (0,1)
X    redraw(); // display new string
X    (*callbck)(instptr); 
X  }
X 
// ---------------------------- PULLDOWN --------------------------------
X
// ##################     pulldown_window class    #######################
// a window child from root_window, not yet visible, not managed from WM,
// position is determined from the button at popup time
X
// special cursor for pulldown menus 
Cursor pulldown_cursor = XCreateFontCursor(display,XC_right_ptr);
X
pulldown_window::pulldown_window (int w, int h) : main_window("",w,h) {
X  XSetWindowAttributes attr; 
X  attr.override_redirect = TRUE; attr.save_under = TRUE;
X  attr.cursor = pulldown_cursor; 
X  XChangeWindowAttributes(display, Win, 
X			  CWOverrideRedirect | CWCursor | CWSaveUnder, 
X			  &attr);
X  type = PulldownType;
}
X
// ##################     pulldown_button class    ########################
// map the window (menu) on root when button is activated (BPress)
// the window is mapped to absolute co-ordinates !
X
pulldown_button::pulldown_button (window & parent, pulldown_window * menu, 
X				  char * Name, int w, int h, int x, int y) 
: button(parent, Name, w, h, x, y) { pulldown_menu = menu; xright = 12;}
X
pulldown_button::pulldown_button(menu_bar & parent, pulldown_window * menu, 
X				 char * Name) 
: button(parent, ext_string(Name)) { pulldown_menu = menu; xright = 12; }
X
pulldown_button::pulldown_button (window & parent, pulldown_window * menu, 
X				  char * Name, char ** help_text,
X				  int w, int h, int x, int y) 
: button(parent, Name, help_text, w, h, x, y) 
X         { pulldown_menu = menu; xright = 12;}
X 
void pulldown_button::picture() { 
X   int offs = (height-8)/2; 
X   tri3d_s(Win,up3d, width-xright,offs,8,8);
}
X
void pulldown_button::BPress_1_CB(XButtonEvent ev) 
{ 
X  unsigned x, y; // *absolut*  position of pulldown menu
X  /* **** old code (works too) **** 
X     // komplettes Aufsteigen im Window tree bis root 
X     // enthaelt auch WM-windows !!
X     Window root_return, query, parent, *cc;
X     query = Win; // WID of the pulldown button
X     x = 0; y = height + 1;
X     do {  
X     unsigned xr, yr, wr, hr, br, dr, nc;
X     XGetGeometry(display, query, &root_return, &xr, &yr, &wr, &hr, &br, &dr);
X     XQueryTree(display, query, &root_return, &parent, &cc, &nc); 
X     // printf("win = %x par = %x,  x y = %d %d\n", query, parent, xr, yr);
X     x += xr; y += yr;
X     query = parent;
X     } while (parent != root_return);
X  */
X  
X  // determine the absolute coord of mouse pointer
X  x = ev.x_root - ev.x; // + (width-pulldown_menu->width)/2; horizontal centr.
X  y = ev.y_root - ev.y + height + 1;
X  // auch nuetzlich :  XMoveResizeWindow(disp,win,x,y,w,h);
X  XMoveWindow(display, pulldown_menu->Win, x, y);
X 
X  pulldown_menu->RealizeChildren();
X  XRaiseWindow(display,pulldown_menu->Win); 
X
X  XGrabPointer(display,pulldown_menu->Win,TRUE,
X	       Button1MotionMask | PointerMotionMask |
X	       EnterWindowMask | LeaveWindowMask 
X	       ,GrabModeAsync, GrabModeAsync,None, None,CurrentTime);
X  pulldown_mapped = pulldown_menu; 
X  active_button = this;
X  // with this trick the next BRelease causes the unmapping of the pulldown
X  // and restores the default_frame (this)
X  // not to solve with class method since BRelease is invoked for another win
X  // should be replaced by push/pop method, to allow multiple popups
} 
X
// if w == 0 parent must be menu_bar -> use autoplacement
pulldown_button * make_radio_menu(window &parent, char *Name, char **list,
X				  window * action_win,
X				  int w, int h, int x, int y) {
X  int wm, hm;      // size of pulldown_menu
X  int nbuttons;   // number of buttons on pulldown
X  char * value;
X  // first parse blist to determine size of pulldown menu
X  compute_text_size(list,wm,nbuttons);
X  wm = wm * 6 + 10 ;        //  6 = length of char
X  hm = nbuttons * 20;       // 20 = height of button
X  pulldown_window * pd_wi = new pulldown_window(wm,hm);
X  pulldown_button * pd_bt;
X  if (w > 0) pd_bt = new pulldown_button(parent,pd_wi,Name,w,h,x,y); else
X     pd_bt = new pulldown_button((menu_bar&) parent, pd_wi, Name);
X  int yp = 0; 
X  while (*list) { 
X    value = *list++;
X    new radio_button(*pd_wi,Name,wm,20,0,yp,value, action_win);
X    yp += 20;
X  };
X  return pd_bt;
}
X
// analogous : with help popup
pulldown_button * make_radio_menu(window &parent, char *Name, char **list,
X				  char ** help_text, window * action_win,
X				  int w, int h, int x, int y) {
X  pulldown_button * r_menu = make_radio_menu(parent, Name, list,
X					     action_win, w, h, x, y );
X  r_menu->add_help(help_text);
X  return r_menu;
}
X
// list : { {"button1", &callback1}, {"button2", &callback} }
pulldown_button * make_pulldown_menu(window &parent, char *Name, 
X				     int nbuttons, struct but_cb list[],
X				     int w, int h, int x, int y) {
X  int wm = 0, hm;     // size of pulldown_menu
X  int i;
X  // first parse blist to determine size of pulldown menu
X  for (i=0; i < nbuttons; i++) { 
X    int ll;
X    ll = strlen(list[i].bname); if (ll > wm) wm = ll;
X  };
X  wm = wm * 6 + 10 ;            //  6 = length of char
X  hm = nbuttons * 20;           // 20 = height of button
X  pulldown_window * pd = new pulldown_window(wm, hm);
X  pulldown_button * pb;
X  if (w > 0) pb = new pulldown_button(parent,pd,Name,w,h,x,y); else
X     pb = new pulldown_button((menu_bar&) parent, pd, Name); 
X
X  int yp = 0; 
X  for (i=0; i < nbuttons; i++) { 
X    new callback_button(*pd,list[i].bname,list[i].cb,wm,20,0, yp);
X    yp += 20;
X  }
X  return pb;
}
X
X
// ###################### text_popup #######################
text_popup::text_popup(char * WMName, int w, int h, char *text[]) :
main_window (WMName, w, h) { 
X  pop_text = text; 
X  new unmap_button (*this,"OK",50,20, (width-50)/2,height-23); 
X  // a button to close the popup window
}
X
void text_popup::Expose_CB(XExposeEvent) { // write the text
X    int ln = 0, y = 0; 
X    while (pop_text[ln]) {   
X      y+= 15;
X      PlaceText(pop_text[ln++], 4, y);
X    }
X  }
X
// String-Arrays: char *x[] = {"xyzuvw","XXXX",...,0} 
// max length of a  string  && number of  strings 
void compute_text_size(char *text[], int &cols, int &lines) {
X  int ll = 0;
X  lines = 0; cols = 0;
X  while (text[lines]) { 
X    ll = strlen(text[lines++]);
X    if (ll > cols) cols = ll;
X    if (ll > 1000 || cols > 1000) error("text-array has no NULL-termination");
X  }
}
X
// ##################### coord_window ##########################
coord_window::coord_window(window & parent, int w, int h, int x, int y, 
X	                   int rxl, int rxr, int ryd, int ryu) :
X    pixmap_window(parent,w,h,x,y), rxl(rxl), ryd(ryd) { 
X    w_diff = rxr + rxl; h_diff = ryd + ryu; // the border minus
}
X
void coord_window::define_coord(float x1, float y1, float x2, float y2) {
X  xl = x1; yd = y1; xr = x2; yu = y2;
X  x0 = rxl; y0 = height - ryd; // Window-coordinates of origin
X  w_eff = width - w_diff; h_eff = height - h_diff;
X  xf = w_eff/(x2 - x1); yf = h_eff/(y2 - y1);
}
X
// compute total window-coordinates from world-values
int coord_window::x_window(float x) { return x0 + (int)(xf * (x - xl) + .5); }
int coord_window::y_window(float y) { return y0 - (int)(yf * (y - yd) + .5); }
X
XXPoint coord_window::p_window(float x, float y) { // returns same as XPoint
X  XPoint temp = { x_window(x), y_window(y) };
X  return temp;
}
X   
// back transformation : window coords to world-values
float coord_window::x_org(int xw) { return (xw - x0)/xf + xl; }
float coord_window::y_org(int yw) { return (y0 - yw)/yf + yd; }
X
void coord_window::x_ticks(float dx, int n) { 
X  float xx; 
X  if (xr < xl) dx = -dx; // failsafe
X  for (xx = xl; xx < xr; xx+= dx) { 
X    int x = x_window(xx); line(x,y0,x,y0+2); 
X    if (n-- == 0) break;
X  } 
}
void coord_window::y_ticks(float dy, int n) { 
X  int i; float yy = yd;
X  if (yu < yd) dy = -dy;
X  for (i = 0; i < n; i++) { 
X    int y = y_window(yy); line(x0,y,x0-2,y); 
X    yy += dy; if (yy > yu) break;
X  }
}
X 
void coord_window::graph(int nx, double f[]) { 
X  int i, x , y, xp, yp; 
X  for (i=0; i<nx-1; i++) { 
X    y = y_window(f[i]); x = x_window(i); 
X    if (i > 0) line(xp, yp ,x, y);
X    xp = x; yp = y; 
X  }
}
X
//   ###########  system buttons && xwd_buttons ##########
X
void system_button::BPress_1_CB(XButtonEvent) { 
X  printf("calling system('%s')\n",cmdline);
X  system(cmdline);
}
X
void xwd_button::BPress_1_CB(XButtonEvent) { 
X  char cmdline[200]; 
X  sprintf(cmdline,"xwd -id 0x%lx %s",dumpw->Win, arg);
X  printf("dump : calling system('%s')\n",cmdline);
X  system(cmdline);
}
X
// ############################################################
//              SLIDERS &   SCROLLBARS
X
slider::slider(window &parent, int w, int h, int x, int y) : 
X  plate (parent,w,h,x,y,up3d) { }
X
void slider::redraw() { // called from Expose_CB, not invoked from move !
X  plate::redraw();
X  line(width/2,0,width/2,height);
}
X
void pure_scrollbar::set_slider(int x) {
X  bar = new slider(*this,sw,sh,x+2,sy); 
X  xact = x;
}
X
void pure_scrollbar::init () { 
X  sw = 19; sh = height-10; sy = 5; // start-values for slider
X  xoff = sw/2+2; xmax = width-sw/2-2; xspan = xmax-xoff-1;
X  set_backing_store(); // to avoid flickering of scrollbar when drawing slider
X  selection_mask |= PointerMotionMask | ButtonPressMask; 
X  nticks = 0; // default : no ticks
}
X
void pure_scrollbar::move(int x) { 
X  if (x >= 0 && x <= xspan) { // the real value in intervall [0..xspan]
X    XMoveWindow(display,bar->Win,x + xoff - sw/2,sy); 
X  }  
}
X
void pure_scrollbar::move_cb(int x) {
X if (x >= 0 && x <= xspan) { // the real value in intervall [0..xspan]
X    XMoveWindow(display,bar->Win,x + xoff - sw/2,sy); 
X    callbck(x);
X  }  
}
X
void pure_scrollbar::redraw() {   
X  plate::redraw(); 
X  line(xoff,height/2,xmax,height/2); // horizontal line
X  // line(xoff,4,xoff,height-4); line(xmax,4,xmax,height-4)
X  for (int i = 0; i < nticks; i++) { // only drawn if nticks > 0
X    int x = xoff + (i+1)*(xmax-xoff)/(nticks+1);
X    line(x,4,x,height-4);
X  }
}
X
void pure_scrollbar::resize(int w, int h) {
X  plate::resize(w,h);
X  sw = bar->width; sy = (height - bar->height)/2;
X  xoff = sw/2+2; xmax = width-sw/2-2; xspan = xmax-xoff-1;
} 
X
void display_window::set_text_mode(int mode) { 
X  // mode 0 : clear, 1 : write
X  text_gc = (mode) ? gc_copy : button_fg_gc;
} 
X 
void scrollbar::init(window &parent, int w, int h, int x, int y, 
X                     int minp, int maxp, int xstart) 
{  min = minp; max = (maxp) ? maxp : xspan; 
X   factor = ((double) (max - min))/xspan; 
X   set_slider( val_to_pix(xstart) );
X   setval(xstart); // Anfangs-default
X   disp_win = new display_window(parent,str,60,h,x+w-60,y,down3d);
X }
X
scrollbar::scrollbar(window &parent, void (*inf)(), int w, int h, 
X		     int x, int y, int minp, int maxp, 
X		     int xstart, char *format) :
X     pure_scrollbar (parent,pwidth(w),h,x,y), format(format) {
X       init(parent,w,h,x,y,minp,maxp,xstart);
X       to_inform = NULL;
X       inffn.empty = inf;
X  }
X 
// 2. constructor :
scrollbar::scrollbar(window &parent, void (*inf)(void*), void * to_inf,
X		     int w, int h, int x, int y, 
X		     int minp, int maxp, int xstart, char *format) :
X     pure_scrollbar (parent,pwidth(w),h,x,y), format(format) {
X       init(parent,w,h,x,y,minp,maxp,xstart);
X       to_inform = to_inf;
X       inffn.vptr = inf;
X  }
X    
void scrollbar::callbck_val(int x) {   
X  // quick clearing of the old display : overwrite with  background gc
X  disp_win->set_text_mode(0); disp_win->draw_val();
X  setval(x); // compute new display
X  disp_win->set_text_mode(1); disp_win->draw_val();
X  // reset default gc !!! , new value
X  if (inffn.value) 
X    { if (to_inform) (*inffn.vptr)(to_inform); else (*inffn.empty)(); }
}
X
void scrollbar::resize(int w, int h) {
X  pure_scrollbar::resize(w,h);  
X  factor = ((double) (max - min))/xspan; 
}
X
// **** class tick_scrollbar ***** : scrollbar with ticks and numbers
// has fixed height (20 + 15 = 35) with ticks and value displays 
void tick_scrollbar::tickstr() { // compute tick strings
X  char *stptr = strvec;
X  for (int i=0; i < nticks+2; i++) {
X    sprintf(stptr,"%d",i*(max-min)/(nticks+1)+min); valstr[i]= stptr;
X    stptr += strlen(stptr)+1;
X  }
}
X
tick_scrollbar::tick_scrollbar(window &parent, void (*inf)(void*), void *to_inf,
X			       int w, int x, int y, int n_ticks, int minp, 
X			       int maxp, int xstart, char *format) :
X  scrollbar(parent, inf, to_inf, w, 20, x, y, minp, maxp, xstart, format) {   
X    nticks = n_ticks;
X    if (nticks > MAXTCKS) error("too many ticks for scrollbar (max 20)");
X    strvec = new char[(nticks+2)*12]; // room should suffice
X    tickstr();
X    for (int i = 0; i < nticks+2; i++) { 
X      // windows to display numbers below ticks
X      // int nl = strlen(valstr[i]);
X      int xp = xoff + i*xspan/(nticks+1) ;
X      valtxt[i] = new text_win(parent, valstr[i], 30, 15, x + xp - 15, y+20);
X    }
X  }
X
tick_scrollbar::~tick_scrollbar() { delete strvec; }
X
void tick_scrollbar::adapt(int maxp, int xstart) {
X  max = maxp; factor = ((double) max - min)/xspan; 
X  change(xstart); // set slider to xstart and displays value
X  tickstr();
X  for (int i = 0; i < nticks+2; i++) { // displays numbers below ticks
X    valtxt[i]->clear(); valtxt[i]->redraw();
X  }
}
X
// ***************************************
// class "edit_window" for editing of strings, max 80 chars 
edit_window::edit_window(window &parent, char *str, int w,int h, int x, int y)
: plate(parent,w,h,x,y,down3d) { 
X  strncpy(value,str,200);
X  XDefineCursor(display,Win,text_cursor);
X  cp = strlen(value); // set behind the string
X  selection_mask |= KeyPressMask;
}
X
void edit_window::mark_cursor() { 
X  XFillRectangle(display, Win, gc_but_xor, xs + 6*cp, 2, 6, 15);
}
void edit_window::Enter_CB(XCrossingEvent) { // frame3d(flat3d); 
X  mark_cursor(); 
}
void edit_window::Leave_CB(XCrossingEvent) { // default_frame(); 
X  mark_cursor(); 
}
X
void edit_window::redraw() {
X  plate::redraw(); 
X  xs = width - 6*strlen(value) - 10; 
X  DrawString(xs,16,value);
}
X  
void edit_window::del_char() { // clear chars left from cursor
X  int i; 
X  for (i = cp; i <= strlen(value); i++) value[i-1] = value[i];
X  cp--;
}
X
void edit_window::ins_char(char x) { // insertion left
X  int i; 
X  for (i = strlen(value); i >= cp; i--) value[i] = value[i-1];
X  value[cp] = x; cp++;
}
X
void edit_window::KeyPress_CB(XKeyEvent ev) {
X  mark_cursor();
X  KeySym keysym = XLookupKeysym(&ev,ev.state & 1);
X  switch(keysym) {
X  case XK_Left: while (cp <= 0) ins_char(0x20); // fill with space
X    cp -= 1; break;
X  case XK_Right: if (cp < strlen(value)) cp += 1; break;
X  case XK_BackSpace: if (cp > 0) del_char(); break;
X  case XK_Delete: if (cp > 0) del_char(); break;
X  case XK_Escape: escape(); break;
X  case XK_Return: enter(); break;               // Return = Enter
X  default: 
X    if ((keysym >= 0x20) && (keysym<= 0x7e)) // all ASCII-chars
X      ins_char(keysym);
X  }
X  redraw();
X  mark_cursor(); 
}
X
// class clock_win : public pixmap_window 
// class to display a simple analogue clock bound to an external time variable
X
clock_win::clock_win(window &parent, int *tptr,int w, int h, int x, int y) :
X  pixmap_window(parent,w,h,x,y,0), tptr(tptr) { init(); }
X
// display a centered arrow with radius r
void clock_win::arrow(double phi, float r) {
X  double c, s; 
X  s = sin(phi); c = cos(phi);
X  line(xc,yc, irint(xc + r*s), irint(yc - r*c));
}
X
void clock_win::draw_interior()  {
X  int r = d/2;
X  XDrawArc(display,pix,gc_copy,xc-r,yc-r,d,d,0,360*64);
X  arrow(*tptr/3600.*2.0*3.1416, rm); // minutes arrow
X  arrow(*tptr/86400.*4.0*3.1416, rh); // hours arrow
}
X  
void clock_win::init() {
X  xc = width/2; yc = height/2; 
X  d = (width <? height) - 2; // minimum of width and height
X  rh = d/3 - 2; rm = d/2 - 4;
X  // printf(" %d %d %d %d %d\n",width,height,xc,yc,d);
}
X
void clock_win::resize(int w, int h) {
X  pixmap_window::resize(w,h);
X  init();
X  redraw();
}
X
//  ************* twodim_input ***********
// a class used to get a twodim value from a mouse pointer driven slider
X
twodim_input::twodim_input(window &parent, int w, int h, int x, int y, 
X			   int swp, int shp, void *vptr)
: plate (parent,w,h,x,y,down3d), vptr(vptr), sw(swp), sh(shp) { 
X  set_backing_store(); 
X  selection_mask |= PointerMotionMask | ButtonPressMask; 
X  set_vars();  
X  bar = new plate(*this,sw,sh,sx,sy,up3d);
X  cbhook = NULL;
}  
X
void twodim_input::set_vars() {
X  sx = 2; sy = 2; 
X  yact = sy; xact = sx; 
X  if (sh == 0) sh = height - 2*sy; // horiz. shifter : yspan = 0
X  if (sw == 0) sw = width  - 2*sx; // vert . shifter : xspan = 0
X  yspan = height - 2*sy - sh; 
X  xspan = width - 2*sx - sw;
}
X
void twodim_input::move(int x, int y) { // called from Events
X  set_slider(x - sx - sw/2,y - sy - sh/2);
}
void twodim_input::BPress_CB(XButtonEvent ev)  {
X  switch (ev.button) {
X  case 1: case 2: // all the same
X  case 3: move(ev.x,ev.y); break;  
X  }
}
X
void twodim_input::Motion_CB(XMotionEvent ev)  { 
X  if (ev.state & (Button1Mask | Button2Mask | Button3Mask)) { 
X    move(ev.x,ev.y); }
}
X
void twodim_input::set_slider(int x, int y)  {  // set slider y = 0..zspan
X  // printf(" %d %d\n",x,y);
X  y = MAX(0, MIN(yspan,y)); 
X  x = MAX(0, MIN(xspan,x));     
X  if (x != xact || y != yact) {
X    xact = x; yact = y;
X    XMoveWindow(display,bar->Win,x + sx ,y + sy); 
X    if (cbhook) cbhook(vptr,this);
X  }
}
X
// called from resize && others 
void twodim_input::slider_adapt(int swp,int shp) { // adaptate to new slider size
X  sw = swp; sh = shp; 
X  set_vars(); 
X  bar->resize(sw,sh); set_slider(0,0);
} 
X
X
void twodim_input::resize(int w, int h)  {
X  //    if (width == w && height == h) return; // only once
X  width = w; height = h; 
X  XResizeWindow(display,Win,width,height); 
X  slider_adapt(sw,sh);
}
X
void twodim_input::configure(int w, int h, int swp, int shp, int x, int y)  { 
X  resize(w,h);
X  slider_adapt(swp,shp);
X  XMoveWindow(display,Win,x,y);
X  RealizeChildren(); // in case it was unmaped before
}
X
X
// scrolled_window has a virtual window which can be shifted with shifters
// arguments are : real width/height, virtual width/height
// (the first window with correct resizing)
// the virtual window must be derived from class virtual_window !!!
X
scrolled_window::scrolled_window(window &parent, int w, int h, int vw, int vh, 
X				 int x, int y) 
: window(parent,w,h,x,y,0) {
X  xp = yp = 0;
X  hvirt = vh; wvirt = vw;
X  hs = vs = 0; clip = 0;
X  resize(w,h);
X  virt_win =  0; // must be set later !!!
} 
X
void scrolled_window::cbhook(twodim_input *ts) {
X  if (virt_win == 0) error("no virtual window bound");
X  int x = ts->xact, y = ts->yact, xs = ts->xspan, ys = ts->yspan;
X  // printf("hook %d %d\n",ts->xact,ts->yact);
X  // transform slider-pos to shift values
X  if (xs != 0) xp = -x*(wvirt - wvis)/xs; 
X  // else vert.shifter: use old xp
X  if (ys != 0) yp = -y*(hvirt - hvis)/ys;
X  XMoveWindow(display,virt_win->Win,xp,yp);
}
X
void scrolled_window::resize(int w, int h) {
X  // if (w == width && h == height) return;
X  width = w; height = h;
X  // printf("resize scrolled window %d %d %d %d\n",w,h,wvirt,hvirt);
X  XResizeWindow(display,Win,w,h);
X  int sz = 15; // shifter dim. (heigth or width)
X  Bool horz_scr = (wvirt > w);
X  if (horz_scr) h -= sz; // left room for horz_shifter (bottom) 
X  Bool vert_scr = (hvirt > h); 
X  if (vert_scr) w -= sz; // left room for shifter (right) 
X  wvis = w; hvis = h;    // that is the region which is actually visible
X
X  if (vert_scr) {
X    int sh = (h-4) * h/hvirt; if (sh < 4) sh = 4; // else too small
X    if (vs == 0) // create new 
X      vs = new vertical_shifter(*this,sz,h,w,0,sh, (CBHOOK) cbhook, this);
X    else vs->configure(sz,h,0,sh,w,0); 
X  } else if (vs) XUnmapWindow(display,vs->Win);
X  if (horz_scr) {
X    int sw = (w-4) * w/wvirt; if (sw < 4) sw = 4; // else too small
X    if (hs == 0) // create new 
X      hs = new horizontal_shifter(*this,w,sz,0,h,sw, (CBHOOK) cbhook,this);
X    else hs->configure(w,sz,sw,0,0,h); 
X  } else if (hs) XUnmapWindow(display,hs->Win);
X  
X  if (clip == 0) clip = new window(*this,wvis, hvis, 0, 0); // clip window
X  else XResizeWindow(display,clip->Win,wvis,hvis);
X  // printf("%d %d %d %d %d %d\n",wvirt,hvirt,wvis,hvis,w,h);
}
X
horizontal_shifter::horizontal_shifter(window &parent, int w, int h, int x, 
X				       int y, int sw, CBHOOK cbh, void *vptr) 
: twodim_input(parent,w,h,x,y,sw,0,vptr) { 
X  cbhook = cbh; 
X  XDefineCursor(display,Win,hs_cursor); 
}
X
vertical_shifter::vertical_shifter(window &parent, int w, int h, int x, int y, 
X				   int sh, CBHOOK cbh, void *vptr) 
: twodim_input(parent,w,h,x,y,0,sh,vptr) { 
X  cbhook = cbh; 
X  XDefineCursor(display,Win,vs_cursor); 
}
SHAR_EOF
chmod 0644 window.c ||
echo 'restore of window.c failed'
Wc_c="`wc -c < 'window.c'`"
test 47152 -eq "$Wc_c" ||
	echo 'window.c: original size 47152, current size' "$Wc_c"
fi
# ============= window.h ==============
if test -f 'window.h' -a X"$1" != X"-c"; then
	echo 'x - skipping window.h (File already exists)'
else
echo 'x - extracting window.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'window.h' &&
// window.h : basic include file for the Grafix package
// the "GNU Public Lincense" policy applies to all programs of this package
// (c) Wolfgang Koehler, wolf@first.gmd.de, Dec. 1994
//     Kiefernring 15
//     14478 Potsdam, Germany
//     0331-863238
X
#include <X11/Xlib.h>
// #include "X11/Xutil.h"
#include <X11/keysym.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
X
#define FALSE 0
#define TRUE 1
X
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define MIN(x,y) ((x) < (y) ? (x) : (y))
X
// since some dumb platforms dont have irint, or rint
#define irint(x) int((x)+0.5)
X
#define SimpleType 0
#define PulldownType 1
X
extern void error(char*);
X
char *ext_string(char * str); // extend str for 1 + 1 space 
X
GC CreateGC(unsigned long mask, XGCValues * gcv);
X
void set_color(int color); // set color for gc_copy 
int alloc_color(unsigned red, unsigned green, unsigned blue);
int alloc_named_color(char *colname);
X
// draws pseudo-3D-borders, mode = up3d, flat3d (background pix), down3d
void rect3d(Window Win, int mode, short x, short y, short w, short h);
X
void tri3d_s(Window Win, int mode, short x, short y, short w, short h);
X
struct point { int x; int y; };
X
extern Colormap def_cmap;
extern Display * display;
extern int screen;
extern GC gc_copy, gc_but_xor, gc_clear, gc_inv, gc_rubber; 
// some often used gcs
extern GC button_fg_gc, button_br_gc, button_lw_gc; 
extern Cursor watch_cursor; // for long redraw methods eg. in coordwindows
extern Cursor hs_cursor, vs_cursor; // special cursors for scrollbars
extern XFontStruct * fixed_fn;
extern unsigned depth, black, white;
extern Bool True_Color_Visual; // only for TrueColor 
X                               // -> XAllocColorCells will not work then 
void handle_event(XEvent &event);
X
class window;
X
void safe_delete(window *w); // delete only, if not yet deleted !
X
struct win_list { // struct to manage a child list of any window
X  window *child; 
X  int x,y;
X  struct win_list *next;
X  win_list(window *ch, int x, int y, win_list *rest) : child(ch), x(x), y(y) 
X    { next = rest; }
};
X
class main_window;
class text_popup;
X
class window {
X
protected:
X  int border_width;
X  GC gc,text_gc;
X  text_popup * help; // ggf. help popup
X  window *parentw;   // only for destructors
X  long selection_mask; // default mask for SelectInput
X  Bool hidden;    // if true not realize the window 
public:  
X  main_window *mainw; // the main window of this window, direct child of root 
X  int width, height;
X  int CB_info;   // toggle debug infos on callbacks in this Window
X  Window Win;
X  int type;      // to distinguish simple <-> pulldown
X
X  win_list * children;        // chained List of children
X 
X  window(char * DISP = NULL); // constructor for root window
X  window(window & parent,
X	 int w = 0, int h = 0, int x = 0, int y = 0, int bw = 1);
X  // to update children list and fit the parent geometry :
X  virtual void add_child(window *ch, int x, int y);
X  
X  void remove_child(window *ch); // remove from my children list
X  virtual ~window();  // virtual destructor
X  
X  virtual void draw_interior() { }   // is called from Map to draw an image 
X  virtual void Map(); 
X  void Unmap() ;
X  void set_backing_store();  // set backing_store = WhenMapped
X  void set_save_under();     // save covered region when mapped
X
X  void Realize();
X  // Realize the whole Window tree from this root
X  void RealizeChildren();
X
X  virtual void clear();
X  virtual int eff_width() { return width; } // effective breadth minus pictures
X
X  virtual void DrawString(int x, int y, char * string);
X
X  // place a string with font (fixed_fn) at x,y (0 = centered)
X  void PlaceText(char * string,int x = 0, int y = 0,
X		   XFontStruct * fn = fixed_fn);
X  virtual void line(int x0, int y0, int x1, int y1);
X  virtual void DrawPoint(int x, int y);
X
X  void add_help(char * WMName,char * text[]);
X  
X  virtual void action(char*, char*) {} // action for windows, that shall
X  // be managed from radio_button - BPress-CBs
X
X  void WatchCursor(); // set cursor of main_window to watch
X  void ResetCursor(); // set back to normal
X  virtual void redraw() {}
X  virtual void resize(int, int);
protected:  
X  virtual void BPress_CB(XButtonEvent) {} 
X  virtual void BPress_1_CB(XButtonEvent); 
X  virtual void BPress_3_CB(XButtonEvent);
X  virtual void BRelease_CB(XButtonEvent) {} 
X  virtual void Enter_CB(XCrossingEvent) {}
X  virtual void Leave_CB(XCrossingEvent) {}
X  virtual void Motion_CB(XMotionEvent) {} // pointer movements
X  virtual void Expose_CB(XExposeEvent);
X  virtual void KeyPress_CB(XKeyEvent) {}
X  virtual void Configure_CB(XConfigureEvent) {} // only main_windows
X  virtual void ClientMsg_CB(XClientMessageEvent) {} // for msg from w manager
X
public:  
X  void CallBack(XEvent &event) ;
};
X
// for special applications : in the main_loop use polling 
// extern Bool polling_mode; // use polling instead of XNextEvent
// extern void (*poll_handler)(); // called after each polling 
X
class main_window : public window {
protected:
X  Bool polling_mode; // for special applications: in the main_loop use polling 
X  // with the virtual function "polling_handler" instead of XNextEvent
X  char *name;
public: 
X  int exit_flag; // used in main_loop to break it
X  main_window(char *Name, int w, int h, int fix_pos = 0, int x = 0, int y = 0);
X  ~main_window();
X  void do_popup(int x, int y); // Realize at absolute x,y-coords
X  virtual void Configure_CB(XConfigureEvent ev);
X  virtual void ClientMsg_CB(XClientMessageEvent ev);
X  void set_icon(char ibits[], int iwidth, int iheight);
X  void main_loop(); 
X  virtual void polling_handler() {}
};
X
// A window that stores its content in a Pixmap, to enable a quick Expose
// Each drawing operation is done to Pixmap, Map & Expose copy pix -> Win
// 
class pixmap_window : public window {
protected:
X  Pixmap pix;  // to store the image and re-map in expose events
public:
X  pixmap_window(window & parent, int w = 0, int h = 0, 
X	       int x = 0, int y = 0, int bw = 1);
X  virtual ~pixmap_window();
X  virtual void clear();
X  virtual void Map(); // copy pix -> Win
X  virtual void DrawString(int x, int y, char * string);
X  virtual void line(int x0, int y0, int x1, int y1);
X  virtual void DrawPoint(int x, int y);
X  virtual void Expose_CB(XExposeEvent ev); 
X  virtual void draw_interior() = 0;
X  virtual void redraw() { clear(); Map(); }
X  virtual void resize(int,int);
};
X
// very simple window to place text
class text_win : public window {
char *text;
public:
X  text_win(window &parent, char *text, int w,int h, int x, int y, int bw = 0) :
X    window(parent,w,h,x,y,bw), text(text) {}
X  virtual void redraw() { PlaceText(text);  }
};
X
// manage position of children
class horizontal_container {
X  int min_w, max_w; // minimum & maximum width for children
public:
X  int xp, yp; // place position for next child, is updated from children
X  int getw(int w) { return ((w > min_w) ? ((w > max_w) ? max_w : w) : min_w) ;}
X  horizontal_container(int minw, int maxw) : min_w(minw), max_w(maxw) 
X  { xp = yp = 0; }
};
X
class menu_bar : public window, public horizontal_container {
public:
X  menu_bar(window & parent, int w, int h, int x = 0, int y = 0, 
X	   int minw = 0, int maxw = 1000, int bw = 1)
X  : window(parent,w,h,x,y,bw), horizontal_container(minw,maxw) {}
X  virtual void add_child(window *child, int x, int y) { 
X    window::add_child(child,x,y); xp += getw(child->width); 
X  }
};
X
class text_popup : public main_window  {
X  char ** pop_text;
public: 
X  text_popup(char * WMName, int w, int h, char *text[]); 
X  void Expose_CB(XExposeEvent ev);
};
X
// Konstanten zur 3d Darstellung
#define down3d 0 
#define up3d   1 
#define flat3d 2
X
// a window with pseudo-3d frames
class plate : public window { 
X  int mode3d;
public:
X  plate(window & parent, int w, int h, int x = 0, int y = 0,int mode3d = up3d);
X  virtual void redraw();  
protected:  
X  void frame3d(int mode) { rect3d(Win, mode, 0, 0, width-1, height-1); }
X  virtual void default_frame() { frame3d(mode3d); }
};
X
class button : public plate {
X  //  parent is a pulldown menu -> other dynamic frame mode
X  int in_pulldown;
protected:
X  // the breadth of strings for  menu_bar (for auto-placement in container)
X  int Nwidth(char *str) { return 6*strlen(str) + 6; }
public:
X  char * Name;
X  void add_help(char **help_text); // replaces window::add_help
X  void init_button(window *parent);
X  button (window & parent, char * Name, int w, int h, 
X	  int x = 0, int y = 0) :
X  plate (parent, w, h, x, y), Name(Name) { init_button(&parent); }
X
X  button (window & parent, char * Name, char ** help_text, int w, int h,
X	  int x = 0, int y = 0) : plate (parent, w, h, x, y), Name(Name) 
X    { add_help(help_text); init_button(&parent); }
X  
X  // autosizing buttons
X  button (menu_bar & parent, char * Name) :
X    Name(Name), plate (parent, parent.getw(Nwidth(Name)),  
X                       parent.height, parent.xp, parent.yp) 
X    { init_button(&parent); }
X  virtual ~button();
X  virtual void default_frame() { frame3d(in_pulldown ? flat3d : up3d);  }
X  void enter_frame() { frame3d(in_pulldown ? up3d : flat3d); }
X  virtual void redraw(); 
protected: 
X  virtual void Enter_CB(XCrossingEvent) { enter_frame(); }
X  virtual void Leave_CB(XCrossingEvent) { default_frame(); }
X  virtual void BPress_CB(XButtonEvent) { frame3d(down3d); }
X
X  virtual void BPress_1_CB(XButtonEvent ) { 
X    // printf("button press '%s' %d \n", Name, ev.button); 
X  }
X  virtual void BRelease_1_action() {} // hook for callbacks with Button1
X  virtual void BRelease_CB(XButtonEvent ev) { 
X    if (ev.state & Button1Mask) { BRelease_1_action(); default_frame(); }
X  }
X
};
X
//                 ##### delete_button #####
// for ordered deleting a window and all of its children recursively
// following events for them are catched by setting the thisW-pointer to NULL
class delete_button : public button { 
window * to_del;
public: 
X  delete_button(window & parent, window * to_del, int w, int h, int x, int y): 
X    button(parent, "delete", w, h, x, y), to_del(to_del) {}
X  delete_button(menu_bar & parent, window * to_del) :
X    button(parent, "delete"), to_del(to_del) {}
private:
X  void BPress_1_CB(XButtonEvent) { to_del->Unmap(); delete (to_del); }
};
X
//             **** "quit_button" ****
// exiting main_loop with setting the exit_flag of corr. main_window
class quit_button : public button { 
public: 
X  quit_button(window & parent, int w, int h, int x, int y) : 
X    button(parent, "quit", w, h, x, y) {}
X  quit_button(menu_bar & parent) : button(parent, "quit") {}
private:
X  void BPress_1_CB(XButtonEvent) { mainw->exit_flag = TRUE; }
};
X
// popup_button : realize the popup menu when BPress (make it visibel) 
// if pressed again : make it unvisible 
class popup_button : public button {
protected: 
X  main_window * popup_menu; 
public: 
X  popup_button(window &parent, main_window * menu, char * Name, 
X	       int w, int h, int x, int y) :
X    button(parent, Name, w, h, x, y) { popup_menu = menu; }  
X
X  popup_button(menu_bar &parent, main_window * menu, char * Name) :
X    button(parent, Name) { popup_menu = menu; } 
protected:
X  virtual void BPress_1_CB(XButtonEvent ev);
};
X
// popup a window with help text and a OK button
// the popup window is created in make_popup from the text array
class help_button : public popup_button {
public: 
X  help_button(window & parent, int x, int y, char * text[]) :
X    popup_button(parent, NULL, "help", 60, 20, x, y) { make_popup(text); }
X
X  help_button(menu_bar & parent, char * Name, char * text[]) :
X    popup_button(parent,NULL, Name) { make_popup(text); }
private:
X  void make_popup(char * text[]);
};
X
// *** "callback_button" class ****
// a button attached with a callback function on BRelease !! event
class callback_button : public button {
X  void (*callback) ();
public:
X  callback_button (window & parent, char * Name, void (*cb)(), 
X		   int w, int h, int x = 0, int y = 0) : 
X  button (parent, Name, w, h, x, y), callback(cb) { }
X  
X  callback_button (menu_bar & parent, char * Name, void (*cb)()) : 
X  button (parent, Name), callback(cb) { }
X
protected:
X  virtual void BPress_1_CB(XButtonEvent) { } // do nothing
X  virtual void BRelease_1_action()  { (*callback)(); } 
};
X
// *** "template_button" class ****
// invokes any member function (void) of an instance of class T, or
// a simple function that has T as argument
// ie. the callback-function is of type "void cb(T)"
// example:  void dist(float x) {ww->z +=x;..} 
//            template_button <float> (mb,"Name", dist, 2);
X
template <class T>
class template_button : public button {
X  void (*callback) (T);
X  T value;
public:
X  template_button (window & parent, char * Name, void (*cb)(T), T val,
X		   int w, int h, int x = 0, int y = 0) : 
X  button (parent, Name, w, h, x, y), callback(cb) {value = val; }
X  
X  template_button (menu_bar & parent, char * Name, void (*cb)(T), 
X		  T val) : 
X  button (parent, Name), callback(cb) { value = val; }
X
protected:
X  virtual void BPress_1_CB(XButtonEvent) { } // do nothing
X  virtual void BRelease_1_action()  { (*callback)(value); }
};
X
//   ***** instance_button : template button for member-functions of class
template <class T>
class instance_button : public button {
X  void (T::*member)();
X  T *instance;
public:
X  instance_button(window &parent, char *Name, void (T::*mem)(), T *inst,
X		  int w, int h, int x, int y) :
X    button(parent,Name,w,h,x,y) { member = mem; instance = inst; }
X
X  instance_button(menu_bar &parent, char *Name, void (T::*mem)(), T *inst) :
X    button(parent,Name) { member = mem; instance = inst; }  
protected:
X  virtual void BPress_1_CB(XButtonEvent) { (instance->*member)(); }
X  virtual void BRelease_1_action() {} 
};
X
// *** "function_button" class **** : yet another variant of callbacks
// a button attached with a callback function on BRelease !! events
// the callback_function gets all arguments of the  ellipses
// (pointer or int); max 10 
// default arguments are not prohibited !
X
#include <stdarg.h>
X
typedef void (*CB)(...); // type of the callback fn
X
class function_button : public button {
X  CB callback;
X  void *values[10]; // the passed values
public:
X  function_button (window & parent, char * Name,  
X                   int w, int h, int x, int y, CB cb,  ...);
X
X  function_button (menu_bar & parent, char * Name, CB cb, ...);
protected:
X  virtual void BPress_1_CB(XButtonEvent) { } // do nothing
X  virtual void BRelease_1_action() {
X    (*callback)(values[0],values[1],values[2],values[3],values[4],values[5],
X		values[6],values[7],values[8],values[9]);} 
};
X
typedef void (*VVP)(void *); // typecast for callbacks with void* argument
X
// ****** class switch_button *****
X
// a button with 2 states of display, which switch on click
// the 2. string should be <= the first (= initial)
class switch_button : public button {
X  char *Narr[2]; // the two strings for display
X  VVP callbck; // the callback to call with instance ptr
X  void *instptr;
X  Bool *toggle; // the pointer to toggled value
public:  
X  switch_button (menu_bar & parent, char *Name1, char *Name2, Bool *toggle,
X		 VVP inf, void * toinf);
X
X  switch_button (window & parent, char *Name1, char *Name2, Bool *toggle,
X		 VVP inf, void * toinf, int w, int h, int x, int y);
X
X  void switch_it();
protected:
X  virtual void BPress_1_CB(XButtonEvent) { } // do nothing
X  virtual void BRelease_1_action() { switch_it(); }
};
X
X
//     ****** class toggle_button : with display of state ****
X
class toggle_button : public button {
X  int *vptr; // the pointer to  toggle-value
X  int xright; // place for picture on the right side
X  virtual int eff_width() { return (width - xright); } // for PlaceText
public:
X  toggle_button(menu_bar &parent, char *Name, int *ref) : 
X      button(parent,ext_string(Name)) { vptr = ref ; xright = 12; }
X  toggle_button(window &parent, char *Name, int *ref, int w, int h, 
X		 int x, int y ) :
X      button(parent,Name,w,h,x,y) { vptr = ref; xright = 12; }
X  void picture() { // 8x8 Pixel gross
X    int offs = (height-8)/2; // distance to top- and bottom border
X    rect3d(Win,(*vptr) ? down3d : up3d, width-xright,offs,8,8); }
protected:
X  virtual void toggle_cb (int) {}  // can be overloded
X  virtual void BRelease_1_action() { 
X    *vptr = ! *vptr; picture(); toggle_cb(*vptr); }
X  virtual void redraw() { button::redraw(); picture(); }
};
X
//   ************  frequently used : toggle and redraw a window
class toggle_redraw_button : public toggle_button {
window *win;
public:
X  toggle_redraw_button(menu_bar &parent, char * Name, int *ref, window *win):
X     toggle_button(parent,Name,ref), win(win) { }
X  virtual void toggle_cb(int) { win->redraw(); }
};
X
// *********************************************************************
//                   PULLDOWN windows
// pulldown window : a window child from root_window, not yet visible, 
// not managed from WM, position is determined from the button at popup time
class pulldown_window : public main_window {
public:
X  pulldown_window (int w, int h);
X  inline void Release_CB(XButtonEvent) { Unmap();}
};
X
//     **** "pulldown_button" class *****
// map the window (menu) on root when button is activated (BPress)
// the window is mapped to absolute co-ordinates !
class pulldown_button : public button { 
X  pulldown_window  * pulldown_menu; 
X  int xright;
X  virtual int eff_width() { return (width-xright); }
public:
X  pulldown_button (window & parent, pulldown_window * menu, char * Name, 
X		   int w, int h, int x, int y);
X  pulldown_button(menu_bar & parent, pulldown_window * menu, 
X		  char * Name);
X  pulldown_button (window & parent, pulldown_window * menu, char * Name, 
X		   char ** help_text, int w, int h, int x, int y);
X  void picture();
protected:
X  virtual void BPress_1_CB(XButtonEvent ev);   
X  virtual void Leave_CB(XCrossingEvent ev) { // iff B1 was not pressed
X    if (!(ev.state & Button1Mask)) default_frame(); }
X  virtual void redraw() { button::redraw(); picture(); }
};
X
X
// creates single button entry with Name and value in a radio_menu
class radio_button : public button {
X  char * value;  // the special value
X  char * menu_name ; // the name of the button which pulled this radio_menu
X  window * action_win;
public:    
X  radio_button(pulldown_window &parent, char * MName, 
X	       int w, int h, int x, int y, char * val, window * action) 
X       : button(parent,val,w,h,x,y), value(val) {
X    menu_name = MName; // Name of menu_button; is passed to action
X    action_win = action;
X  }
protected:
X  virtual void BRelease_1_action() { 
X    if (action_win) action_win->action(menu_name, value); 
X  }
};
X
// makes a radio-menu (toggle) with  named buttons (name = value : string)
// list : consists of char* : { "value1", "value2",..., 0 }
// action_win : window which "action" method is to call after toggle
// the Name (as pointer) is passed also -> to know which menu was activated
pulldown_button * make_radio_menu(window &parent, char *Name,
X				  char **blist,  window * action_win = 0,
X				  int w= 0, int h= 0, int x= 0, int y= 0);
X
// analogous : with help popup
pulldown_button * make_radio_menu(window &parent, char *Name, char **list,
X				  char ** help_text, window * action_win = 0,
X				  int w= 0, int h= 0, int x= 0, int y= 0 ); 
X
// for callback_buttons : name string, callback function
struct but_cb { char * bname; void (*cb) (); };
X
// makes pulldown_menu with a list of callback_buttons
// und einem pulldown_button (im parent) der es aktiviert
pulldown_button * make_pulldown_menu(window &parent, char *Name, 
X				     int nbuttons, struct but_cb list[],
X				     int w= 0, int h= 0 , int x= 0, int y= 0);
X
// ---------------------- POPUP WINDOWS ------------------------------------
X
// unmap_button : a special button to Unmap the parent
//                 on BPress, esp. usefull for popup menus
class unmap_button : public button { 
X  window * to_unmap;
public: 
X  unmap_button(window & parent, char * string,
X	       int w, int h, int x, int y) : 
X  button(parent,string, w, h, x, y) { to_unmap = &parent;}  
X  // 2. constructor, used for unmap_buttons on menu_bars
X  unmap_button(menu_bar & parent, char * string, window * unmap) :
X    button(parent,string) { to_unmap = unmap;}
private:
X  virtual void BPress_1_CB(XButtonEvent) { to_unmap->Unmap(); }
};
X
// computes for string array: max length of strings && number of strings 
void compute_text_size(char *text[], int &cols, int &lines);
X
// define a co-ordinate system in a window 
class coord_window : public pixmap_window {
protected:
X  int x0,y0; // window-coordinates of origin
X  int w_eff,h_eff; // effective	width and height of coord-sys
X  int w_diff,h_diff,rxl,ryd;
X  float xl,yd, // WC of left, bottom edge (origin, ia: 0,0)
X        xr,yu, // WC of right, top edge (ia: xmax, ymax)
X        xf,yf; // transformation factors
public:
X
X  void define_coord(float x1, float y1, float x2, float y2);
X
X  // compute total window-coordinates from world-values
X  int x_window(float x);
X  int y_window(float y);
X  XPoint p_window(float x, float y); // returns same as XPoint
X 
X  // back transformation : window coords to world-values
X  float x_org(int xw);
X  float y_org(int yw);
X
X  // rx : free rand left/right & ry : bottom
X  coord_window(window & parent, int w, int h, int x, int y, 
X	       int rxl = 5, int rxr = 5, int ryd = 5, int ryu = 5);
X 
X  // draws line with normed window coordinates
X  // ie. origin => (0,0), y grows upwards !!
X  void rline(int xp, int yp, int xq, int yq) {
X    line(x0 + xp, y0 - yp, x0 + xq, y0 - yq); }
X  
X  void draw_coords() {
X    rline(0,0,0,h_eff); rline(0,0,w_eff,0);
X   }
X  // draw x-ticks from xl..xo in dx-steps, max n ticks
X  void x_ticks(float dx, int n = 1000);
X  void y_ticks(float dy, int n = 1000);
X
X  void wline(float x1, float y1, float x2, float y2) {
X    line(x_window(x1),y_window(y1),x_window(x2),y_window(y2)); }
X 
X  void graph(int nx, double f[]); 
};
X
// invokes system-call with cmdline-string as argument
class system_button : public button {
char * cmdline;
public: 
X  system_button(window &parent,char *Name, char *cmdline, 
X	      int w, int h, int x, int y) : 
X    button(parent,Name,w,h,x,y), cmdline(cmdline) {}
X  virtual void BPress_1_CB(XButtonEvent);
};
X
// calls 'system("xwd -in wid " + arg)' and produces X-Window-dump of the
// window 'dumpw'; 
// with "arg" the output can be controlled
// eg. "-out -nobdr dump.file" or " | xpr | lpr " as hardcopy 
// with "xwud -in dump.file" or "xpr" to display or print
// eg:  'xwd_button du1(mb,"dump","-nobdrs -out dump.file",pwindow);'
class xwd_button : public button { 
window * dumpw;
char * arg; 
public: 
X  xwd_button(window &parent, char *Name, char *arg, window *dumpw,
X	      int w, int h, int x, int y) : 
X    button(parent,Name,w,h,x,y), dumpw(dumpw), arg(arg) {}
X  
X  xwd_button(menu_bar &parent,char *Name, char *arg, window *dumpw ) : 
X    button(parent,Name), dumpw(dumpw), arg(arg) {}
X
X  void BPress_1_CB(XButtonEvent);
};
X 
// **************************************************************
//               SCROLLBARS
X
// sliders as movable plate for scrollbars
class slider : public plate { 
public: 
X  slider(window &parent, int w, int h, int x, int y); 
X  virtual void redraw(); // called from Expose_CB
};
X
// a simple scrollbar without display of the value (should not be used)
// if the 1. constructor (without xanf) is used, the slider must explicitely 
// be set !!
X
class pure_scrollbar : public plate {
X  slider * bar;
protected:
X  int sw,sh,sy,xoff,xmax,xspan,xact;
public:
X  int nticks; // the number of tick lines (def = 0)
X  void set_slider(int x); // fuer Anfang: Setzen des sliders nach x
X  void init (); // Setzen der Elemente
X  // 1. constructor: without initial value
X  pure_scrollbar(window &parent, int w, int h, int x, int y) :
X    plate (parent,w,h,x,y,down3d) { init(); }
X  // 2. constructor : with initial value 
X  pure_scrollbar(window &parent, int w, int h, int x, int y, int xanf) :
X    plate (parent,w,h,x,y,down3d) { init(); set_slider(xanf);}
X
protected:
X  // virtual function "callbck" is called from move
X  virtual void callbck(int x) { printf(" %d",x); fflush(stdout); } 
X
X  void move(int x); // Bewegen des sliders (x = Pointer) 
X  void move_cb(int x); // Bewegen des sliders (x = Pointer) und callbck  
X
X  virtual void redraw();
X
X  // Springen bei Maus-Click button1
X  virtual void BPress_1_CB(XButtonEvent ev) { move_cb(ev.x - xoff); }
X
X  // Ziehen, wenn Button1 gedrueckt
X  virtual void Motion_CB(XMotionEvent ev) { 
X    if (ev.state & Button1Mask) { move_cb(ev.x - xoff); }
X  } 
X  virtual void resize(int, int);
};
X
// to display the actual value of a slider
class display_window : public plate { 
char * val; 
public: 
X  display_window(window &parent, char *def, int w, int h, int x, int y, 
X		 int mode3d) :
X    plate(parent,w,h,x,y,mode3d) { val = def; }
X  void draw_val() { PlaceText(val); }
X  void set_text_mode(int mode); // mode 0 : Loeschen, 1 : Schreiben
X  virtual void redraw() { plate::redraw(); draw_val(); }
X
};
X
//   ********* class scrollbar ********
// the union "fn_union" is used to access the function pointer 
// for the 2 types of info function, that occur as callbacks
union fn_union {  
X  void (*empty)();     // der parameterlose call mode (Form 1)
X  void (*vptr)(void*); // der callmode mit void* (Form 2)
X  void *value;         // fuer Test auf NULL
};
X
// 2 constructors : with different callback-forms   
//      1. callback inf() as function without parameters  (old version )
//      2. callback inf(void *), gets the (void*) argument "to_inf" 
//         with this form memberfunctions of other classes can be called 
// "minp, maxp" are the limit values of the scrollbar, which are mapped to
//          [0..xspan] pixels
//          if maxp == 0 (default) the width of the slider is adopted
// "format" serves as transformation value
// "inf"    is an callback, which is called upon each move of the slider 
//          (without arguments), the actual value can be querried from
//          "scrollbar.value" 
// "xstart" is the starting value of the slider
X
class scrollbar : public pure_scrollbar {
X  display_window * disp_win;
X  pure_scrollbar * ps;
X  char str[80];
X  void *to_inform; // pointer for 2nd form
X  fn_union inffn;
X  char * format; // the format string for display, like in printf: "Wert = %4x"
protected:
X  double factor;   // the conversion factor x into pixels = 0..w -> min..max 
public:
X  int min, max, value;
private:
X  void setval(int x) { // update string and value
X    value = x; sprintf(str,format,x); 
X  }
X  int pwidth(int w) { return (w-60); } // the eff. width of pure_scrollbar
X  int pix_to_val(int pix) { return (irint(pix*factor) + min); }
X  int val_to_pix(int x) { return (irint((x-min)/factor)); }
public:
X  void init(window &parent, int w, int h, int x, int y,
X	    int minp, int maxp, int xstart);
X  // 1. construktor
X  scrollbar(window &parent, void (*inf)(), int w, int h, int x, int y, 
X	    int minp = 0, int maxp = 0, int xstart = 0, char *format = "%d");
X  // 2. construktor
X  scrollbar(window &parent, void (*inf)(void*), void * to_inf,
X	    int w, int h, int x, int y, 
X	    int minp = 0, int maxp = 0, int xstart = 0, char *format = "%d");
X
X  // explicite setting of slider and display 
X  void change(int x) { move( val_to_pix(x) ); callbck_val(x);} 
protected:
X  virtual void callbck(int pix) {  // called from move_cb (mouse events)
X    callbck_val( pix_to_val(pix) );
X  }
X  virtual void callbck_val(int x);    // called from change
X  virtual void resize(int, int);
};
X
// **** class tick_scrollbar ***** : scrollbar with ticks and numbers
// has fixed height (20 + 15 = 35) with ticks and value displays 
X
#define MAXTCKS 20 // max number of ticks+2 
X
class tick_scrollbar : public scrollbar {
X  text_win *valtxt[MAXTCKS+2]; // display windows for : max 20 ticks !!
X  char *strvec; // holds all tick numbers as C-strings 
X  char *valstr[MAXTCKS+2]; // pointer to individual tick-string into strvec
X  void tickstr();
public:
X  tick_scrollbar(window &parent, void (*inf)(void*), void * to_inf,
X		 int w, int x, int y, int n_ticks, int minp = 0, 
X		 int maxp = 0, int xstart = 0, char *format = "%d");
X  ~tick_scrollbar();
X  void adapt(int maxp, int xstart);
};
X  
// container class for interaction between play_scrollbar and 
// a lattice drawer class 
// methods must be overwritten from derived classes,
// a pointer of this class is given to play_scrollbar as argument
class stepper {
public:
X  virtual void seek_step(int i) = 0; // seek and perform actual drawing
X  virtual Bool switch_play_mode(VVP, void*) = 0; // returns actual mode
};
X
// **** class play_scrollbar ***
// tick_scrollbar, that adds playback- and stepping buttons left and right  
class play_scrollbar : public tick_scrollbar {
X  stepper *stp;
X  Bool play_mode;
X  // called when setting the slider, or indirectly from step_xxx
X  void updated() { stp->seek_step(value); }
X
X  // button callback functions :
X  void step_fwd() { change(value+1); } 
X  void step_bck() { change(value-1); } 
X  void reset() { change(min); }
X
X  void switch_play() {
X    play_mode = stp->switch_play_mode((VVP)&play_scrollbar::step_fwd,this);
X  }
X
public:
X  play_scrollbar(window &parent, int w, int x, int y, int n_ticks, stepper *stp,
X		 int minp = 0, int maxp = 0, int xstart = 0) : stp(stp),
X  tick_scrollbar(parent, (VVP) &play_scrollbar::updated, this, w-2*(15+20), 
X		 x+15+20, y, n_ticks, minp, maxp, xstart) {
X    new instance_button <play_scrollbar> 
X      (parent,">", &play_scrollbar::step_fwd, this, 15, 20, 0, 0); // left
X    
X    new instance_button <play_scrollbar> 
X      (parent,"<", &play_scrollbar::step_bck, this, 15, 20, w-35, 0); // right
X  
X    new switch_button(parent,">>","||",&play_mode,
X		      (VVP) &play_scrollbar::switch_play,this, 20, 20, 15, 0);
X    new instance_button <play_scrollbar> 
X      (parent,"<<", &play_scrollbar::reset, this, 20, 20, w-20, 0);
X  }
};
X
X
// class for temporarily set and reset cursor for a window 
// using constructors & destructors
class TempCursor {
X window * win;
X public:
X  TempCursor(window *w) {
X    win = w;
X    XDefineCursor(display, win->Win, watch_cursor);
X   }
X  ~TempCursor() { XUndefineCursor(display, win->Win); }
};
X
// ***************************************
// class "edit_window" for editing  of strings, max 200 chars long 
// two virtual fn should be newly defined in derived classes: 
//   enter - action on completion
//   escape - aborting
class edit_window : public plate {
X  int cp; // text cursor position in string (0..strlen)
X  int xs; // x-pos of string start
protected:
X  void mark_cursor();
X  virtual void Enter_CB(XCrossingEvent ev);
X  virtual void Leave_CB(XCrossingEvent ev);
X
X  void del_char();
X  void ins_char(char x);
public:
X  char value[200];  
X  edit_window(window &parent, char *str, int w,int h, int x, int y);
X  virtual void redraw();
X  virtual void enter() { printf("%s\n",value); } // to overwrite
X  virtual void escape() { memset(value,0,80); cp = 0; } // clears string
X  virtual void format_error() { XBell(display,10); }
X  void KeyPress_CB(XKeyEvent ev);
};
X
// class to display a simple analogue clock bound to an external time variable
class clock_win : public pixmap_window {
public:
X  int* tptr; // pointer to the time variable (in seconds), 
X             // to be updated externally !
X  int xc,yc; // centre co-ordinates
X  float rh,rm; // rx = radius of minute/hour arrows
X  int d; // diameter of the clock
X    // *tptr is the timer
X  clock_win(window &parent, int *tptr,int w, int h, int x, int y);
X  void arrow(double phi, float r);  // display a centered arrow with radius r
X  virtual void draw_interior();
X  virtual void resize(int w, int h);
X  void init();
};
X
//  ************* twodim_input ***********
// a class used to get a twodim value from a mouse pointer driven slider
X
class twodim_input;
X
typedef void (*CBHOOK)(void *,twodim_input *); // the correct type for cbhook 
X
class twodim_input : public plate {
X  plate *bar;
X  void *vptr; // the first arg for cbhook -> should be a this-pointer
protected:
X  int sw,sh; // slider size
X  int sx,sy; // slider offset to borders
public:
X  int xact,yact; // actual position (0..*span)
X  int xspan,yspan; // span width for movement x,y = [0..zspan]
X  // the cbhook should be used to respond on input 
X  void (*cbhook)(void*, twodim_input *);
X
X  // swp, shp : width/height of slider; if = 0 : confined in this direction 
X  // vptr : passed as 1. argument to cbhook
X  twodim_input(window &parent, int w, int h, int x, int y, int swp, int shp,
X	       void *vptr = NULL);
protected:
X  void set_vars();
X  void move(int x, int y);  // called from Events
X  virtual void BPress_CB(XButtonEvent ev);
X  virtual void Motion_CB(XMotionEvent ev);
X
public: 
X  void set_slider(int x, int y);
X  void slider_adapt(int swp,int shp); // called from resize && others 
X  void resize(int w, int h);
X  void configure(int w, int h, int swp, int shp, int x, int y);
};
X
// two simple convinience derivations from twodim_input
class horizontal_shifter : public twodim_input {
public:
X  horizontal_shifter(window &parent, int w, int h, int x, int y, int sw, 
X		     CBHOOK cbh, void *vptr = NULL);
};
X
class vertical_shifter : public twodim_input {
public:
X  vertical_shifter(window &parent, int w, int h, int x, int y, int sh,
X		   CBHOOK cbh, void *vptr = NULL); 
};
X
// scrolled_window has a virtual window which can be shifted with shifters
// arguments are : real width/height, virtual width/height
// (the first window with correct resizing)
// the virtual window must be derived from class virtual_window !!!
class scrolled_window : public window {
X  int xp, yp; // actual position
X  int hvis,wvis; // visible window size
X  // the hook called from shifters : shift drawing_area
X  void cbhook(twodim_input *ts); 
public:
X  twodim_input *vs, *hs;
X  window *clip; // the clipped region
X  window *virt_win; // the virtual window
X  int hvirt, wvirt; // the virtual size
X
X  scrolled_window(window &parent, int w, int h, int vw, int vh, 
X	       int x = 0, int y = 0);
X  virtual void resize(int w, int h);
};
X
// class to enable a convinient linking of virtual window for scrolled_window
// *** an instance must be defined for every scrolled_window *** !!!
class virtual_window  : public window {
public:
X  virtual_window(scrolled_window *scr) : 
X  window(*(scr->clip), scr->wvirt, scr->hvirt,0,0,0) { // no border
X    scr->virt_win = this; 
X  }
X  virtual void redraw() = 0; // if not defined : useless !!
X  virtual void resize(int, int) {} // do nothing !!
};
SHAR_EOF
chmod 0644 window.h ||
echo 'restore of window.h failed'
Wc_c="`wc -c < 'window.h'`"
test 34405 -eq "$Wc_c" ||
	echo 'window.h: original size 34405, current size' "$Wc_c"
fi
# ============= lat_win.c ==============
if test -f 'lat_win.c' -a X"$1" != X"-c"; then
	echo 'x - skipping lat_win.c (File already exists)'
else
echo 'x - extracting lat_win.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'lat_win.c' &&
#include "lattice.h"
X
float grd2rad = 180.0/M_PI; // conversion grad -> radian
static int debug = 0;
X
lattice_window::lattice_window(window & parent, int w, int h, int x, int y) :
X    coord_window(parent,w,h,x,y,2,2,2,2) // free rand : hor, vert : 2 Pix
{ 
X   scptr = NULL;
X   ncolors = 100;
X   ixstart = 0; ixend = 0;
X   iystart = 0; iyend = 0; rand = 0;
X   external_colors = NULL; 
}
X
// draw clipped lines using global clip vectors y_top, y_bot
// lastp : draw last point of line (1) or not (0)
void lattice_window::cline(XPoint a, XPoint b, int lastp) {
X  int sx,sy,dx,dy,x,y,visible,ytt,ybb,up,down;
X  int ex = 0, ey = 0;
X  if (debug) printf(" %d %d %d %d ",a.x,a.y,b.x,b.y);
X  
X  dx = b.x - a.x; dy = b.y - a.y;
X  sx = (dx > 0) ? 1 : ((dx < 0) ? -1 : 0);
X  sy = (dy > 0) ? 1 : ((dy < 0) ? -1 : 0);
X
X  x = a.x; y = a.y; 
X  dx = abs(dx); dy = abs(dy);
X
X  do { 
X    up = (y > y_top[x]); down = (y < y_bot[x]); 
X    if (up) ytt = y; if (down) ybb = y;
X    visible = up || down; 
X    int endp = (x == b.x) && (y == b.y);
X    if (endp &&  ! lastp) break;
X
X    if (visible) DrawPoint(x,y); 
X
X    if (dy < dx) {
X      if (up) y_top[x] = ytt; if (down) y_bot[x] = ybb; 
X      x += sx; ey += dy;  
X      if (2*ey > dx) { y += sy; ey -= dx; } 
X    } else {
X      y += sy; ex += dx;
X      if (2*ex > dy) {  
X	if (up) y_top[x] = ytt; if (down) y_bot[x] = ybb; 
X	x += sx; ex -= dy; }
X    }
X    if (endp) break; 
X  } while (1);  
}
X
// fills from the line (a,b) up to the boundaries y_top, y_bot
// if (lastp) including the endpoint, 
// if (dofill) really fill, else only set boundaries
void lattice_window::fill(XPoint a, XPoint b, int lastp, int dofill) {
X  int sx,sy,dx,dy,x,y;
X  int ex = 0, ey = 0;
X
X  dx = b.x - a.x; dy = b.y - a.y;
X  sx = (dx > 0) ? 1 : ((dx < 0) ? -1 : 0);
X  sy = (dy > 0) ? 1 : ((dy < 0) ? -1 : 0);
X
X  x = a.x; y = a.y; 
X  dx = abs(dx); dy = abs(dy);
X
X  if (dy < dx) { 
X    do {
X      int endp = (x == b.x) && (y == b.y);
X      if (endp &&  ! lastp) break;
X
X      if (y > y_top[x]) { if (dofill) line(x,y,x,y_top[x]); y_top[x] = y; }
X      if (y < y_bot[x]) { if (dofill) line(x,y,x,y_bot[x]); y_bot[x] = y; }
X      x += sx; ey += dy;  
X      if (2*ey > dx) { y += sy; ey -= dx; } 
X      if (endp) break; 
X    } while (1);  
X  } else {
X    do {
X      int endp = (x == b.x) && (y == b.y);
X      if (endp &&  ! lastp) break;
X
X      y += sy; ex += dx;
X      if (2*ex > dy) {  
X	if (y > y_top[x]) { if (dofill) line(x,y,x,y_top[x]); y_top[x] = y; }
X        if (y < y_bot[x]) { if (dofill) line(x,y,x,y_bot[x]); y_bot[x] = y; }
X	x += sx; ex -= dy; }
X    
X      if (endp) break; 
X    } while (1);  
X  }
}
X
struct XPoint lattice_window::screen_project(float x, float y, float z)
{
X  float xs,ys,yss,zss,t,dx,dy; 
X  // printf(" %f %f %f \n",x,y,z);
X  dx = x - xp; dy = y - yp;
X  xs = ca*dx - sa*dy;  ys = ca*dy + sa*dx;     // rotation x,y-plane
X  zss = cb*z - sb*ys; yss = cb*ys + sb*z;      // rotation ys,z-plane
X    
X  // central-projection with perspective
X  // exaktly : temp.y = arcsin(yss/(distance - zss)) = y-view angle
X  // where "distance" is distance between viewpoint and origin
X
X  t = (dist == 0.0) ? 1.0 : 1.0/(1.0 - dist*zss/xp); 	   
X  XPoint temp = p_window(t*xs,t*yss);
X
X  // this should not happen, it would overflow y_top, y_bot indicees
X  // clip to boundary values
X  if (temp.x < 0) temp.x = 0; else if (temp.x >= width) temp.x = width-1;
X  return temp;
}
X
void reverse(int &x1, int &x2, int &dx) {
X  int tmp = x1; x1 = x2; x2 = tmp; dx = -dx;
}
X
// the old method for lattice drawing is obsolete
// alpha, beta : Drehwinkel (hier rad!), gamma : z-Faktor,
/*
void lattice_window::make_lattice(int nx, int ny, float *FF, 
X			       float alpha, float beta, float gamma, float z0, 
X			       int opaque, float distance)
{ 
X  float (*ff)[ny] = (float (*) [ny]) FF;
X  int x,y; 
X  y_bot = new int[width]; y_top = new int[width]; 
X  for (x=0; x < width; x++) { y_top[x] = 0; y_bot[x] = height; }
X
X  ca = cos(alpha); sa = sin(alpha); cb = cos(beta); sb = sin(beta);
X  dist = distance;
X  // printf(" %d %d %f %f %f\n",nx,ny,alpha,beta,gamma);
X
X  // the ix-range [xstart .. xend] will be mapped to [0..xdraw-1] 
X  int xdraw,ydraw;     // the x,y-lattice values, to be drawn
X  if (ixend == 0) ixend = nx; // with 0 initialized
X  if (iyend == 0) iyend = ny;
X  xdraw = ixend - ixstart + 2; // + 2 points for border
X  ydraw = iyend - iystart + 2;
X  
X  xspan = ixend - ixstart - 1; yspan = iyend - iystart -1;
X  xp = 0.5*xspan; yp= 0.5*yspan; // rotation centre in x,y plane
X  
X  float xmax,ymax;
X  ymax = xmax = 0.5*sqrt(xspan*xspan + yspan*yspan); 
X
X  //    printf( "%d %d %d %d \n",ixstart,iystart,xdraw,ydraw);
X  define_coord(-xmax, -ymax, xmax, ymax); 
X
X  int ix,iy;
X  float zh,xh,yh;
X  zmax = -1E30; 
X
X  struct XPoint scp[xdraw][ydraw]; // all grid-points after transformation
X  // x,y : indicees of  scp ; 
X  // xh,yh,z : 3d-coordinates
X  // ix,iy : indicees of  ff 
X  // die Ecken zB. (xh,yh,zh) = (0,0,0) -> will be mapped three times to :  
X  //                x,y = (0,0) (0,1) (1,0) 
X  // xh,yh : (0,0,zh) -> (1,1)
X  znorm = gamma * xmax;
X  for (x = 1, ix = ixstart, xh = .0; x < xdraw-1; x++, ix++, xh += 1.0) { 
X    for (y = 1, iy = iystart, yh = .0; y < ydraw-1; y++, iy++, yh += 1.0 ) {
X      zh = znorm * (ff[ix][iy]- z0); if (zh > zmax) zmax = zh; 
X      scp[x][y] = screen_project(xh,yh,zh);
X    }
X  }
X  yh = ydraw-3;
X  for (x = 1, xh = 0.0; x<xdraw-1; x++, xh += 1.0) { 
X    scp[x][0] = screen_project(xh,0,0);
X    scp[x][ydraw-1] = screen_project(xh,yh,0); 
X  }
X  
X  xh = xdraw-3;
X  for (y = 1, yh = 0.0; y<ydraw-1; y++, yh += 1.0) { 
X    scp[0][y] = screen_project(0,yh,0);
X    scp[xdraw-1][y] = screen_project(xh,yh,0); 
X  }
X  scp[0][0] = scp[0][1];  scp[0][ydraw-1] = scp[0][ydraw-2];  
X  scp[xdraw-1][0] = scp[xdraw-2][0];  
X  scp[xdraw-1][ydraw-1] = scp[xdraw-2][ydraw-2]; 
X
X  int x0,y0,dx,dy,xx,yy,yt,x1,y1;
X
X  XPoint sc00 = screen_project(0,0,0),       // the origin   
X         scxy = screen_project(xdraw-3,ydraw-3,0), // the opposite edge       
X         scx = screen_project(xdraw-3,0,0),  // x,0
X         scy = screen_project(0,ydraw-3,0),  // 0,y
X         sczm = screen_project(0,0,zmax);   
X  pline(sc00,sczm);       // z-axis
X  
X  int i, dzy = sczm.y - sc00.y, nti; // draw z-ticks with numbers
X  nti = (abs(dzy) > 60) ? 5 : (abs(dzy) / 15 + 1); // number of ticks 
X  for (i=0; i< nti+1; i++) { 
X    float zi = i/float(nti);
X    int x = sc00.x, y = sc00.y + int(zi*dzy); 
X    line(x,y,x-4,y); // z tick
X    char ticks[20]; sprintf(ticks,"%g",zi*zmax/znorm + z0);
X    int xs = (x < width/2) ? x+3 : x - 6*strlen(ticks) - 6; // string position
X    DrawString(xs,y+5,ticks);
X  }
X
X  // determination of direction of   for-loops xx,yy
X  // so, that y is decreasing, ie start always in most forward point
X  // rand = 1 : drawing with border lines  , 
X  // else  rand = 0 : ie only from x = 1 .. xdraw-2 to draw
X  int orand = ! rand; // 0/1
X  x0 = orand; x1 = xdraw-orand-1; dx = 1;
X  if (sin(alpha) < 0.) reverse(x0,x1,dx);
X
X  y0 = orand; y1 = ydraw-orand-1; dy = 1;
X  if (cos(alpha) < 0.) reverse(y0,y1,dy);
X 
X  for (yy = y0 ; ; yy+= dy) {
X      for (xx = x0 ; ; xx+= dx) 
X	{ XPoint sc = scp[xx][yy];
X	  if (debug) printf("\n %d %d ", xx, yy);
X	  if (xx != x1) xline(sc,scp[xx+dx][yy],1);
X          if (yy != y1) xline(sc,scp[xx][yy+dy],0); 
X	  if (xx == x1) break;
X	} 
X      if (yy == y1) break;
X  }
X  // at least draw the xy axes
X  if (orand) { cline(sc00,scx,1); cline(sc00,scy,1); } 
X  
X   delete[] y_top; delete[] y_bot;
}
*/
X
// for swapping the driving step variables 
static void swap_dir(int& x0, int& x1, int &dx, float &f0, float &f1) {
X  int t = x0; x0 = x1; x1 = t; 
X  float f = f0; f0 = f1; f1 = f;
X  dx = -dx; 
}
X
palette_popup *pal_win = NULL; // popup window der color palette 
X
// draws a perspective picture of the gridwise defined function FF
// either with shading algorithm (body = True) or as a lattice
void lattice_window::make_body(int nx, int ny, float *FF, 
X			       float alpha, float beta, float gamma, float z0, 
X			       int opaque, 
X			       float distance, float al, float bl) {
X  float (*ff)[ny] = (float (*) [ny]) FF;
X  y_bot = new int[width]; y_top = new int[width]; 
X  int x,y; 
X  for (x=0; x < width; x++) { y_top[x] = 0; y_bot[x] = height; }
X
X  // eigentlich koennen hier alle Projektionen und clippings entfallen !
X  if (flat_mode) { alpha = beta = distance = 0; }
X
X  ca = cos(alpha); sa = sin(alpha); cb = cos(beta); sb = sin(beta);
X  dist = distance;
X  // printf(" %d %d %f %f %f\n",nx,ny,alpha,beta,gamma);
X
X  if (ixend == 0) ixend = nx; // am Anfang mit 0 initialisiert
X  if (iyend == 0) iyend = ny;
X  xspan = ixend - ixstart - 1; yspan = iyend - iystart -1;
X  xp = 0.5*xspan; yp= 0.5*yspan; // Drehpunkt der x,y-Ebene
X
X  float xmax,ymax;
X  if (flat_mode) { xmax = xp; ymax= yp; } else
X  ymax = xmax = 0.5*sqrt(xspan*xspan + yspan*yspan); 
X
X  define_coord(-xmax, -ymax, xmax, ymax); 
X
X  int ix,iy;
X  float zh,xh,yh;
X  zmax = -1E30;
X  if (scptr) delete[] scptr; 
X  scptr = new XPoint[nx*ny]; 
X  // all  nx*ny grid-points after trafo, addressed as scp[nx][ny]
X  struct XPoint (*scp)[ny] = (XPoint (*) [ny]) scptr; 
X  znorm = gamma * xmax;
X  for (ix = ixstart, xh = .0; ix < ixend; ix++, xh += 1.0) { 
X    for (iy = iystart, yh = .0; iy < iyend; iy++, yh += 1.0 ) {
X      zh = znorm * (ff[ix][iy]-z0); if (zh > zmax) zmax = zh;
X      if (flat_mode) { 
X	scp[ix][iy] = p_window(xh - xp,yh - yp);
X      } else
X      scp[ix][iy] = screen_project(xh, yh, zh);
X    }
X  }  
X
X  int colors[nx][ny];
X
X  if (body && ! external_colors) { 
X    // else : given colors for areas -> no computation               
X    // computing of reflections coefficients of the grid points
X    // subtraction of rotation angles -> means fixed (constant) light source
X    // otherwise : co-moving light source (moves with frame)
X    // disadvantage for fixed light source :
X    // upon rotating the orientation is bad 
X    float e_alpha = al /* -alpha */ , e_beta = bl /* -beta */ ;
X    float ex = cos(e_alpha)*cos(e_beta), ey = sin(e_alpha)*cos(e_beta), 
X    ez = sin(e_beta); // (ex,ey,ez) = normal of incident ray
X
X    float rpp[nx][ny];
X    float rmax = -1e30, rmin = 1e30, mu = 1/SQR(gamma); 
X    for (ix = ixstart+1; ix < ixend; ix++) { 
X      for (iy = iystart+1; iy < iyend; iy++) {
X	float z00 = ff[ix][iy]; // z0 shift not needed here
X	float z10 = ff[ix-1][iy], z01 = ff[ix][iy-1], z11 = ff[ix-1][iy-1];
X	// computation of normals  to (x,y) (x+1,y) (x,y+1) :
X	// n = (zx, zy, 1)/|N|
X	float zxp = z01 - z11,  zyp = z10 - z11; // growing differences
X	float zxm = z00 - z10,  zym = z00 - z01; // falling  differences
X	// fuer Quadrate benutze mittlere Ableitung
X         zxp += zxm; zyp += zym; 
X	//            scalar product n * E
X	rpp[ix][iy]= opaque ? (zxp*ex+zyp*ey+ez)/sqrt(zxp*zxp + zyp*zyp + mu) 
X	                    : - (z00+z01+z10+z11); // prop. z
X	rmax = MAX(rpp[ix][iy], rmax);  // for norming of scalar products
X	rmin = MIN(rpp[ix][iy], rmin);
X      }
X    } 
X    // printf(" %g %g\n",rmin,rmax);
X    for (ix = ixstart+1; ix < ixend; ix++)  
X      for (iy = iystart+1; iy < iyend; iy++)
X	// norming  of scalar prod. s = [rmin..rmax] -> [0..ncolors-1]
X	colors[ix][iy] = (int) ((ncolors-1)*(rpp[ix][iy]-rmin)/(rmax-rmin));
X        // norming in -1..+1 (for normals adapted) :
X	// colors[ix][iy] = (int) ((ncolors-1)*(0.5*rpp[ix][iy] + 0.5));
X	
X  }
X
X  // Determination of parameters of the for-loops, in such a way that 
X  // the drawing always starts at the front edge (towards view-point)        
X  // xs,ys  are the offsets between  ix,iy and the 
X  // index of the scalarprodukt-arrays, which count from 1,1
X  // examples  : ixstart = 0, ixend = 10, 
X  //                	x0   	x1    xe     dx     xs
X  // alpha = 0..90   	0    	1      9      1      0
X  // alpha = -90..0  	9    	8      0     -1      1
X  
X  int x0 = ixstart, x1 = ixstart+1, xe = ixend-1, dx = 1, 
X      xx = ixend-ixstart-1, xs = 0;  
X  int y0 = iystart, y1 = iystart+1, ye = iyend-1, dy = 1, 
X      yy = iyend-iystart-1, ys = 0;
X
X  float xfront = 0, yfront = 0, xback = xspan, yback = yspan, xff, yff;
X  if (sa < 0.) { swap_dir(x0,xe,dx,xfront,xback); x1 = ixend-2; xs = 1; }
X  if (ca < 0.) { swap_dir(y0,ye,dy,yfront,yback); y1 = iyend-2; ys = 1; }
X
X  // draw the x and y axes (front lines)
X  XPoint sff = screen_project(xfront,yfront,0),
X         sbf = screen_project(xback,yfront,0), 
X         sfb = screen_project(xfront,yback,0);
X  cline(sff,sbf,0); // x axis
X  cline(sff,sfb,0); // y axis
X
X  if (rand) { // draw the lines from axes to first grid line
X    for (y = y0, yff = yfront; ; y += dy, yff += dy) {
X      cline(screen_project(xfront,yff,0),scp[x0][y],0);
X      if (y == ye) break;
X    }
X    for (x = x0, xff = xfront; ; x+= dx, xff += dx) {
X      cline(screen_project(xff,yfront,0),scp[x][y0],0);  
X      if (x == xe) break;
X    }
X  }
X
X  if (body) { // draw coloured  faces 
X    for (ix=x1, x=0; x < xx; ix+=dx, x++) 
X      cline(scp[ix][y0],scp[ix-dx][y0],1);
X    // or : fill(scp[ix][y0],scp[ix-dx][y0],1,0); -> without drawing
X    for (iy=y1, y=0; y < yy; iy+=dy, y++)
X      cline(scp[x0][iy],scp[x0][iy-dy],1);
X
X    for (ix=x1, x=0; x < xx; ix+=dx, x++) {
X      for (iy=y1, y=0; y < yy; iy+=dy, y++) { 
X	XPoint p00 = scp[ix][iy], p10 = scp[ix-dx][iy], p01 = scp[ix][iy-dy];
X
X	int color;
X	if (external_colors) color = external_colors[(ix+xs)*ny + iy+ys];
X	else {
X	  int pixr = colors[ix+xs][iy+ys];
X	  color = pal_win->color_cells[pixr].pixel;
X	} 
X	set_color(color);  
X	fill(p00, p10, 0, 1); fill(p00, p01, 0, 1);  
X      }
X    }
X    set_color(black); // reset for gc_copy !  
X  } else {  // usual lattice is drawn
X    for (y = y0; ; y += dy) {
X      for (x = x0; ; x+= dx) { 
X	XPoint sc = scp[x][y];
X	if (x != xe) xline(sc,scp[x+dx][y],1);
X	if (y != ye) xline(sc,scp[x][y+dy],0); 
X	if (x == xe) break;
X      } 
X      if (y == ye) break;
X    }
X  }
X  if (! flat_mode) {
X    XPoint sc00 = screen_project(0,0,0);       // the origin
X    XPoint sczm = screen_project(0,0,zmax); 
X    pline(sc00,sczm);     // z-axis to zmax
X    int i, dzy = sczm.y - sc00.y, nti;  // draw z-ticks with numbers
X    nti = (abs(dzy) > 60) ? 5 : (abs(dzy) / 15 + 1); // number of ticks 
X    for (i=0; i< nti+1; i++) { 
X      float zi = i/float(nti);
X      int x = sc00.x, y = sc00.y + int(zi*dzy); 
X      line(x,y,x-4,y); // z tick
X      char ticks[20]; sprintf(ticks,"%g",zi*zmax/znorm + z0);
X      int xs = (x < width/2) ? x+3 : x - 6*strlen(ticks) - 6; //string Position
X      DrawString(xs,y+5,ticks);
X    }
X  }
X  delete[] y_top; delete[] y_bot;
}
X
SHAR_EOF
chmod 0644 lat_win.c ||
echo 'restore of lat_win.c failed'
Wc_c="`wc -c < 'lat_win.c'`"
test 14496 -eq "$Wc_c" ||
	echo 'lat_win.c: original size 14496, current size' "$Wc_c"
fi
true || echo 'restore of lat_man.c failed'
echo End of part 1, continue with part 2
exit 0


