WIRP

Windows Interface Reduced Programming

WIRP is a library of c routines for simple, platform independent GUI programming. It is made for technical and scientific programmers who need a GUI without learning a new programming language and without having the latest "API of the week". Layout of labels, buttons, sliders, editfields, list-, dropdown- and radioboxes is done by coordinate or automatically by row/column; a simple GUI layout editor is linked into the running programm. Drawing is simple but very efficient through pixmaps.
1998-jul-27, André Köstli, 101.30482@germanynet.de

Platforms

 
Compilers used for testing WIRP
 #define  Platform, compiler
 VGA   DOSX (symantec 7.2  sc -mx -DVGA)
 MSW  MS-Win/16 borland 3.1:  bcc -ml -DMSW -DB16 
 MS-WIN/32 symantec 7.2:  sc -mn -DMSW
 XWI  X-Windows GNU-C:  gcc -DXWI 
 
To compile and link the complete WIRP with a test example for DOS:
sc -mx -DVGA test.c vga.c w.c drw.c dlg.c
takes just two or three seconds; for Windows95/NT, its slower (windows.h ):
sc -mn -DMSW test.c msw.c w.c drw.c gdi32.lib comdlg32.lib
and under Linux it is:
gcc -DXWI -lX11 test.c xwi.c w.c drw.c dlg.c

ToDo


Files

 
WIRP sourcefiles 
 wirp.h   include for all wirp programs 
 vga.h|c  #ifdef VGA , DOS specific code
 msw.h|c  #ifdef MSW,  MS-Windows specific code
 xwi.h|c  #ifdef XWI,  X-Windows specific code
 krn.h  included in vga.h/msw.h/xwi.h
 w.c   most of wirp 
 dlg.c   filedialog (VGA,XWI) 
 drw.c  drawing routines 
 font*.c  fonts
 
 

Function overview

 
Function groups
 *** Initialization, ending and layout
 wc*  window create, opens a new window
 wn*  access window by name
 wp*  access window by pointer
 drw*  drawing to a frame
 w_* Graphics
 *frame*  container for other windows or drawing window
 *button*  push- or togglebutton
 *label*  line of text
 *edit*  editable line of text
 *slider*  numeric input
 *listbox*  several lines of text, scrollable
 *combobox*  choice item with drop down menu
*radiobox* choice item
 
 

Initialization functions

w_init, w_enit, cmain, wloop, wpeek, wcloseall, wlayout, wresource
 

Create funtions

wcframe, wcbutton, wclabel, wcedit, wcslider, wclistbox, wccombobox, wcradiobox, wcmenuadd, wcmenupopup, wcmessagexy, wcpaledit, wfileselect.
These functions open a window, a drop down menu (menuadd), a popup menu (mneupopup), a message box (message), a palette editor (paledit) or a fileselect box.

The functions to open a window (except menu, message, paledit) have a char *par as first parameter.
par describes the window layout as  "name,x,y,w,h,attribute,...", where

Attribute list
 black,blue,green,cyan, 
 red,magenta,brown,white, 
 gray,lightblue,lightgreen, 
 lightcyan,lightred,lightmagenta, 
 yellow,brightwhite
 background colors (text color for label) 
 corespond to the vga colors 
 numbered 0 to 15 where colornumbers used
 value   add value to slider
 check  checkmark button
 verti   vertical slider
 noslider  no slider for listbox
 invert  invert color if button on
 tblack   text black, otherwise brightwhite
 nochange  do not allow editing of window
 tlarge  text large
 listvalues  slider with value list
 frthin   thin border (2 pixel instead of 4) for frame
 saveunder   save pixels under window in pixmap
 nochild   this is not a child window
 modal   dont handle other windows until this one closes
 closemodal   close automatically, if other window has event
 bitmap   button with bitmap
 noframe   no border for frame
 c7tlarge   large text if windowheight > 700
 c5tlarge   large text if windowheight > 500
 
Apparently, there is no defined window tree. Instead, there is an implicit tree defined by opening sequence and coordinates: if within a previous opened frame, this is the parent. A treelist is shown when CTRL-T is hit, A choicelist of level0 windows by CTRL-L.
 

Access functions

wpclose, wnclose, wpdraw, wndraw, wpredraw, wpsetatt, wnsetatt
wphelptext, wnhelptext, wpsettext, wnsettext, wpsliderset, wnsliderset,
wpboxadd, wnboxadd, wpboxdel, wnboxdel, wpboxdelall ,wpcombotxt ,wncomboset
wmenupopxy ,wnmenuset
wntotop, wnsetmodal, wpbitmap, wpclip, wpxyinclient
wfindname, wnfind
wgetevmask, wgetevbutton
wpsetstatuswin, wsetstatustext, wsetsizecallb

These functions get or change properties of windows. Access to windows is by name of a window (wn*) or by a pointer to a Windowst structure (wp*).

When using access by name, nothing happens, if the window does not exist and the pointer returned by the wc* call can be ignored. e.g.

wcframe("frame1","Drawing area",NULL);
drwframename("frame1");
drwlinec(0,20,100,120,_BLACK);
drwupdate();
...
wnclose("frame1");
/* another use of "frame1" would be ignored */
The same example using pointers. Care is to be taken that never a dangling pointer is used.
Windowst *frdrw;
frdrw=wcframe("frame1","Drawing area",NULL);
drwframe(frdrw);
drwlinec(0,20,100,120,_BLACK);
drwupdate();
...
wpclose(frdrw);
/* another use of frdrw (except as in frdrw=wc...) would crash! */
 

Layout editor

The WIRP editor window is opened by pressing CTRL-LeftShift-RightMB while the cursor is over the window to be edited.
 
The Move or Size buttons change position or size of the window in increments given on the slider; the left mousebutton is pressed to fix the new position. 
The Close button ends editing. 
The other buttons toggle window attributes
Pressing RightMB on one of the color buttons opens the palette editor window 
 
On the palette editor window, the first slider shows the color number, the next three sliders show the red, green and blue values. This window can also be opened by a call to wcpaledit. Changes to colors are not immediately visible if hardware palettes are not supported (XWindows with 15, 16 or 24 bit color).
If the window layout is changed by the WIRP editor the par strings of changed windows are written to file *.wrp, where * is the name of the executable. This file is read when the program starts and the layout should be transient. The name of this resource file may be changed by wresource.

Typedefs and constants

Callback functions

typedef void (*Wcallb)(char *name,int ip1,int ip2);
pointer to callback function. A parameter of this type is in most create calls; if it is set NULL, no callback routine is called.
typedef void (Wcallbf)(char *name,int ip1,int ip2);
callback function

name     name of window or text of menuentry
ip1,ip2  depends on windowtype
 
Callback functions
called from on action ip1 ip2
menu lmb up on menuitem
button lmb down+up within button or button status changed (2 state button) button status
slider value changed value=ip1 +ip2/10000.0
edit return-key, cursor-up-key or cursor-down-key
frame depends on mask x coordinate y coordinate
listbox depends on mask row, 1=first column, 1=first
combobox lmb up on item item, 1=first
 

#define yvermenu 17
height of menubar (VGA,XWI), to be subtracted from size of first frame for VGA, choose the size of the first frame as ymax-yyvermenu, e.g. 640x463; the same sizes can then be used for MSW.

Colors

enum {_BLACK=0       , _BLUE          , _GREEN         , _CYAN          ,
      _RED           , _MAGENTA       , _BROWN         , _WHITE         ,
      _GRAY          , _LIGHTBLUE     , _LIGHTGREEN    , _LIGHTCYAN     ,
      _LIGHTRED      , _LIGHTMAGENTA  , _YELLOW        , _BRIGHTWHITE  };
The 16 colornumbers.

Window structure

The following structures should normally not be seen by the WIRP user:
struct windowst{ void *next,*child,*ptr,*helptext; char *name; Pixel *save; 
   void (*draw)(struct windowst*);int (*hit)(struct windowst*,Evstack *); 
                 short x,y,w,h,stat,att,mask;char typ,col; };  /* Windowst;*/ 
typedef struct windowst Windowst;
basic structure for each window, has one of the following types.
Window types
#define (in w.c) windowst.ptr -> type
W_SLIDER 1 Sliderst slider
W_BUTTON 2 Buttonst button
W_FRAME  4 Framest frame
W_LABEL  8 Labelst label, edit
W_LIBOX 16 Liboxst listbox, combobox, (menu(VGA,XWI))
typedef struct { Windowst *win; double fa,fe,finc,fcur,flast,fpage,*flist; 
                 double *fres;Wcallb callb;}                     Sliderst; 
typedef struct { Windowst *win; char *text; 
                 int *ires;Wcallb callb;}                        Buttonst; 
typedef struct { Windowst *win; char *text; void *data; int cx,cy,cw,ch,ndata; 
                           Wcallb callb;}                        Framest; 
typedef struct { Windowst *win; char *text; void *data; int cx,cy,cw,ch,ndata 
               ,hili,rad; Wcallb *cbl;Wcallb callb;}             Liboxst; 
typedef struct { Windowst *win; char *text; int n,ic; 
                           Wcallb callb; }                       Labelst;

Event mask

The following constants are needed, if event values is asked by wgetevmask or if an event mask bit is added to windowst.mask
enum { MM_MOVE=1,MM_LMBDOWN=2,MM_LMBUP=4,MM_RMBDOWN=8,MM_RMBUP=16, 
                 MM_MMBDOWN=32,MM_MMBUP=64, 
       key_mask=128,tim_mask=256, 
       leave_mask=512,size_mask=1024,paint_mask=2048,close_mask=4096, 
       menu_mask=8192,menuselect_mask=16384};
event mask
   not all events available in every version,
   e..g. XWI has no timer (tim_mask), so far
 

The following constants are needed, if event values is asked by wgetevbutton

enum { LMB_DOWN=1,RMB_DOWN=2,MMB_DOWN=4, 
       KEY_RSH=256,KEY_LSH=512,KEY_CTRL=1024,KEY_ALT=2048}; 
enum scancodes { key_F1=359,key_home=371,key_up,key_pgup,key_left=375, 
       key_right=377,key_end=379,key_down,key_pgdn,key_ins,key_del };
event button
   status of mouse buttons and special keys or
   ascii code or one of the above "scancodes", if mask==key_mask
 

Pixmaps

typedef unsigned char Pixel;
Type of pixmaps. A Pixel is a value of 0..255, where 0..15 are the vga colors (see attributes), and 16..144 are predefined as a 128 grayscale lut. This color palette can be changed.

If pixmaps are given as parameters to wcbutton and wpbitmap, hex characters are expected, each hex digit (0..0xf) defines one pixel. The program bmp2wpm can be used to produce such c code from Windows BMP files.

long vga_rgb[16] (or  msw_rgb[16], xwi_rgb[16])
the rgb values of the first 16 colors (==VGA palette)

Menus

enum { Cswitchon='û',Cswitchoff='ú',Cmultiswoff=' ',Cmultiswon=' ' };
First char in menutext for switching menues, see also wnmenuset
switch is for on/off menuentries,
multisw for choice groups of menuentries.

Mode parameters

enum {PUTmode=0,XORmode,SNZmode}; 
#define SNZzero 255
drawing modes
SNZmode means do not draw if pixel==SNZzero
 

font parameters

enum {vga_6x8font=1,vga_8x8font=2,vga_8x14font=3};
#define w_mediofont vga_8x8font
#define w_smallfont vga_6x8font
#define w_largefont vga_8x14font
#define w_smallfont2 4 // 12x16 (6x8 doubled)
#define w_largefont2 5 // 16x28 (8x14 doubled)

Functions

Windowst* wcframe(char *par,char *text,Wcallb callb) ;
frame, may be used as container (windows within it are moved, when frame moves) or as drawable (see drw* functions)
callb gets x,y coord relative to frame in ip1,ip2
text = title, use "" for no title; if NULL, par(name) is used
void wcmessagexy(int x,int y,char *s);
Messagebox, several lines in s separated by "\n"
void wlayout(char *str,int nr,int dist);
Layout strategie for the next opened windows
str="row","column"  nr windows in one row/col with distance dist
      "shift","set"   x(+)=nr, y(+)=dist
void wpclose(Windowst *we);
void wnclose(char *name);
close window
void wcloseall(void);
close all windows
Windowst * wcmenuadd(char *s,Wcallb *mcb);
Windowst * wcmenupopup(char *s,Wcallb *mcb);
add a menu to menubar or at pointer(popup),
s  = menuname,entries, separated by ",", a helptext is sep by "|"
mcb= list of callback functs
void wmenupopxy(int x,int y);
Make popup menus appear at x,y; if x=y=0, popup menus appear at cursor position (default);
void wnmenuset(char *name,int row,char *p);
In menu name entry number row is set depending on the text in p:
"on", "off": Has a "chosen" switch or not.
"active", "inactive": inactive means not selectable
Windowst* wclabel(char *par,char *text);
simple textlabel, text is copied
Windowst* wcedit(char *par,char *text,int n,Wcallb callb);
editable text, n=max.length of text,
CARE:text is NOT copied (MUST be static)
void wpsettext(Windowst *win,char *ch);
void wnsettext(char *name,char *ch);
changes text of label to ch
Windowst* wcbutton(char *par,char *text,int *ires,Wcallb callb);
text: button text (copied)
if bitmap attribute: text -> pixmap, if bitmap and text==NULL, an pixmap is created and can be changed in the layouteditor.
if ires!=NULL it is a 2-state button (ires=0|1, MUST be static or global!), if ires!=NULL and attribute check given, a checkmark button is drawn.
void wpbitmap(Windowst *wb,char *bm);
add WIRP hex bitmap to bitmap button
Windowst* wcslider(char *par,double *fli,double *fres,Wcallb callb);
create slider, fli[] contains:
if listval attribute: fli[0]=number of values, [1]..[fli[0]]=values
else: start, end, increment, page-increment (may be zero=jump to hit)
fres: if fres!=NULL contains actual value (MUST be static or global!)
void wpsliderset(Windowst *win,double val);
void wnsliderset(char *name,double val);
change slider value, does NOT call callb function
Windowst *wclistbox(char *par,char *text,int ntext,char **ptext,Wcallb callb);
Windowst *wccombobox(char *par,char *text,int ntext,char **ptext,Wcallb callb);
Windowst *wcradiobox(char *par,char *text,int ntext,int an,char **ptext,Wcallb callb);
list/dropdown/radiobox, ptext contains ntext pointers to textlines (copied)
radiobox has number an as activated entry
callb gets linenr in ip1, column in ip2
void wpboxadd(Windowst *w,char *text,int line);
void wnboxadd(char *name,char *text,int line);
add text after line (=0 at begin,=very large at end)
void wpboxdel(Windowst *w,int line);
void wnboxdel(char *name,int line);
delete line (very large: last)
void wpboxdelall(Windowst *w);
delete all lines
char *wpcombotxt(Windowst *win,int i);
get pointer to textline i
void wncomboset(char *name,int val);
set combobox to text at line val
int wequtxt(char *s1,char *s2);
Compare textstrings
char *wmktext(char *ch);
Returns pointer to copy of ch
int wpxyinclient(Windowst *frw,int *xp,int *yp);
return 1 if xp,yp in client area of window frw and reduce xp,yp to client
int wloop(void);
handles one WIRP event,
returns 0 if no window open, >0 for key entered (==asci code), <0 for other event
int wpeek(void);
handles one event, similar to wloop, but returns 0, if no event pending
void wpredraw(Windowst *wp);
redraw everything whithin wp; only x,y,w,h of wp is used
  
Windowst *wnfind(char *name);
find window by name and return pointer or NULL if not found
Windowst *wfindname(Windowst *wr,char *name);
find window by name, start with root if wr==NULL
void wpdraw(Windowst *wp);
void wndraw(char *name);
draw window
int wgetevmask(void);
get eventmask of last event
int wgetevbutton(void);
get button status of last event
void wresource(char *filename);
use file filename as WIRP resourcefile, internally appending ".wrp" to filename, if its not already there. The default is the name of the executable (with ".EXE" stripped for DOS/WIN) with ".WRP" appended. If the layout edior is used, the resource file is written to.
void wpsetstatuswin(Windowst *w);
use window w as status and helptext window
void wsetstatustext(char *t);
write text to status window
void wphelptext(Windowst *w,char *t);
void wnhelptext(char *n,char *t);
add helptext to window
void wsetsizecallb(Wcallb cb);
Set a callback routine to be called when the maximize button is hit (MSW). The new window size is in w_mx, w_my;
int wpsetatt(Windowst *w,char *att);
int wnsetatt(char *n,char *att);
Set attribute att for window.
In addition, window can be set "visible" and "invisible".
void wpclip(Windowst *ws);
Set clipping to the x,y,w,h values of ws. ws=NULL means no clipping. Useful when using the w_* routines for direct drawing.
void wntotop(char *name);
Make window the top (most visible) window.
void wnsetmodal(char *name);
Make window modal, i.e. only this winow gets events.
 

Special functions

int cmain(int argc,char **argv);
Pseudo main programm, this is because MSW does not allow a "main"
char *wfileselect(char *mask,char *direct,char *title);
fileselectbox, uses Win-API dialog if MSW defined; for VGA and XWI the code in dlg.c is used.
mask=filemask e.g. "textfiles (*.txt)|all files (*.*)"
direct=directory e.g. "."
title= text for title

Drawing routines

All x,y, coordinates are relative to the actual drawable (AD).
Pixel * drwframe(Windowst *frwp);
Pixel * drwframename(char *name);
select frame as drawable, returns pointer to pixmap or NULL if no success
void drwupdate(void);
update (copy pixmap to frame) actual drawable (AD)
void drwupdatew(Windowst *frw);
update frame frw
void drwclose(Windowst *frwp);
Release drawing pixmap
void drwclear(void);
fill AD whith background color
int drwsetmode(int mode);
set drawmode (PUTmode,XORmode)
void drwgetwh(int *w,int *h);
get width,height of AD
void drwlinec(int x1,int y1,int x2,int y2,int col);
int drwpixel(int x,int y,int col);
void drwsetbox(int xp,int yp,int wp,int hp,int col);
draw line, pixel, filled box whith color col
void drwputbox(int xp,int yp,int wp,int hp,Pixel *p);
void drwgetbox(int xp,int yp,int wp,int hp,Pixel *p);
pixel transfer from or to pixmap p
void drwzbuf(void);
adds zbuffer to AD
int drwfilledpol(int n,int x[],int y[],Pixel d[],Pixel c[]);
draw filled polygon of n points, c=color (interpolated)
d=distance (interpolated), only useful if drwzbuf was called
void drwlinelc(int x1,int y1,int c1,int x2,int y2,int c2);
draw line whith color interpolated from c1 to c2
int drwfont(int n,int color,int bcolor);
chose textfont n, color and background color
if color==bcolor dont draw background
returns font_width+(font_height<<5)
void drwtext(int x,int y,char *s);
x,y=left upper corner, s=text
void drwprint(int mode);
Simple hardcopy, writes AD to file LPT1 for graphics printing .
Works for DOS only.
mode==1: 8 pin printer
mode==2: 24 pin printer
 
int drwprintini(double spixpmm,double *xpixpmm,double *ypixpmm);
Prining initialization, for MSW only. For the size of the print, the current AD frame is used. All following drw output goes to the printer, until drwupdate is called. I.e. the AD is not copied to the printer, but the drawing has to be done again reflecting the (usually much smaller) pixelsize of the printer. For texts, w_largefont2 should probably be used to be readable at 300dpi.
spixpmm: assumed number of pixel per [mm] on screen, 3 is a reasonable value.
returns: 0: Initialization failed; 1: ok.
xpixpmm: pixel per [mm] on printer in x direction
ypixpmm: pixel per [mm] on printer in y direction
 

Graphics functions

These names in vga.h,msw.h,xwi.h define the interface to the platform specific part of WIRP.

The w_* names in these include files are #defined to vga_*, msw_* and
xwi_* functions, respectively.

If directdrawing (i.e. without pixmap as in the drw* functions) is wanted, these routines may be used. For a WIRP user, this seems not to be necessary.

void w_init(void);
initialisation call, called before entering cmain
void w_enit(void);
finitialisation call, called after leaving cmain
void w_setmode(int m);
set drawing mode
int w_getmode(void);
get actual drawing mode
void w_setcur(int on);
Cursor on (on!=0) or off.
void w_selectcur(int n);
Select cursor (currently VGA only)
n==1: Normal pointer
n==2: Cross
void w_drawpixel(unsigned int x,unsigned int y,Pixel c);
Pixel w_readpixel(unsigned int x,unsigned int y);
void w_putzei(int y,int x,int n,Pixel *c);
void w_getzei(int y,int x,int n,Pixel *c);
void w_putbox(int x,int y,int w,int h,Pixel *pix);
void w_getbox(int x,int y,int w,int h,Pixel *pix);
void w_alleszu(Pixel c);
void w_rect(int x1,int y1,int x2,int y2,int f);
void w_fillrect(int x1,int y1,int x2,int y2,int f);
void w_horli(int y,int x1,int x2,Pixel c);
void w_drawline(int x1, int y1, int x2, int y2,Pixel c);
void w_drawlinb(int x1, int y1, int x2, int y2,Pixel c);
int w_font(int n,int color,int bcolor);
void w_text(int x,int y,char *s);
void w_drwcur(void);
int w_getmes(Evstack *ev,int warte);
void w_wartsync(int n);

Palette handling

void wcpaledit(int col,int x,int y);
palette editor dialog, used in the layout editor
void w_setpal(int ix,int red,int green,int blue);
void w_getpal(int ix,int *red,int *green,int *blue);
Set or get color value ix (0<=ix<=255).
void w_setallpal(unsigned char *rgb);
void w_getallpal(unsigned char *rgb);
Set or get all 255 colors.
 


Examples

 
The simplest WIRP program looks like: 
 #include <stdio.h> 
 #include "wirp.h" 
 int cmain(int argc,char **argv) {  
  wcframe("f0,0,0,600,400","Hello world",NULL); 
  while (wloop()!=27) ; /* wait until esc key hit */ 
  wcloseall();
  return 0; 
 }
 
 
With a "stop" button: 
 #include <stdio.h>  
 #include "wirp.h"  
 int cmain(int argc,char **argv) {  
  static int istop; 
  wcframe("f0,0,0,120,60,white,tlarge","Hello world",NULL);  
  wcbutton("Stopbutton,red,tlarge",NULL,&istop,NULL);  
  while (!istop) wloop(); /* wait until stop */  
  wcloseall();  
  return 0;  
 } 
 
"stop" button with callback:
 #include <stdio.h> 
 #include "wirp.h" 
 static void bcbstop(char *m,int i,int j) { 
   wcloseall(); 
 } 
 int cmain(int argc,char **argv) {  
  wcframe("f0,0,0,600,400",argv[0],NULL); 
  wcbutton("btn1,red,tlarge","STOP",NULL,bcbstop); 
  while (wloop()) ; /* wait until wcloseall */ 
  return 0; 
 }
FORTRAN example, please note that (if your compiler does not extend the syntax to allow zero terminated strings and value parameters)
      subroutine cmain()
      integer wloop
      external bcbstop
      character c0
      c0=char(0)
      call wcframe('f0,0,0,120,60,white,tlarge'//c0,'Hello world'//c0,
     +             bcbstop)
      call wcbutton('Stopbutton,red,tlarge'//c0,'stop'//c0,ires,bcbstop)
 1    if (wloop().ne.0) goto 1
      end
      subroutine bcbstop(nam,ip1,ip2)
      call wcloseall()
      end
This was compiled with the FORTRAN to c converter and Symantec c for DOS
f2c ex.f
sc -mx -DVGA -HIf2cwirp.h -I\f2c ex.c w.obj vga.obj drw.obj \f2c\f2c.lib
The file f2cwirp contains (vga_ is to be edited to msw_ for Win or xwi_ for X-Win):
#define wcloseall_ wcloseall
#define wloop_ wloop
#define cmain_ cmain
#define wcbutton_ wcbutton
#define wcframe_ wcframe
 
    Creating and editing a lookup table 
#include <math.h>
#include <stdio.h>
#include <string.h>

#include "wirp.h"

static int lutsiz=0,nlut=16,r[256],g[256],b[256];
static char fileread[120]="\0";

static void opnfrm(void) {
 wcframe("drawing,20,16,260,132,white,frthin","",NULL);
}

static void drwlut(void) {
 int i,j,mi,mj,x=0,y=0,w,h,ww,hh,c=16;
 drwgetwh(&ww,&hh);
 switch (lutsiz) {
 case 1: mi=1;mj=nlut;w=ww/mj;h=hh; break;
 case 2: mi=8;mj=8   ;w=ww/mj;h=hh/mi; break;
 case 3: mi=8;mj=16  ;w=ww/mj;h=hh/mi; break;
 case 4: mi=16;mj=16 ;w=ww/mj;h=hh/mi; break;
 default: return;
 }
 for (i=0;i<nlut;i++) w_setpal(c++,r[i],g[i],b[i]);
 c=16;
 drwframename("drawing");
 for (i=0;i<mi;i++) {
  x=0;
  for (j=0;j<mj;j++) {
   if (c-16>=nlut) break;
   drwsetbox(x,y,w,h,c++);
   x+=w;
  }
  y+=h;
 }
 drwupdate();
}

static double ergb,er,eg,eb;

static void editcb(char *sn,int ip1,int ip2) {
 int r,g,b;
 w_getpal(ergb+16,&r,&g,&b);
 er=r;eg=g;eb=b;
 wnsliderset("sre",er);
 wnsliderset("sge",eg);
 wnsliderset("sbe",eb);
}

static void edit1cb(char *sn,int ip1,int ip2) {
 w_setpal(ergb+16,er,eg,eb);
}

static void openedit(void) {
 int i;
 double slv1[]={0.0,255.0,1.0,0.0};
 double slv2[]={0.0,255.0,1.0,0.0};
 Windowst *sl;
 er=eg=eb=ergb=0;
 slv1[1]=nlut-1;
 wcframe( "fre,50,160,120,140,white,tlarge","Edit color",NULL);
 wcslider("sne,60,190,100,white,value,tlarge",slv1,&ergb,editcb);
 wcslider("sre,60,215,100,red,value,tlarge",  slv2,&er,edit1cb);
 wcslider("sge,60,240,100,green,value,tlarge",slv2,&eg,edit1cb);
 wcslider("sbe,60,265,100,blue,value,tlarge", slv2,&eb,edit1cb);
 editcb("",0,0);
}

static void helplbcb(char *n,int i,int j) {
 wnclose("helplibo");
}

static char *text[]= {
  "Use File,Open to read",
  " an existing lookuptable.",
  " ",
  " Lookuptable files consist of",
  " one line per color with ",
  "   index red green blue ",
  " where all values must be",
  " within 0..255. ",
  " ",
  "Use File,New to create",
  " a new lookuptable. ",
  " ",
  " Then select from the popup menu",
  " the size of the table, ",
  " possible values are",
  " 16, 64, 128, 236;",
  " the last not beeing 256",
  " to leave some background colors.",
  " Note that in SVGA cards the",
  " palette can only handle 6 bit ",
  " per color, so more than 64 values",
  " for a grey-lut is useless.",
  " ",
  " A default LUT with greyvalues",
  " is created and some sliders ",
  " allow editing. The LUT may be",
  " divided into sections (default 1) ",
  " and each section has a start and",
  " end rgbvalue, start may be  ",
  " higher than end.",
  " ",
  " After pressing Ok, single color",
  " entries may be changed.",
  " ",
  "Use File,Save to write",
  " the LUT to a file. ",
  " ",
  " CARE: there is no warning",
  " when overwriting a file!",
  " "};
static void mcbhelp1(char *menitem,int ip1,int ip2) {
 Windowst *lb;
 lb=wclistbox(
     "helplibo,0,0,295,360,closemodal,white,tblack,tlarge",
     "", sizeof(text)/sizeof(char *),text,helplbcb);
 lb->mask|=MM_LMBUP;
}

static void mcbstop(char *menitem,int ip1,int ip2) {
  wcloseall();
}

static void mcbabout(char *menitem,int ip1,int ip2) {
  wcmessagexy(4,4,
  "  LookupTable Editor  \n"
  "Graphics library WIRP \n"
  "       A.Köstli       \n"
  " Stuttgart, 1996,1997 ");
}

static void mcbread(char *menitem,int ip1,int ip2) {
 char *f;
 wnclose("frs");
 wnclose("fre");
 wnclose("drawing");
 f=wfileselect(
  "Lookup (*.lut)|All (*.*)",
  ".",menitem);
 if (f && strcmp(f,"") ) {
  int i,m=0,l=0,cr,cg,cb;
  char ch[81];
  FILE *fi=fopen(f,"r");
  if (fi==NULL) {
   wcmessagexy(20,100,"Could not open file for reading!");
  } else {
   strcpy(fileread,f);
   for (i=0;i<256;i++) r[i]=g[i]=b[i]=0;
   while (!feof(fi)) {
    fgets(ch,80,fi);
    if (feof(fi)) break;
    l++;
    sscanf(ch,"%d %d %d %d",&i,&cr,&cg,&cb);
    if (i>=0 && i<256) {
     r[i]=cr; g[i]=cg; b[i]=cb;
     if (i>m) m=i;
    } else {
     sprintf(ch,"Error in %s at line %d",f,l);
     wcmessagexy(20,100,ch);
     break;
    }
   }
   fclose(fi);
   nlut=m+1;
   if (m>128)     lutsiz=4;
   else if (m>64) lutsiz=3;
   else if (m>16) lutsiz=2;
   else           lutsiz=1;
   opnfrm();
   drwlut();
   openedit();
  }
 }
}

static void mcbwrite(char *menitem,int ip1,int ip2) {
 FILE *fi;
 char *f;
 f=wfileselect(
  "Lookup (*.lut)|All (*.*)",
  ".",menitem);
 strcpy(fileread,f);
 if (strlen(fileread)) {
  int i,cr,cg,cb;
  fi=fopen(fileread,"w");
  if (fi==NULL) {
   wcmessagexy(20,100,"Could not open file for writing!");
  } else {
   for (i=0;i<nlut;i++) {
    w_getpal(i+16,&cr,&cg,&cb);
    fprintf(fi,"%d %d %d %d\n",i,cr,cg,cb);
   }
   fclose(fi);
  }
 }
}

static void mcbnew(char *menitem,int ip1,int ip2) ;

static void buttoncb(char *n,int ip1,int ip2) {
 wnclose("frs");
 openedit();
}

static double nrgbs=1,irgbs=1,r1,r3,g1,g3,b1,b3;
static double r1s[8],r3s[8],g1s[8],g3s[8],b1s[8],b3s[8];

static void slcb(char *ns,int ip1,int ip2) {
 int i,ia=0,is=0,nluts;
 i=irgbs;
 r1s[i-1]=r1; r3s[i-1]=r3;
 g1s[i-1]=g1; g3s[i-1]=g3;
 b1s[i-1]=b1; b3s[i-1]=b3;
 nluts=nlut/nrgbs;
 for (i=nlut;i<256;i++) r[i]=g[i]=b[i]=0;
 for (i=0;i<nlut;i++) {
  if (is<nrgbs-1 && i>=(is+1)*nluts) {
   is++; ia=i;
   if (is==nrgbs-1) nluts=nlut-nluts*is;
  }
  r[i]=r1s[is]+(r3s[is]-r1s[is])/(nluts-1)*(i-ia);
  g[i]=g1s[is]+(g3s[is]-g1s[is])/(nluts-1)*(i-ia);
  b[i]=b1s[is]+(b3s[is]-b1s[is])/(nluts-1)*(i-ia);
 }
 drwlut();
}

static void slscb(char *sn,int ip1,int ip2) {
 int i=irgbs;
 if (irgbs>nrgbs) {
  nrgbs=irgbs;
  r1s[i-1]=r1; r3s[i-1]=r3;
  g1s[i-1]=g1; g3s[i-1]=g3;
  b1s[i-1]=b1; b3s[i-1]=b3;
 } else {
  r1=r1s[i-1]; r3=r3s[i-1];
  g1=g1s[i-1]; g3=g3s[i-1];
  b1=b1s[i-1]; b3=b3s[i-1];
 }
 wnsliderset("sr1",r1);
 wnsliderset("sg1",g1);
 wnsliderset("sb1",b1);
 wnsliderset("sr3",r3);
 wnsliderset("sg3",g3);
 wnsliderset("sb3",b3);
 slcb("",0,0);
}

static void mcbform1(char *menitem,int ip1,int ip2) {
 int i;
 double slv1[]={0.0,15.0,1.0,0.0};
 double slvs[]={1.0, 8.0,1.0,0.0};
 Windowst *sl;
 switch(ip1) {
 case 1: lutsiz=1; nlut=16; break;
 case 2: lutsiz=2; nlut=64; break;
 case 3: lutsiz=3; nlut=128; break;
 case 4: lutsiz=4; nlut=236; break;
 }
 opnfrm();
 irgbs=nrgbs=1;
 r3=g3=b3=slv1[1]=255;
 r1=g1=b1=0;
 wcframe( "frs,010,160,280,220,white,tlarge,frthin",
                                     "Create Lookuptable",NULL);
 wclabel( "st1,110,186,80,black,tlarge","Section");
 wcslider("srs,110,200,80,white,value,tlarge",slvs,&irgbs,slscb);
 wclabel( "st2,030,226,100,black,tlarge","Start color");
 wclabel( "st3,170,226,100,black,tlarge","End color");
 wcslider("sr1,030,240,100,red,value,tlarge",  slv1,&r1,slcb);
 wcslider("sr3,170,240,100,red,value,tlarge",  slv1,&r3,slcb);
 wcslider("sg1,030,270,100,green,value,tlarge",slv1,&g1,slcb);
 wcslider("sg3,170,270,100,green,value,tlarge",slv1,&g3,slcb);
 wcslider("sb1,030,300,100,blue,value,tlarge", slv1,&b1,slcb);
 wcslider("sb3,170,300,100,blue,value,tlarge", slv1,&b3,slcb);
 wcbutton("Ok,110,330,80,30,white,tlarge",NULL,NULL,buttoncb);
 slcb("",0,0);
}

static char *mefile="File ,New ,Open ,Save ,ÄÄÄÄÄ,Exit ";
static char *mehelp="Help ,Help ,ÍÍÍÍÍÍ,About ";
static char *meform="LUTcolors,  16,  64,  128,  236,";

static Wcallb mcbfile[]={mcbnew,mcbread,mcbwrite,NULL,mcbstop };
static Wcallb mcbhelp[]={mcbhelp1,NULL,mcbabout };
static Wcallb mcbform[]=
                    {mcbform1,mcbform1,mcbform1,mcbform1,NULL };

static void mcbnew(char *menitem,int ip1,int ip2) {
 int i=1; char *m=meform;
 while ((m=strchr(m,','))!=NULL && *(++m)!=0)
  if (i++==lutsiz) *m=Cmultiswon;
  else             *m=Cmultiswoff;
 wnclose("drawing");
 wnclose("frs");
 wnclose("fre");
 wcmenupopup(meform,mcbform);
}

int cmain(int argc,char **argv) {
 int i;
 wcframe("f0,0,0,300,400,cyan,noframe","",NULL);

 wcmenuadd(mefile,mcbfile);
 wcmenuadd(mehelp,mcbhelp);

 do {
  i=wloop();
  switch (i) {
  case 3 : /* CTRL-C */ wcloseall(); break;
  case 27: wnclose("helplibo"); wnclose("f_w_message");
  /* ESC */ wnclose("menuLUTcolors"); break;
  }
 } while (i);
}