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


//-----------------------------------------------------------------------------

//

// basic graphics routines for OS/2  (PM)

//

// S. Naeher 1995,1996

//-----------------------------------------------------------------------------



#include <LEDA/impl/x_basic.h>



#include <string.h>

#include <stdio.h>

#include <stdlib.h>

#include <math.h>



#define INCL_WIN

#define INCL_GPI

#include <os2.h>



#define LEDA_ID         1



#define IDM_FILE        1

#define IDM_EXIT        2

#define IDM_FONT        3



#define TEXT_FONT_ID    1

#define BOLD_FONT_ID    2

#define FIXED_FONT_ID   3

#define USER_FONT_ID    4





typedef int Window;



typedef void (*redraw_fct)(void*);



struct os2_win 

{

  HWND hwndFrame;

  HWND hwnd;

  HPS  hps;

  int  bg_col;

  int  width;

  int  height;

  int  iconized;

  int  mapped;



  char* header;



  FONTMETRICS fm;



  int          COLOR;

  int          LWIDTH;

  int          JSTYLE;

  line_style   LSTYLE;

  text_mode    TMODE;

  drawing_mode MODE;

  

  void* inf;

  

  redraw_fct redraw;

};





#define YCOORD(w,ypix)  (wlist[w].height - ypix -1)





// global data



static HAB hab = 0;

static HMQ hmq = 0;



static SIZEL sizel = {0,0};

static DEVOPENSTRUC dop = {NULL,(PSZ)"DISPLAY",NULL,NULL,NULL,NULL,NULL,NULL,NULL};



static FATTRS TextFattrs;

static FATTRS BoldFattrs;

static FATTRS MesgFattrs;



struct event {

  int win;

  int kind;

  int val;

  int x;

  int y;

  unsigned long t;

};



static event cur_event;





#define  MAX_WIN 32



static os2_win wlist[MAX_WIN+1];

static Window wcount = 0;



static LONG  rgb_table[32];

static long  mode_table[4];

static long  lstyle_table[4];



static int shift_key_down = 0;

static int ctrl_key_down = 0;

static int alt_key_down = 0;





/* display */



inline void message(char* s)

{ WinAlarm( HWND_DESKTOP, WA_ERROR );

  WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, (PSZ) s, 

                 (PSZ)"LEDA WINDOW MESSAGE", 256, MB_OK);

} 



inline void message(char* s, int i)

{ WinAlarm( HWND_DESKTOP, WA_ERROR );

  char msg[256];

  sprintf(msg,s,i);

  WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, (PSZ) msg, 

                (PSZ)"LEDA WINDOW MESSAGE", 256, MB_OK);

} 



inline void message(char* s, int i, int j)

{ WinAlarm( HWND_DESKTOP, WA_ERROR );

  char msg[256];

  sprintf(msg,s,i,j);

  WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, (PSZ) msg, 

                (PSZ)"LEDA WINDOW MESSAGE", 256, MB_OK);

} 







#define LONGFromRGB(R,G,B) (LONG)(((LONG)R<<16)+((LONG)G<<8)+(LONG)B)



inline void set_rgb_table(int i, 

                          unsigned char r, unsigned char g, unsigned char b)

{ rgb_table[2*i] = i;

  rgb_table[2*i+1] = LONGFromRGB(r,g,b);

 }



static void init_palette(HWND hwnd,HPS hps)

{ 

  set_rgb_table(white, 255,255,255);

  set_rgb_table(black,   0,  0,  0);

  set_rgb_table(red,   255,  0,  0);

  set_rgb_table(green,  32,255,  0);

  set_rgb_table(blue,    0,  0,213);

  set_rgb_table(yellow,255,255,  0);

  set_rgb_table(violet,160,  0,208);

  set_rgb_table(orange,255,160,  0);

  set_rgb_table(cyan,    0,192,192);

  set_rgb_table(brown, 192,112, 56);

  set_rgb_table(pink,  255,  0,255);

  set_rgb_table(green2,  0,160,100);

  set_rgb_table(blue2,   0,128,255);

  set_rgb_table(grey1, 212,212,212);

  set_rgb_table(grey2, 180,180,180);

  set_rgb_table(grey3, 116,116,116);



  if (!GpiCreateLogColorTable(hps,LCOL_PURECOLOR,LCOLF_INDRGB,0,32,rgb_table))

     message("LEDA: cannot create color table");

}







static void font_dialog(HWND hwnd, PFONTMETRICS fm)

{ 

  FONTDLG FontDlg;

  char szFamilyname[FACESIZE];

  szFamilyname[0] = 0;

  memset((PCH)&FontDlg,0,sizeof(FONTDLG));

  FontDlg.cbSize         = sizeof(FONTDLG);

  FontDlg.hpsScreen      = WinGetPS(hwnd);

  FontDlg.pszFamilyname  = (PSZ)szFamilyname;

  FontDlg.usFamilyBufLen = FACESIZE;

  FontDlg.pszPreview     = (PSZ)"Sample Text";

  FontDlg.fl             = FNTS_RESETBUTTON | FNTS_CENTER |

                           FNTS_INITFROMFATTRS | FNTS_BITMAPONLY;

  FontDlg.flStyle        = FATTR_SEL_ITALIC;

  FontDlg.clrFore        = CLR_BLACK;

  FontDlg.clrBack        = CLR_PALEGRAY;

  FontDlg.fAttrs         = TextFattrs;

  FontDlg.pszTitle       = (PSZ)"FONT SELECTION";

  

  WinFontDlg(HWND_DESKTOP,hwnd,(PFONTDLG)&FontDlg);



  if (FontDlg.lReturn == DID_OK)

  {  char msg[256];

     TextFattrs = FontDlg.fAttrs;

     sprintf(msg,"Facename = %s  MaxBaseLinExt = %d CharWidth = %d", 

             TextFattrs.szFacename,

             TextFattrs.lMaxBaselineExt,

             TextFattrs.lAveCharWidth);

     message(msg);

     GpiCreateLogFont(FontDlg.hpsScreen,(PSTR8)NULL,TEXT_FONT_ID,&TextFattrs);

     GpiSetCharSet(FontDlg.hpsScreen,TEXT_FONT_ID);

     GpiQueryFontMetrics(FontDlg.hpsScreen,sizeof(FONTMETRICS),fm);

   }



  WinReleasePS(FontDlg.hpsScreen);

}







static MRESULT EXPENTRY ClientWndProc (HWND hwnd, ULONG msg,

                                       MPARAM mp1, MPARAM mp2)

{

  int w;



  for(w = 1; w<=wcount; w++)

     if (wlist[w].hwnd == hwnd) break;



  cur_event.win = w;



  switch (msg) {



  case WM_SIZE:

        { wlist[w].width = SHORT1FROMMP(mp2);

          wlist[w].height = SHORT2FROMMP(mp2);

          return ((MRESULT)0);

         }



  case WM_ERASEBACKGROUND:

          return (MRFROMLONG(1L));



  case WM_PAINT: 

        { RECTL rcl;

          WinQueryUpdateRect(hwnd,&rcl);

          cur_event.kind = exposure_event;

          cur_event.x =   rcl.xLeft;

          cur_event.y =   YCOORD(w,rcl.yTop);

          cur_event.val = rcl.xRight - rcl.xLeft + 1;

          cur_event.t =   (unsigned long)(rcl.yTop - rcl.yBottom + 1);

          WinValidateRect(hwnd,&rcl,FALSE);

          return ((MRESULT)0);

         }



  case WM_QUIT: 

  case WM_CLOSE: 

         cur_event.kind = destroy_event;

         x_close_display();

         exit(0);



  case WM_BUTTON1DBLCLK: 

  case WM_BUTTON1DOWN: 

         cur_event.kind = button_press_event;

         cur_event.val = 1;

         cur_event.x = SHORT1FROMMP(mp1);

         cur_event.y = YCOORD(w,SHORT2FROMMP(mp1));

         if (ctrl_key_down)  cur_event.val = 2;

         if (shift_key_down) cur_event.val |= 256;

         break;



  case WM_BUTTON2DBLCLK: 

  case WM_BUTTON2DOWN: 

         cur_event.kind = button_press_event;

         cur_event.val = 3;

         cur_event.x = SHORT1FROMMP(mp1);

         cur_event.y = YCOORD(w,SHORT2FROMMP(mp1));

         if (ctrl_key_down)  cur_event.val = 2;

         if (shift_key_down) cur_event.val |= 256;

         break;





  case WM_BUTTON1UP: 

         cur_event.kind = button_release_event;

         cur_event.val = 1;

         cur_event.x = SHORT1FROMMP(mp1);

         cur_event.y = YCOORD(w,SHORT2FROMMP(mp1));

         if (ctrl_key_down)  cur_event.val = 2;

         if (shift_key_down) cur_event.val |= 256;

         break;



  case WM_BUTTON2UP: 

         cur_event.kind = button_release_event;

         cur_event.val = 3;

         cur_event.x = SHORT1FROMMP(mp1);

         cur_event.y = YCOORD(w,SHORT2FROMMP(mp1));

         if (ctrl_key_down)  cur_event.val = 2;

         if (shift_key_down) cur_event.val |= 256;

         break;





  case WM_MOUSEMOVE: 

         cur_event.kind = motion_event;

         cur_event.x = SHORT1FROMMP(mp1);

         cur_event.y = YCOORD(w,SHORT2FROMMP(mp1));

         break;





  case WM_CHAR: 

        { USHORT fsKeyFlags = (USHORT) SHORT1FROMMP(mp1);

          if (fsKeyFlags & KC_KEYUP) 

             { //key up

               shift_key_down = 0;

               ctrl_key_down = 0;

               alt_key_down = 0;

              }

          else // key down

             { if (fsKeyFlags & KC_SHIFT) shift_key_down = 1;

               if (fsKeyFlags & KC_CTRL)  ctrl_key_down = 1;

               if (fsKeyFlags & KC_ALT)   

               { alt_key_down = 1;

                 font_dialog(hwnd,&wlist[w].fm);

                }

               if (fsKeyFlags & KC_CHAR )

               { cur_event.val = SHORT1FROMMP(mp2);

                 cur_event.kind = key_press_event;

                }

              }

           break;

         }





    case WM_COMMAND:

      switch (SHORT1FROMMP (mp1))

      { case IDM_FONT:

           font_dialog(hwnd,&wlist[w].fm);

           return ((MRESULT)0);



        case IDM_EXIT:

           WinSendMsg (hwnd, WM_CLOSE, NULL, NULL);

           return ((MRESULT)0);

        }



    }



   return WinDefWindowProc (hwnd, msg, mp1, mp2);

}







void x_open_display(void)

{ 

  hab = WinInitialize (0);

  hmq = WinCreateMsgQueue (hab, 0);



  WinRegisterClass (hab,

                    (PSZ)"LEDA-WINDOW", 

                    ClientWndProc, 

                    CS_SIZEREDRAW | CS_SAVEBITS, 

                    0L);



  mode_table[src_mode] = FM_OVERPAINT;

  mode_table[or_mode]  = FM_OR;

  mode_table[xor_mode] = FM_NOTXORSRC;

  mode_table[and_mode] = FM_AND;



  lstyle_table[dotted] = LINETYPE_DOT;

  lstyle_table[dashed] = LINETYPE_LONGDASH;

  lstyle_table[solid]  = LINETYPE_SOLID;





  HPS hps = WinGetPS(HWND_DESKTOP);





  TextFattrs.usRecordLength  = sizeof(FATTRS);

  TextFattrs.fsSelection     = 0;

  TextFattrs.lMatch          = 0L;

  TextFattrs.idRegistry      = 0;

  TextFattrs.lMaxBaselineExt = 14L;

  TextFattrs.lAveCharWidth   = 6L;

  TextFattrs.fsType          = 0;

  strcpy(TextFattrs.szFacename,"System VIO");



  BoldFattrs.usRecordLength  = sizeof(FATTRS);

  BoldFattrs.fsSelection     = 0;

  BoldFattrs.lMatch          = 0L;

  BoldFattrs.idRegistry      = 0;

  BoldFattrs.lMaxBaselineExt = 16L;

  BoldFattrs.lAveCharWidth   = 8L;

  BoldFattrs.fsType          = 0;

  strcpy(TextFattrs.szFacename,"System Proportional");



  // NULL window



  wlist[0].COLOR = black;

  wlist[0].LSTYLE = solid;

  wlist[0].LWIDTH = 1;

  wlist[0].MODE = src_mode;



  GpiCreateLogFont(hps,(PSTR8)NULL,TEXT_FONT_ID,&TextFattrs);

  GpiSetCharSet(hps,TEXT_FONT_ID);

  GpiQueryFontMetrics(hps,sizeof(FONTMETRICS),&wlist[0].fm);



  wlist[0].fm.lAveCharWidth = 8;

  wlist[0].fm.lMaxBaselineExt = 14;  



  WinReleasePS(hps);

}





void x_close_display(void)

{ WinDestroyMsgQueue (hmq);

  WinTerminate (hab);

 }







void x_flush_display(void) {}



int  x_create_buffer(int)    { return 0; }

int  x_test_buffer(int) { return 0; }

void x_start_buffering(int) {} 

void x_flush_buffer(int, int, int, int, int, int, int) {}

void x_flush_buffer(int, int, int, int, int) {} 

void x_stop_buffering(int) {}

void x_delete_buffer(int)  {}



char* x_get_buffer_pixrect(int) { return 0; }







   



int x_display_width(void)

{ return WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN); }



int x_display_height(void)

{ return WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN); }



/*

int x_mouse_buttons(void)

{ return WinQuerySysValue(HWND_DESKTOP, SV_CMOUSEBUTTONS); }

*/





int x_display_depth(void) { return 16; }



int x_display_bits_saved(void) { return 0; }







/* windows */





Window x_create_window(void* inf, int width,int height,int bg_col, 

                       const char* header, const char* label, int p_win,

                       void (*func)(void*))

{

  if (wcount++ >= MAX_WIN) 

      message("LEDA: maximal number of windows (%d) exceeded",MAX_WIN);



  os2_win* wp = &wlist[wcount];



  wp->hwndFrame = 0;

  wp->hwnd      = 0;

  wp->hps       = 0;

  wp->bg_col    = bg_col;

  wp->redraw    = func;

  wp->width     = width;

  wp->height    = height;

  wp->COLOR     = black;

  wp->LSTYLE    = solid;

  wp->LWIDTH    = 1;

  wp->JSTYLE    = 1;

  wp->MODE      = src_mode;

  wp->TMODE     = transparent;

  wp->iconized  = 0;

  wp->mapped    = 0;

  wp->inf       = inf;



  wp->header = new char[strlen(header) + 1];

  strcpy(wp->header,header);



  return wcount;

}





void x_open_window(Window win, int x, int y, int width,int height,int p_win) 

{

  HWND hwndFrame  = wlist[win].hwndFrame;

  HWND hwndParent = 0;



  ULONG flFrameFlags = 0;



  int screen_height = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);



  if (p_win)

    { RECTL rectl;

      WinQueryWindowRect(wlist[p_win].hwnd,&rectl);

      WinMapWindowPoints(wlist[p_win].hwnd,HWND_DESKTOP,(PPOINTL)&rectl,2);

      x += rectl.xLeft;

      y += (screen_height - rectl.yTop);

      hwndParent = wlist[p_win].hwndFrame;

      flFrameFlags = FCF_BORDER;

      width  += 2*WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);

      height += 2*WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);

      //flFrameFlags = FCF_BORDER;

      //width  += 2*WinQuerySysValue(HWND_DESKTOP, SV_CXDLGFRAME);

      //height += 2*WinQuerySysValue(HWND_DESKTOP, SV_CYDLGFRAME);

     }

  else

    { //height += WinQuerySysValue(HWND_DESKTOP, SV_CYMENU); 

      height += WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR); 

      height += 2*WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER);

      width  += 2*WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER);

      flFrameFlags = ( FCF_TITLEBAR      | 

                       FCF_SYSMENU       |

                       FCF_SIZEBORDER    | 

                       FCF_MINMAX        |

                    // FCF_MENU          | 

                       FCF_ICON          | 

                       FCF_TASKLIST);

     }



  y = screen_height - height - y; 





  if (!hwndFrame)

  { FRAMECDATA FrameData;

    FrameData.cb = sizeof(FRAMECDATA);

    FrameData.flCreateFlags = flFrameFlags;

    FrameData.hmodResources = 0;

    FrameData.idResources = LEDA_ID;



    hwndFrame = WinCreateWindow(HWND_DESKTOP, 

                                WC_FRAME, 

                                (PSZ)wlist[win].header,

                                0, 0, 0, 0, 0, 

                                hwndParent, 

                                HWND_TOP, 

                                LEDA_ID,

                                (PVOID)(PFRAMECDATA)&FrameData,

                                NULL);



    HWND hwnd = WinCreateWindow(hwndFrame,

                                (PSZ)"LEDA-WINDOW", 

                                NULL, 

                                0, 0, 0, 0, 0, 

                                hwndFrame, 

                                HWND_TOP, 

                                FID_CLIENT,

                                NULL, 

                                NULL);





    HDC hdc = WinOpenWindowDC(hwnd);

    HPS hps = GpiCreatePS(hab,hdc,&sizel,PU_PELS | GPIF_DEFAULT | 

                                                   GPIT_NORMAL | GPIA_ASSOC);

  

    if (hps == 0) 

       message("LEDA: cannot create client hps");

  

    if (GpiCreateLogFont(hps,(PSTR8)NULL,TEXT_FONT_ID,&TextFattrs) == FALSE)

       message("LEDA: cannot create font");

  

    GpiSetCharSet(hps,TEXT_FONT_ID);

  

    init_palette(hwnd,hps);

  

    GpiSetMix(hps,mode_table[src_mode]);

    GpiSetColor(hps,black);

    GpiSetBackColor(hps,wlist[win].bg_col);

    GpiSetLineType(hps,lstyle_table[solid]);



    wlist[win].hwndFrame = hwndFrame;

    wlist[win].hwnd      = hwnd;

    wlist[win].hps       = hps;

  }

  

  WinSetWindowPos(hwndFrame,0,x,y,width,height,

                  SWP_SHOW | SWP_ACTIVATE | SWP_SIZE | SWP_MOVE);



  SWP swp;

  WinQueryWindowPos(wlist[win].hwnd, &swp);

  wlist[win].width = swp.cx;

  wlist[win].height = swp.cy;





  GpiQueryFontMetrics(wlist[win].hps,sizeof(FONTMETRICS),&wlist[win].fm);



  x_set_color(win,wlist[win].COLOR);

  x_set_mode(win,wlist[win].MODE);

  x_set_text_mode(win,wlist[win].TMODE);

  x_set_line_width(win,wlist[win].LWIDTH);

  x_set_line_style(win,wlist[win].LSTYLE);



  wlist[win].mapped = 1;



  QMSG qmsg;

  while (WinPeekMsg(hab,&qmsg,0L,0,0,PM_REMOVE)) WinDispatchMsg (hab, &qmsg);

}







int  x_window_opened(int win) { return wlist[win].mapped; }





void x_close_window(Window win) 

{ WinShowWindow(wlist[win].hwndFrame,FALSE);

  wlist[win].mapped = 0;

 }





void x_destroy_window(Window win) 

{ GpiAssociate(wlist[win].hps, NULLHANDLE); 

  GpiDestroyPS(wlist[win].hps); 

  WinDestroyWindow(wlist[win].hwndFrame); 

  delete[] wlist[win].header;

 }





void x_set_clip_rect(int win, int x0, int y0, int w, int h)

{

  HPS hps = wlist[win].hps;



  y0 = wlist[win].height - y0;



  RECTL rcl;

  rcl.xLeft   = x0;

  rcl.xRight  = x0+w;

  rcl.yTop    = y0;

  rcl.yBottom = y0-h;



  HRGN hrgn0;

  HRGN hrgn = GpiCreateRegion(hps,1,&rcl);

  GpiSetClipRegion(hps,hrgn,&hrgn0);

  GpiDestroyRegion(hps,hrgn0);

 }

 





void x_set_header(Window win, const char *s)

{ WinSetWindowText(wlist[win].hwndFrame, (PSZ)s);

  WinInvalidateRect(WinWindowFromID(wlist[win].hwndFrame, FID_TITLEBAR),

                                                     (PRECTL)NULL, FALSE);

 }





void* x_window_inf(Window win) { return wlist[win].inf; }





int x_window_width(Window win)

{ HWND hwnd = wlist[win].hwnd;

  if (hwnd)

    { SWP swp;

      WinQueryWindowPos(hwnd, &swp);

      return swp.cx;

     }

   else

     return wlist[win].width;

 }





int x_window_height(Window win)

{ HWND hwnd = wlist[win].hwnd;

  if (hwnd)

    { SWP swp;

      WinQueryWindowPos(hwnd, &swp);

      return swp.cy;

     }

   else

     return wlist[win].height;

 }









void x_window_position(Window win, int* x, int* y)

{ HWND hwnd = wlist[win].hwnd;

  *x = *y = 0;

  if (hwnd)

  { SWP swp;

    WinQueryWindowPos(wlist[win].hwnd, &swp);

    *x = swp.x;

    *y = swp.y;

   }

 }





void x_clear_window(Window win)

{ // dispatch all pending messages first

  QMSG qmsg;

  while (WinPeekMsg(hab,&qmsg,0L,0,0,PM_REMOVE)) WinDispatchMsg (hab, &qmsg);

  RECTL rcl;

  WinQueryWindowRect(wlist[win].hwnd, &rcl);

  drawing_mode save_mode = x_set_mode(win,src_mode);

  WinFillRect(wlist[win].hps,&rcl,wlist[win].bg_col);

  x_set_mode(win,save_mode);

}





/* drawing */



inline void MoveTo(HPS hps, int x, int y)

{ POINTL pos;

  pos.x = x;

  pos.y = y;

  GpiMove(hps,&pos);

 }



inline void LineTo(HPS hps, int x, int y)

{ POINTL pos;

  pos.x = x;

  pos.y = y;

  GpiLine(hps,&pos);

 }



inline void SetArcParams(HPS hps, int r1, int r2)

{ ARCPARAMS arcparams; 

  arcparams.lP = r1;

  arcparams.lQ = r2;

  arcparams.lR = 0;

  arcparams.lS = 0;

  GpiSetArcParams(hps, (PARCPARAMS)&arcparams);

}





static void adjust_line(int s, int& x1, int& y1, int& x2, int& y2)

{ int dx = x2 - x1;

  int dy = y2 - y1;

  if (dx == 0 && dy == 0) return;



  int xoff = s;

  int yoff = s;



  if (dx < 0) { dx = -dx; xoff = -s; }

  if (dy < 0) { dy = -dy; yoff = -s; }



  if ( dx >= dy) x2 += xoff;

  if ( dx <= dy) y2 += yoff;

 }





void x_line(Window win, int x1, int y1, int x2, int y2)

{ HPS hps = wlist[win].hps;

  int jstyle = wlist[win].JSTYLE;

  if ((jstyle & 1) == 0) adjust_line(-1,x2,y2,x1,y1);

  if ((jstyle & 2) == 0) adjust_line(-1,x1,y1,x2,y2);

  GpiBeginPath(hps,1L);

  MoveTo(hps,x1,YCOORD(win,y1));

  LineTo(hps,x2,YCOORD(win,y2));

  GpiEndPath(hps);

  GpiStrokePath(hps,1L,0L);

 }



void x_lines(int w, int n, int *x1, int *y1, int* x2, int* y2)

{ while (n--) x_line(w,*x1++,*y1++,*x2++,*y2++); }





void x_rect(Window win, int x1, int y1, int x2, int y2)

{ HPS hps = wlist[win].hps;

  MoveTo(hps,x1,YCOORD(win,y1));

  POINTL pos;

  pos.x = x2;

  pos.y = YCOORD(win,y2);

  GpiBox(hps,DRO_OUTLINE,&pos,0,0);

 }





void x_box(Window win, int x1, int y1, int x2, int y2)

{ HPS hps = wlist[win].hps;

  MoveTo(hps,x1,YCOORD(win,y1));

  POINTL pos;

  pos.x = x2;

  pos.y = YCOORD(win,y2);

  GpiBox(hps,DRO_OUTLINEFILL,&pos,0,0);

 }







void x_circle(Window win, int x, int y, int r)

{ HPS hps = wlist[win].hps;

  SetArcParams(hps,r,r);

  GpiBeginPath(hps,1L);

  MoveTo(hps,x,YCOORD(win,y));

  GpiFullArc(hps,DRO_OUTLINE,MAKEFIXED(1,0));

  GpiEndPath(hps);

  GpiStrokePath(hps,1L,0L);

}





void x_fill_circle(Window win, int x, int y, int r)

{ HPS hps = wlist[win].hps;

  SetArcParams(hps,r,r);

  MoveTo(hps,x,YCOORD(win,y));

  GpiFullArc(hps,DRO_OUTLINEFILL,MAKEFIXED(1,0));

}





void x_pixel(Window win, int x, int y)

{ POINTL p;

  p.x = x;

  p.y = YCOORD(win,y);

  GpiSetPel(wlist[win].hps,&p);

}







void x_pixels(Window win, int n, int* x, int* y)

{ while (n--) x_pixel(win,x[n],y[n]); }





void x_point(Window win, int x, int y)

{ HPS hps = wlist[win].hps;

  y = YCOORD(win,y);

  MoveTo(hps,x-2,y-2);

  LineTo(hps,x+2,y+2);

  MoveTo(hps,x-2,y+2);

  LineTo(hps,x-1,y+1);

  MoveTo(hps,x+1,y-1);

  LineTo(hps,x+2,y-2);

 }





void x_arc(Window win,int mx,int my,int r1,int r2,double start,double angle)

{ HPS hps = wlist[win].hps;

  POINTL p[3];

  p[0].x = mx + int(r1*cos(start));

  p[0].y = YCOORD(win,my + int(r1*sin(start)));

  p[1].x = mx + int(r1*cos(start+angle/2));

  p[1].y = YCOORD(win,my + int(r1*sin(start+angle/2)));

  p[2].x = mx + int(r1*cos(start+angle));

  p[2].y = YCOORD(win,my + int(r1*sin(start+angle)));

  GpiBeginPath(hps,1L);

  GpiMove(hps,p);

  GpiPointArc(hps,p+1);

  GpiEndPath(hps);

  GpiStrokePath(hps,1L,0L);

}





void x_fill_arc(Window win,int x0,int y0,int r1,int r2,double a1,double a2) {}





void x_ellipse(Window win, int x, int y, int r1, int r2)

{ HPS hps = wlist[win].hps;

  SetArcParams(hps,r1,r2);

  y = YCOORD(win,y);

  MoveTo(hps,x,y);

  GpiFullArc(hps,DRO_OUTLINE,MAKEFIXED(1,0));

}





void x_fill_ellipse(Window win, int x, int y, int r1, int r2)

{ HPS hps = wlist[win].hps;

  SetArcParams(hps,r1,r2);

  y = YCOORD(win,y);

  MoveTo(hps,x,y);

  GpiFullArc(hps,DRO_OUTLINEFILL,MAKEFIXED(1,0));

}





void x_polygon(Window win, int n, int* xcoord, int* ycoord)

{ HPS hps = wlist[win].hps;

  POINTL*  p = new POINTL[n];

  for(int i=0; i < n; i++) 

  { p[i].x = xcoord[i];

    p[i].y = YCOORD(win,ycoord[i]);

   }

  GpiBeginPath(hps,1L);

  GpiPolyLine(hps,n,p);

  GpiEndPath(hps);

  GpiStrokePath(hps,1L,0L);

}





void x_fill_polygon(Window win, int n, int* xcoord, int* ycoord)

{ HPS hps = wlist[win].hps;

  POINTL*  p = new POINTL[n];

  for(int i=0; i < n; i++) 

  { p[i].x = xcoord[i];

    p[i].y = YCOORD(win,ycoord[i]);

   }

  GpiMove(hps,p);

  GpiBeginArea(hps,BA_BOUNDARY | BA_ALTERNATE);

  GpiPolyLine(hps,n,p);

  GpiEndArea(hps);

}





void x_text(Window win, int x, int y, const char* s, int l)

{ int h = x_text_height(win,s);

  int w = x_text_width(win,s);



  if (wlist[win].TMODE == opaque)

  { int save_col = x_set_color(win,white);

    drawing_mode save_mode = x_set_mode(win,src_mode);

    x_box(win,x,y,x+w,y+h);

    x_set_color(win,save_col);

    x_set_mode(win,save_mode);

   }



  y = YCOORD(win,y);



  POINTL pos;

  pos.x = x;

  pos.y = y - wlist[win].fm.lMaxAscender;

  int len = strlen(s);

  if (len > 512) len = 512;

  if (len > l) len = l;

  GpiCharStringAt(wlist[win].hps,&pos,len, (PSZ)s);

 }

  

void x_text(Window win, int x, int y, const char* s)

{ x_text(win, x, y, s, 512); }





void x_ctext(Window win, int x, int y, const char* s)

{ int h = x_text_height(win,s);

  int w = x_text_width(win,s);

  x_text(win,x-w/2,y-h/2,s);

}



 

//------------------------------------------------------------------------------

// pixrects and bitmaps

//------------------------------------------------------------------------------



inline void SWAP(int& x1, int& x2)

{ int t = x1; x1 = x2; x2 = t; }



struct Image {

 short w;

 short h;

 HBITMAP map;

};







char* x_create_pixrect(Window win, int x1, int y1, int x2, int y2)

{ HPS hps = wlist[win].hps;

  Image* im = new Image;



  y1 = YCOORD(win,y1);

  y2 = YCOORD(win,y2);



  if (x1 > x2) SWAP(x1,x2);

  if (y1 > y2) SWAP(y1,y2);



  im->w = x2-x1+1;

  im->h = y2-y1+1;



  // create memory device context and presentation space



  HDC hdc_mem = DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 5L,(PDEVOPENDATA)&dop, 

                                                                NULLHANDLE);

  HPS hps_mem = GpiCreatePS(hab,hdc_mem,&sizel,GPIA_ASSOC|GPIT_NORMAL|PU_PELS);



  BITMAPINFOHEADER2 bmp = {16, 0, 0, 4, 1}; 

  bmp.cx = im->w;

  bmp.cy = im->h;

  im->map = GpiCreateBitmap(hps_mem, &bmp, 0L, NULL, NULL);

  GpiSetBitmap(hps_mem, im->map);



  POINTL aptl[3];

  aptl[0].x = 0;  

  aptl[0].y = 0;

  aptl[1].x = im->w-1;  

  aptl[1].y = im->h-1;

  aptl[2].x = x1; 

  aptl[2].y = y1;

  GpiBitBlt(hps_mem,hps,3,aptl,ROP_SRCCOPY,BBO_IGNORE);

  GpiDestroyPS(hps_mem);

  DevCloseDC(hdc_mem);

  return (char*)im;

}

 



void x_insert_pixrect(Window win, char* rect)

{ x_insert_pixrect(win,0,0,rect); }





void x_insert_pixrect(Window win, int x, int y, char* rect)

{ // (x,y) lower left corner !



  HPS hps = wlist[win].hps;



  HDC hdc_mem = DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 5L,(PDEVOPENDATA)&dop, 

                                                                NULLHANDLE);

  HPS hps_mem = GpiCreatePS(hab,hdc_mem,&sizel,GPIA_ASSOC|GPIT_NORMAL|PU_PELS);



  y = YCOORD(win,y);



  Image* im = (Image*)rect;

  GpiSetBitmap(hps_mem, im->map);

  POINTL aptl[4];

  aptl[0].x = x; 

  aptl[0].y = y;

  aptl[1].x = x + im->w-1; 

  aptl[1].y = y + im->h-1;

  aptl[2].x = 0; 

  aptl[2].y = 0;

  GpiBitBlt(hps,hps_mem,3,aptl,ROP_SRCCOPY,BBO_IGNORE);

  GpiDestroyPS(hps_mem);

  DevCloseDC(hdc_mem);

 }







void x_insert_pixrect(int win, int x, int y, char* rect, int x0, int y0, int x1, int y1)

{ // (x,y) lower left corner !



  HPS hps = wlist[win].hps;



  HDC hdc_mem = DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 5L,(PDEVOPENDATA)&dop, 

                                                                NULLHANDLE);

  HPS hps_mem = GpiCreatePS(hab,hdc_mem,&sizel,GPIA_ASSOC|GPIT_NORMAL|PU_PELS);



  y = YCOORD(win,y);



  if (x0 > x1) SWAP(x0,x1);

  if (y0 > y1) SWAP(y0,y1);



  Image* im = (Image*)rect;

  int wi = x1 - x0 + 1;

  int he = y1 - y0 + 1;



  GpiSetBitmap(hps_mem, im->map);

  POINTL aptl[4];

  aptl[0].x = x; 

  aptl[0].y = y;

  aptl[1].x = x + wi-1; 

  aptl[1].y = y + he-1;

  aptl[2].x = x0; 

  aptl[2].y = x0;

  GpiBitBlt(hps,hps_mem,3,aptl,ROP_SRCCOPY,BBO_IGNORE);

  GpiDestroyPS(hps_mem);

  DevCloseDC(hdc_mem);

 }









void x_delete_pixrect(char* rect)

{ Image* im = (Image*)rect;

  GpiDeleteBitmap(im->map);

 }





void x_copy_pixrect(Window win, int x1, int y1, int x2, int y2, int x, int y)

{ char* p = x_create_pixrect(win,x1,y1,x2,y2);

  x_insert_pixrect(win,x,y,p);

  x_delete_pixrect(p);

 }





static char rev_byte(char c)

{ char c1 = 0x00;

  if (c & 0x01) c1 |= 0x80;

  if (c & 0x02) c1 |= 0x40;

  if (c & 0x04) c1 |= 0x20;

  if (c & 0x08) c1 |= 0x10;

  if (c & 0x10) c1 |= 0x08;

  if (c & 0x20) c1 |= 0x04;

  if (c & 0x40) c1 |= 0x02;

  if (c & 0x80) c1 |= 0x01;

  return ~c1;

 }





char* x_create_bitmap(Window win, int w, int h, char* q)

{ HPS hps = wlist[win].hps;



  int   bw0 = (w+7)/8;

  int   bw1 = 2*((bw0+1)/2);

  char* buf = new char[bw1*h];



  for(int i=h-1; i>=0; i--)

  { char* p = buf+bw1*i;

    for(int j=0; j<bw1; j++) 

       *p++ = (j >= bw0) ? 0 : rev_byte(*q++);

   }



  Image* im = new Image;

  im->w = w;

  im->h = h;



  // create memory device context and presentation space



  HDC hdc_mem = DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 5L,(PDEVOPENDATA)&dop, 

                                                                NULLHANDLE);

  HPS hps_mem = GpiCreatePS(hab,hdc_mem,&sizel,GPIA_ASSOC|GPIT_NORMAL|PU_PELS);



  BITMAPINFOHEADER2 bmih;

  bmih.cbFix = 16;

  bmih.cx = w;

  bmih.cy = h;

  bmih.cPlanes = 1;

  bmih.cBitCount = 1;



  im->map = GpiCreateBitmap(hps_mem,&bmih,CBM_INIT,(PBYTE)buf,(BITMAPINFO2*)&bmih);

  GpiDestroyPS(hps_mem);

  DevCloseDC(hdc_mem);

  delete[] buf;

  return (char*)im;

}



char* x_create_pixrect(Window win, int w, int h, char* data, int, int)

{ return x_create_bitmap(win,w,h,data); }







char* x_create_pixrect(Window win, char** xpm) { return (char*)0; }





void x_pixrect_dimensions(char* rect, int* w, int* h)

{ if (rect)

  { Image* im = (Image*)rect;

    *w = im->w;

    *h = im->h;

   }

}







void  x_insert_bitmap(Window win, int x, int y, char* rect)

{ // (x,y) lower left corner !



  HPS hps = wlist[win].hps;



  HDC hdc_mem = DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 5L,(PDEVOPENDATA)&dop, 

                                                                NULLHANDLE);

  HPS hps_mem = GpiCreatePS(hab,hdc_mem,&sizel,GPIA_ASSOC|GPIT_NORMAL|PU_PELS);



  y = YCOORD(win,y);



  Image* im = (Image*)rect;

  GpiSetBitmap(hps_mem, im->map);

  POINTL aptl[4];

  aptl[0].x = x; 

  aptl[0].y = y;

  aptl[1].x = x + im->w; 

  aptl[1].y = y + im->h;

  aptl[2].x = 0; 

  aptl[2].y = 0;

  GpiBitBlt(hps,hps_mem,3,aptl,ROP_SRCCOPY,BBO_IGNORE);

  GpiDestroyPS(hps_mem);

  DevCloseDC(hdc_mem);

 }





void  x_delete_bitmap(char* rect)

{ Image* im = (Image*)rect;

  GpiDeleteBitmap(im->map);

 }

 





/* fonts and text */



int x_load_text_font(const char* font_name)

{ for(int w=1; w<=wcount; w++) x_set_font(w,font_name);

  return 1; 

 }



int x_load_bold_font(const char* font_name)  { return 0; }

int x_load_fixed_font(const char* font_name) { return 0; }



int x_set_font(Window win, const char* fname)  

{ 

  int scaling = 1;

  if (fname[0] >= '1' && fname[0] <= '9') 

     scaling = fname[0] - '0';



  HPS hps = wlist[win].hps;

  TextFattrs.lMaxBaselineExt = 3*scaling;

  GpiCreateLogFont(hps,(PSTR8)NULL,USER_FONT_ID,&TextFattrs);

  GpiSetCharSet(hps,USER_FONT_ID);

  GpiQueryFontMetrics(hps,sizeof(FONTMETRICS),&wlist[win].fm);

  return 1; 

 }





void x_set_text_font(Window win)

{ HPS hps = wlist[win].hps;

  GpiCreateLogFont(hps,(PSTR8)NULL,TEXT_FONT_ID,&TextFattrs);

  GpiSetCharSet(hps,TEXT_FONT_ID);

  GpiQueryFontMetrics(hps,sizeof(FONTMETRICS),&wlist[win].fm);

}





void x_set_bold_font(Window win)

{ HPS hps = wlist[win].hps;

  GpiCreateLogFont(hps,(PSTR8)NULL,BOLD_FONT_ID,&BoldFattrs);

  GpiSetCharSet(hps,BOLD_FONT_ID);

  GpiQueryFontMetrics(hps,sizeof(FONTMETRICS),&wlist[win].fm);

}





void x_set_fixed_font(Window win)

{ HPS hps = wlist[win].hps;

  GpiCreateLogFont(hps,(PSTR8)NULL,TEXT_FONT_ID,&TextFattrs);

  GpiSetCharSet(hps,TEXT_FONT_ID);

  GpiQueryFontMetrics(hps,sizeof(FONTMETRICS),&wlist[win].fm);

}



int x_text_width(Window win,const char* s)

{ return x_text_width(win,s,strlen(s)); }



int x_text_width(Window win,const char* s, int l)

{ if (l > strlen(s)) l = strlen(s);

  if (!wlist[win].hwnd)

     return  l * wlist[0].fm.lAveCharWidth;

  HPS hps = wlist[win].hps;

  POINTL ptl[TXTBOX_COUNT+1];

  GpiQueryTextBox(hps,l,(PCH)s,TXTBOX_COUNT,ptl);

  return ptl[TXTBOX_TOPRIGHT].x - ptl[TXTBOX_BOTTOMLEFT].x; 

 }





int x_text_height(Window win,const char* s) 

{ if (!wlist[win].hwnd)

     return wlist[0].fm.lMaxBaselineExt;  

  HPS hps = wlist[win].hps;

  POINTL ptl[TXTBOX_COUNT+1];

  GpiQueryTextBox(hps,strlen(s),(PCH)s,TXTBOX_COUNT,ptl);

  return ptl[TXTBOX_TOPRIGHT].y - ptl[TXTBOX_BOTTOMLEFT].y; 

 }

 





/* drawing parameters */



int x_set_color(Window win, int col) 

{ int c = wlist[win].COLOR;

  if (c!=col)

  { GpiSetColor(wlist[win].hps,col); 

    wlist[win].COLOR = col;

   }

  return c;

 }





drawing_mode x_set_mode(Window win, drawing_mode mod) 

{ drawing_mode m = wlist[win].MODE;

  if (m != mod)

  { HPS hps = wlist[win].hps;

    if (hps) GpiSetMix(hps,mode_table[mod]); 

    wlist[win].MODE = mod;

   }

  return m;

 }





int x_set_line_width(Window win, int w) 

{ int lw = wlist[win].LWIDTH;

  if (lw != w)

  { HPS hps = wlist[win].hps;

    if (hps) GpiSetLineWidthGeom(hps,w); 

    wlist[win].LWIDTH = w;

   }

  return lw;

 }





line_style x_set_line_style(Window win, line_style s)

{ line_style ls = wlist[win].LSTYLE;

  if (ls != s)

  { HPS hps = wlist[win].hps;

    if (hps) GpiSetLineType(hps,lstyle_table[s]);

    wlist[win].LSTYLE = s;

   }

  return ls;

 }





text_mode x_set_text_mode(Window win, text_mode tm) 

{ text_mode save = wlist[win].TMODE;

  wlist[win].TMODE = tm;  

  return save;

 }



int x_set_join_style(Window win, int js) 

{ int save = wlist[win].JSTYLE;

  wlist[win].JSTYLE = js;  

  return save;

 }







int           x_get_color(Window win)      { return wlist[win].COLOR;  }

drawing_mode  x_get_mode(Window win)       { return wlist[win].MODE;   }

int           x_get_line_width(Window win) { return wlist[win].LWIDTH; }

line_style    x_get_line_style(Window win) { return wlist[win].LSTYLE; }

text_mode     x_get_text_mode(Window win)  { return wlist[win].TMODE;  }





void x_set_read_gc(Window win)

{ HPS hps = wlist[win].hps;

  GpiSetMix(hps,mode_table[xor_mode]);

  GpiSetColor(hps,black);

  GpiSetLineType(hps,lstyle_table[solid]);

  GpiSetLineWidthGeom(hps,1);

 }



void x_reset_gc(Window win)

{ HPS hps = wlist[win].hps;

  GpiSetMix(hps,mode_table[wlist[win].MODE]);

  GpiSetColor(hps,wlist[win].COLOR);

  GpiSetLineType(hps,lstyle_table[wlist[win].LSTYLE]);

  GpiSetLineWidthGeom(hps,wlist[win].LWIDTH);

 }









/* colors */



void x_set_palette(int i, int r, int g, int b)

{ unsigned char R = (unsigned char)r;

  unsigned char G = (unsigned char)g;

  unsigned char B = (unsigned char)b;

  rgb_table[2*i+1] = LONGFromRGB(R,G,B);

  for(int win=1; win<=wcount; win++)

    GpiCreateLogColorTable(wlist[win].hps,LCOL_PURECOLOR,

                                              LCOLF_INDRGB,0L,32L,rgb_table);

}

 



void x_get_palette(int i, int* red, int* green, int* blue)

{ LONG rgb = rgb_table[i];

  *blue  =  rgb        & 0xFF; 

  *green = (rgb >>  8) & 0xFF;

  *red   = (rgb >> 16) & 0xFF;

 }





int x_new_color(const char*) { return black; }

int x_new_color(int,int,int) { return black; }





/* events */



static QMSG qmsg;

static int putback = 0;

static event last_event;





int x_get_next_event(Window* win, int* val, int* x, int* y, unsigned long *t,

                                                            int msec)

{ // get next event with timeout

  // not implemented

  return x_get_next_event(win,val,x,y,t);

}



int x_get_next_event(Window* win, int* val, int* x, int* y, unsigned long *t)

{ 

  if (putback) 

   { cur_event = last_event;

     putback = 0;

    }

  else

    { cur_event.kind = no_event;

      if (WinGetMsg (hab, &qmsg, 0L, 0, 0))

         WinDispatchMsg (hab, &qmsg);

      else

         exit(0);

      if (cur_event.kind != exposure_event)

         cur_event.t = qmsg.time;

      if (cur_event.kind != no_event) 

          last_event = cur_event;

     } 



  *win = cur_event.win;

  *val = cur_event.val;

  *x   = cur_event.x;

  *y   = cur_event.y;

  *t   = cur_event.t;

  return cur_event.kind;

 }





int x_check_next_event(Window* win, int* val, int* x, int* y, unsigned long *t)

{ 

  if (putback || WinPeekMsg(hab, &qmsg, 0L, 0, 0, PM_NOREMOVE))

     return x_get_next_event(win,val,x,y,t); 

  else

     return no_event;

 }



void x_put_back_event(void) {  putback = 1; }







// not implemented



int x_get_pixel(Window, int, int) 

{ return 0; }



void x_start_timer(Window win, int msec)

{ /* not implemented */ }



void x_stop_timer(Window win)

{ /* not implemented */ }



void x_set_border_width(Window, int) 

{ /* not implemented */ }



void x_grab_pointer(Window) 

{ /* not implemented */ }



void x_ungrab_pointer() 

{ /* not implemented */ }



void x_set_icon_pixmap(Window,char*)

{ /* not implemented */ }





//-----------------------------------------------------------------------------

//

// basic graphics routines for OS/2  (PM)

//

// S. Naeher 1995,1996

//-----------------------------------------------------------------------------



#include <LEDA/impl/x_basic.h>



#include <string.h>

#include <stdio.h>

#include <stdlib.h>

#include <math.h>



#define INCL_WIN

#define INCL_GPI

#include <os2.h>



#define LEDA_ID         1



#define IDM_FILE        1

#define IDM_EXIT        2

#define IDM_FONT        3



#define TEXT_FONT_ID    1

#define BOLD_FONT_ID    2

#define FIXED_FONT_ID   3

#define USER_FONT_ID    4





typedef int Window;



typedef void (*redraw_fct)(void*);



struct os2_win 

{

  HWND hwndFrame;

  HWND hwnd;

  HPS  hps;

  int  bg_col;

  int  width;

  int  height;

  int  iconized;

  int  mapped;



  char* header;



  FONTMETRICS fm;



  int          COLOR;

  int          LWIDTH;

  int          JSTYLE;

  line_style   LSTYLE;

  text_mode    TMODE;

  drawing_mode MODE;

  

  void* inf;

  

  redraw_fct redraw;

};





#define YCOORD(w,ypix)  (wlist[w].height - ypix -1)





// global data



static HAB hab = 0;

static HMQ hmq = 0;



static SIZEL sizel = {0,0};

static DEVOPENSTRUC dop = {NULL,(PSZ)"DISPLAY",NULL,NULL,NULL,NULL,NULL,NULL,NULL};



static FATTRS TextFattrs;

static FATTRS BoldFattrs;

static FATTRS MesgFattrs;



struct event {

  int win;

  int kind;

  int val;

  int x;

  int y;

  unsigned long t;

};



static event cur_event;





#define  MAX_WIN 32



static os2_win wlist[MAX_WIN+1];

static Window wcount = 0;



static LONG  rgb_table[32];

static long  mode_table[4];

static long  lstyle_table[4];



static int shift_key_down = 0;

static int ctrl_key_down = 0;

static int alt_key_down = 0;





/* display */



inline void message(char* s)

{ WinAlarm( HWND_DESKTOP, WA_ERROR );

  WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, (PSZ) s, 

                 (PSZ)"LEDA WINDOW MESSAGE", 256, MB_OK);

} 



inline void message(char* s, int i)

{ WinAlarm( HWND_DESKTOP, WA_ERROR );

  char msg[256];

  sprintf(msg,s,i);

  WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, (PSZ) msg, 

                (PSZ)"LEDA WINDOW MESSAGE", 256, MB_OK);

} 



inline void message(char* s, int i, int j)

{ WinAlarm( HWND_DESKTOP, WA_ERROR );

  char msg[256];

  sprintf(msg,s,i,j);

  WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, (PSZ) msg, 

                (PSZ)"LEDA WINDOW MESSAGE", 256, MB_OK);

} 







#define LONGFromRGB(R,G,B) (LONG)(((LONG)R<<16)+((LONG)G<<8)+(LONG)B)



inline void set_rgb_table(int i, 

                          unsigned char r, unsigned char g, unsigned char b)

{ rgb_table[2*i] = i;

  rgb_table[2*i+1] = LONGFromRGB(r,g,b);

 }



static void init_palette(HWND hwnd,HPS hps)

{ 

  set_rgb_table(white, 255,255,255);

  set_rgb_table(black,   0,  0,  0);

  set_rgb_table(red,   255,  0,  0);

  set_rgb_table(green,  32,255,  0);

  set_rgb_table(blue,    0,  0,213);

  set_rgb_table(yellow,255,255,  0);

  set_rgb_table(violet,160,  0,208);

  set_rgb_table(orange,255,160,  0);

  set_rgb_table(cyan,    0,192,192);

  set_rgb_table(brown, 192,112, 56);

  set_rgb_table(pink,  255,  0,255);

  set_rgb_table(green2,  0,160,100);

  set_rgb_table(blue2,   0,128,255);

  set_rgb_table(grey1, 212,212,212);

  set_rgb_table(grey2, 180,180,180);

  set_rgb_table(grey3, 116,116,116);



  if (!GpiCreateLogColorTable(hps,LCOL_PURECOLOR,LCOLF_INDRGB,0,32,rgb_table))

     message("LEDA: cannot create color table");

}







static void font_dialog(HWND hwnd, PFONTMETRICS fm)

{ 

  FONTDLG FontDlg;

  char szFamilyname[FACESIZE];

  szFamilyname[0] = 0;

  memset((PCH)&FontDlg,0,sizeof(FONTDLG));

  FontDlg.cbSize         = sizeof(FONTDLG);

  FontDlg.hpsScreen      = WinGetPS(hwnd);

  FontDlg.pszFamilyname  = (PSZ)szFamilyname;

  FontDlg.usFamilyBufLen = FACESIZE;

  FontDlg.pszPreview     = (PSZ)"Sample Text";

  FontDlg.fl             = FNTS_RESETBUTTON | FNTS_CENTER |

                           FNTS_INITFROMFATTRS | FNTS_BITMAPONLY;

  FontDlg.flStyle        = FATTR_SEL_ITALIC;

  FontDlg.clrFore        = CLR_BLACK;

  FontDlg.clrBack        = CLR_PALEGRAY;

  FontDlg.fAttrs         = TextFattrs;

  FontDlg.pszTitle       = (PSZ)"FONT SELECTION";

  

  WinFontDlg(HWND_DESKTOP,hwnd,(PFONTDLG)&FontDlg);



  if (FontDlg.lReturn == DID_OK)

  {  char msg[256];

     TextFattrs = FontDlg.fAttrs;

     sprintf(msg,"Facename = %s  MaxBaseLinExt = %d CharWidth = %d", 

             TextFattrs.szFacename,

             TextFattrs.lMaxBaselineExt,

             TextFattrs.lAveCharWidth);

     message(msg);

     GpiCreateLogFont(FontDlg.hpsScreen,(PSTR8)NULL,TEXT_FONT_ID,&TextFattrs);

     GpiSetCharSet(FontDlg.hpsScreen,TEXT_FONT_ID);

     GpiQueryFontMetrics(FontDlg.hpsScreen,sizeof(FONTMETRICS),fm);

   }



  WinReleasePS(FontDlg.hpsScreen);

}







static MRESULT EXPENTRY ClientWndProc (HWND hwnd, ULONG msg,

                                       MPARAM mp1, MPARAM mp2)

{

  int w;



  for(w = 1; w<=wcount; w++)

     if (wlist[w].hwnd == hwnd) break;



  cur_event.win = w;



  switch (msg) {



  case WM_SIZE:

        { wlist[w].width = SHORT1FROMMP(mp2);

          wlist[w].height = SHORT2FROMMP(mp2);

          return ((MRESULT)0);

         }



  case WM_ERASEBACKGROUND:

          return (MRFROMLONG(1L));



  case WM_PAINT: 

        { RECTL rcl;

          WinQueryUpdateRect(hwnd,&rcl);

          cur_event.kind = exposure_event;

          cur_event.x =   rcl.xLeft;

          cur_event.y =   YCOORD(w,rcl.yTop);

          cur_event.val = rcl.xRight - rcl.xLeft + 1;

          cur_event.t =   (unsigned long)(rcl.yTop - rcl.yBottom + 1);

          WinValidateRect(hwnd,&rcl,FALSE);

          return ((MRESULT)0);

         }



  case WM_QUIT: 

  case WM_CLOSE: 

         cur_event.kind = destroy_event;

         x_close_display();

         exit(0);



  case WM_BUTTON1DBLCLK: 

  case WM_BUTTON1DOWN: 

         cur_event.kind = button_press_event;

         cur_event.val = 1;

         cur_event.x = SHORT1FROMMP(mp1);

         cur_event.y = YCOORD(w,SHORT2FROMMP(mp1));

         if (ctrl_key_down)  cur_event.val = 2;

         if (shift_key_down) cur_event.val |= 256;

         break;



  case WM_BUTTON2DBLCLK: 

  case WM_BUTTON2DOWN: 

         cur_event.kind = button_press_event;

         cur_event.val = 3;

         cur_event.x = SHORT1FROMMP(mp1);

         cur_event.y = YCOORD(w,SHORT2FROMMP(mp1));

         if (ctrl_key_down)  cur_event.val = 2;

         if (shift_key_down) cur_event.val |= 256;

         break;





  case WM_BUTTON1UP: 

         cur_event.kind = button_release_event;

         cur_event.val = 1;

         cur_event.x = SHORT1FROMMP(mp1);

         cur_event.y = YCOORD(w,SHORT2FROMMP(mp1));

         if (ctrl_key_down)  cur_event.val = 2;

         if (shift_key_down) cur_event.val |= 256;

         break;



  case WM_BUTTON2UP: 

         cur_event.kind = button_release_event;

         cur_event.val = 3;

         cur_event.x = SHORT1FROMMP(mp1);

         cur_event.y = YCOORD(w,SHORT2FROMMP(mp1));

         if (ctrl_key_down)  cur_event.val = 2;

         if (shift_key_down) cur_event.val |= 256;

         break;





  case WM_MOUSEMOVE: 

         cur_event.kind = motion_event;

         cur_event.x = SHORT1FROMMP(mp1);

         cur_event.y = YCOORD(w,SHORT2FROMMP(mp1));

         break;





  case WM_CHAR: 

        { USHORT fsKeyFlags = (USHORT) SHORT1FROMMP(mp1);

          if (fsKeyFlags & KC_KEYUP) 

             { //key up

               shift_key_down = 0;

               ctrl_key_down = 0;

               alt_key_down = 0;

              }

          else // key down

             { if (fsKeyFlags & KC_SHIFT) shift_key_down = 1;

               if (fsKeyFlags & KC_CTRL)  ctrl_key_down = 1;

               if (fsKeyFlags & KC_ALT)   

               { alt_key_down = 1;

                 font_dialog(hwnd,&wlist[w].fm);

                }

               if (fsKeyFlags & KC_CHAR )

               { cur_event.val = SHORT1FROMMP(mp2);

                 cur_event.kind = key_press_event;

                }

              }

           break;

         }





    case WM_COMMAND:

      switch (SHORT1FROMMP (mp1))

      { case IDM_FONT:

           font_dialog(hwnd,&wlist[w].fm);

           return ((MRESULT)0);



        case IDM_EXIT:

           WinSendMsg (hwnd, WM_CLOSE, NULL, NULL);

           return ((MRESULT)0);

        }



    }



   return WinDefWindowProc (hwnd, msg, mp1, mp2);

}







void x_open_display(void)

{ 

  hab = WinInitialize (0);

  hmq = WinCreateMsgQueue (hab, 0);



  WinRegisterClass (hab,

                    (PSZ)"LEDA-WINDOW", 

                    ClientWndProc, 

                    CS_SIZEREDRAW | CS_SAVEBITS, 

                    0L);



  mode_table[src_mode] = FM_OVERPAINT;

  mode_table[or_mode]  = FM_OR;

  mode_table[xor_mode] = FM_NOTXORSRC;

  mode_table[and_mode] = FM_AND;



  lstyle_table[dotted] = LINETYPE_DOT;

  lstyle_table[dashed] = LINETYPE_LONGDASH;

  lstyle_table[solid]  = LINETYPE_SOLID;





  HPS hps = WinGetPS(HWND_DESKTOP);





  TextFattrs.usRecordLength  = sizeof(FATTRS);

  TextFattrs.fsSelection     = 0;

  TextFattrs.lMatch          = 0L;

  TextFattrs.idRegistry      = 0;

  TextFattrs.lMaxBaselineExt = 14L;

  TextFattrs.lAveCharWidth   = 6L;

  TextFattrs.fsType          = 0;

  strcpy(TextFattrs.szFacename,"System VIO");



  BoldFattrs.usRecordLength  = sizeof(FATTRS);

  BoldFattrs.fsSelection     = 0;

  BoldFattrs.lMatch          = 0L;

  BoldFattrs.idRegistry      = 0;

  BoldFattrs.lMaxBaselineExt = 16L;

  BoldFattrs.lAveCharWidth   = 8L;

  BoldFattrs.fsType          = 0;

  strcpy(TextFattrs.szFacename,"System Proportional");



  // NULL window



  wlist[0].COLOR = black;

  wlist[0].LSTYLE = solid;

  wlist[0].LWIDTH = 1;

  wlist[0].MODE = src_mode;



  GpiCreateLogFont(hps,(PSTR8)NULL,TEXT_FONT_ID,&TextFattrs);

  GpiSetCharSet(hps,TEXT_FONT_ID);

  GpiQueryFontMetrics(hps,sizeof(FONTMETRICS),&wlist[0].fm);



  wlist[0].fm.lAveCharWidth = 8;

  wlist[0].fm.lMaxBaselineExt = 14;  



  WinReleasePS(hps);

}





void x_close_display(void)

{ WinDestroyMsgQueue (hmq);

  WinTerminate (hab);

 }







void x_flush_display(void) {}



int  x_create_buffer(int)    { return 0; }

int  x_test_buffer(int) { return 0; }

void x_start_buffering(int) {} 

void x_flush_buffer(int, int, int, int, int, int, int) {}

void x_flush_buffer(int, int, int, int, int) {} 

void x_stop_buffering(int) {}

void x_delete_buffer(int)  {}



char* x_get_buffer_pixrect(int) { return 0; }







   



int x_display_width(void)

{ return WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN); }



int x_display_height(void)

{ return WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN); }



/*

int x_mouse_buttons(void)

{ return WinQuerySysValue(HWND_DESKTOP, SV_CMOUSEBUTTONS); }

*/





int x_display_depth(void) { return 16; }



int x_display_bits_saved(void) { return 0; }







/* windows */





Window x_create_window(void* inf, int width,int height,int bg_col, 

                       const char* header, const char* label, int p_win,

                       void (*func)(void*))

{

  if (wcount++ >= MAX_WIN) 

      message("LEDA: maximal number of windows (%d) exceeded",MAX_WIN);



  os2_win* wp = &wlist[wcount];



  wp->hwndFrame = 0;

  wp->hwnd      = 0;

  wp->hps       = 0;

  wp->bg_col    = bg_col;

  wp->redraw    = func;

  wp->width     = width;

  wp->height    = height;

  wp->COLOR     = black;

  wp->LSTYLE    = solid;

  wp->LWIDTH    = 1;

  wp->JSTYLE    = 1;

  wp->MODE      = src_mode;

  wp->TMODE     = transparent;

  wp->iconized  = 0;

  wp->mapped    = 0;

  wp->inf       = inf;



  wp->header = new char[strlen(header) + 1];

  strcpy(wp->header,header);



  return wcount;

}





void x_open_window(Window win, int x, int y, int width,int height,int p_win) 

{

  HWND hwndFrame  = wlist[win].hwndFrame;

  HWND hwndParent = 0;



  ULONG flFrameFlags = 0;



  int screen_height = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);



  if (p_win)

    { RECTL rectl;

      WinQueryWindowRect(wlist[p_win].hwnd,&rectl);

      WinMapWindowPoints(wlist[p_win].hwnd,HWND_DESKTOP,(PPOINTL)&rectl,2);

      x += rectl.xLeft;

      y += (screen_height - rectl.yTop);

      hwndParent = wlist[p_win].hwndFrame;

      flFrameFlags = FCF_BORDER;

      width  += 2*WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);

      height += 2*WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);

      //flFrameFlags = FCF_BORDER;

      //width  += 2*WinQuerySysValue(HWND_DESKTOP, SV_CXDLGFRAME);

      //height += 2*WinQuerySysValue(HWND_DESKTOP, SV_CYDLGFRAME);

     }

  else

    { //height += WinQuerySysValue(HWND_DESKTOP, SV_CYMENU); 

      height += WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR); 

      height += 2*WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER);

      width  += 2*WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER);

      flFrameFlags = ( FCF_TITLEBAR      | 

                       FCF_SYSMENU       |

                       FCF_SIZEBORDER    | 

                       FCF_MINMAX        |

                    // FCF_MENU          | 

                       FCF_ICON          | 

                       FCF_TASKLIST);

     }



  y = screen_height - height - y; 





  if (!hwndFrame)

  { FRAMECDATA FrameData;

    FrameData.cb = sizeof(FRAMECDATA);

    FrameData.flCreateFlags = flFrameFlags;

    FrameData.hmodResources = 0;

    FrameData.idResources = LEDA_ID;



    hwndFrame = WinCreateWindow(HWND_DESKTOP, 

                                WC_FRAME, 

                                (PSZ)wlist[win].header,

                                0, 0, 0, 0, 0, 

                                hwndParent, 

                                HWND_TOP, 

                                LEDA_ID,

                                (PVOID)(PFRAMECDATA)&FrameData,

                                NULL);



    HWND hwnd = WinCreateWindow(hwndFrame,

                                (PSZ)"LEDA-WINDOW", 

                                NULL, 

                                0, 0, 0, 0, 0, 

                                hwndFrame, 

                                HWND_TOP, 

                                FID_CLIENT,

                                NULL, 

                                NULL);





    HDC hdc = WinOpenWindowDC(hwnd);

    HPS hps = GpiCreatePS(hab,hdc,&sizel,PU_PELS | GPIF_DEFAULT | 

                                                   GPIT_NORMAL | GPIA_ASSOC);

  

    if (hps == 0) 

       message("LEDA: cannot create client hps");

  

    if (GpiCreateLogFont(hps,(PSTR8)NULL,TEXT_FONT_ID,&TextFattrs) == FALSE)

       message("LEDA: cannot create font");

  

    GpiSetCharSet(hps,TEXT_FONT_ID);

  

    init_palette(hwnd,hps);

  

    GpiSetMix(hps,mode_table[src_mode]);

    GpiSetColor(hps,black);

    GpiSetBackColor(hps,wlist[win].bg_col);

    GpiSetLineType(hps,lstyle_table[solid]);



    wlist[win].hwndFrame = hwndFrame;

    wlist[win].hwnd      = hwnd;

    wlist[win].hps       = hps;

  }

  

  WinSetWindowPos(hwndFrame,0,x,y,width,height,

                  SWP_SHOW | SWP_ACTIVATE | SWP_SIZE | SWP_MOVE);



  SWP swp;

  WinQueryWindowPos(wlist[win].hwnd, &swp);

  wlist[win].width = swp.cx;

  wlist[win].height = swp.cy;





  GpiQueryFontMetrics(wlist[win].hps,sizeof(FONTMETRICS),&wlist[win].fm);



  x_set_color(win,wlist[win].COLOR);

  x_set_mode(win,wlist[win].MODE);

  x_set_text_mode(win,wlist[win].TMODE);

  x_set_line_width(win,wlist[win].LWIDTH);

  x_set_line_style(win,wlist[win].LSTYLE);



  wlist[win].mapped = 1;



  QMSG qmsg;

  while (WinPeekMsg(hab,&qmsg,0L,0,0,PM_REMOVE)) WinDispatchMsg (hab, &qmsg);

}







int  x_window_opened(int win) { return wlist[win].mapped; }





void x_close_window(Window win) 

{ WinShowWindow(wlist[win].hwndFrame,FALSE);

  wlist[win].mapped = 0;

 }





void x_destroy_window(Window win) 

{ GpiAssociate(wlist[win].hps, NULLHANDLE); 

  GpiDestroyPS(wlist[win].hps); 

  WinDestroyWindow(wlist[win].hwndFrame); 

  delete[] wlist[win].header;

 }





void x_set_clip_rect(int win, int x0, int y0, int w, int h)

{

  HPS hps = wlist[win].hps;



  y0 = wlist[win].height - y0;



  RECTL rcl;

  rcl.xLeft   = x0;

  rcl.xRight  = x0+w;

  rcl.yTop    = y0;

  rcl.yBottom = y0-h;



  HRGN hrgn0;

  HRGN hrgn = GpiCreateRegion(hps,1,&rcl);

  GpiSetClipRegion(hps,hrgn,&hrgn0);

  GpiDestroyRegion(hps,hrgn0);

 }

 





void x_set_header(Window win, const char *s)

{ WinSetWindowText(wlist[win].hwndFrame, (PSZ)s);

  WinInvalidateRect(WinWindowFromID(wlist[win].hwndFrame, FID_TITLEBAR),

                                                     (PRECTL)NULL, FALSE);

 }





void* x_window_inf(Window win) { return wlist[win].inf; }





int x_window_width(Window win)

{ HWND hwnd = wlist[win].hwnd;

  if (hwnd)

    { SWP swp;

      WinQueryWindowPos(hwnd, &swp);

      return swp.cx;

     }

   else

     return wlist[win].width;

 }





int x_window_height(Window win)

{ HWND hwnd = wlist[win].hwnd;

  if (hwnd)

    { SWP swp;

      WinQueryWindowPos(hwnd, &swp);

      return swp.cy;

     }

   else

     return wlist[win].height;

 }









void x_window_position(Window win, int* x, int* y)

{ HWND hwnd = wlist[win].hwnd;

  *x = *y = 0;

  if (hwnd)

  { SWP swp;

    WinQueryWindowPos(wlist[win].hwnd, &swp);

    *x = swp.x;

    *y = swp.y;

   }

 }





void x_clear_window(Window win)

{ // dispatch all pending messages first

  QMSG qmsg;

  while (WinPeekMsg(hab,&qmsg,0L,0,0,PM_REMOVE)) WinDispatchMsg (hab, &qmsg);

  RECTL rcl;

  WinQueryWindowRect(wlist[win].hwnd, &rcl);

  drawing_mode save_mode = x_set_mode(win,src_mode);

  WinFillRect(wlist[win].hps,&rcl,wlist[win].bg_col);

  x_set_mode(win,save_mode);

}





/* drawing */



inline void MoveTo(HPS hps, int x, int y)

{ POINTL pos;

  pos.x = x;

  pos.y = y;

  GpiMove(hps,&pos);

 }



inline void LineTo(HPS hps, int x, int y)

{ POINTL pos;

  pos.x = x;

  pos.y = y;

  GpiLine(hps,&pos);

 }



inline void SetArcParams(HPS hps, int r1, int r2)

{ ARCPARAMS arcparams; 

  arcparams.lP = r1;

  arcparams.lQ = r2;

  arcparams.lR = 0;

  arcparams.lS = 0;

  GpiSetArcParams(hps, (PARCPARAMS)&arcparams);

}





static void adjust_line(int s, int& x1, int& y1, int& x2, int& y2)

{ int dx = x2 - x1;

  int dy = y2 - y1;

  if (dx == 0 && dy == 0) return;



  int xoff = s;

  int yoff = s;



  if (dx < 0) { dx = -dx; xoff = -s; }

  if (dy < 0) { dy = -dy; yoff = -s; }



  if ( dx >= dy) x2 += xoff;

  if ( dx <= dy) y2 += yoff;

 }





void x_line(Window win, int x1, int y1, int x2, int y2)

{ HPS hps = wlist[win].hps;

  int jstyle = wlist[win].JSTYLE;

  if ((jstyle & 1) == 0) adjust_line(-1,x2,y2,x1,y1);

  if ((jstyle & 2) == 0) adjust_line(-1,x1,y1,x2,y2);

  GpiBeginPath(hps,1L);

  MoveTo(hps,x1,YCOORD(win,y1));

  LineTo(hps,x2,YCOORD(win,y2));

  GpiEndPath(hps);

  GpiStrokePath(hps,1L,0L);

 }



void x_lines(int w, int n, int *x1, int *y1, int* x2, int* y2)

{ while (n--) x_line(w,*x1++,*y1++,*x2++,*y2++); }





void x_rect(Window win, int x1, int y1, int x2, int y2)

{ HPS hps = wlist[win].hps;

  MoveTo(hps,x1,YCOORD(win,y1));

  POINTL pos;

  pos.x = x2;

  pos.y = YCOORD(win,y2);

  GpiBox(hps,DRO_OUTLINE,&pos,0,0);

 }





void x_box(Window win, int x1, int y1, int x2, int y2)

{ HPS hps = wlist[win].hps;

  MoveTo(hps,x1,YCOORD(win,y1));

  POINTL pos;

  pos.x = x2;

  pos.y = YCOORD(win,y2);

  GpiBox(hps,DRO_OUTLINEFILL,&pos,0,0);

 }







void x_circle(Window win, int x, int y, int r)

{ HPS hps = wlist[win].hps;

  SetArcParams(hps,r,r);

  GpiBeginPath(hps,1L);

  MoveTo(hps,x,YCOORD(win,y));

  GpiFullArc(hps,DRO_OUTLINE,MAKEFIXED(1,0));

  GpiEndPath(hps);

  GpiStrokePath(hps,1L,0L);

}





void x_fill_circle(Window win, int x, int y, int r)

{ HPS hps = wlist[win].hps;

  SetArcParams(hps,r,r);

  MoveTo(hps,x,YCOORD(win,y));

  GpiFullArc(hps,DRO_OUTLINEFILL,MAKEFIXED(1,0));

}





void x_pixel(Window win, int x, int y)

{ POINTL p;

  p.x = x;

  p.y = YCOORD(win,y);

  GpiSetPel(wlist[win].hps,&p);

}







void x_pixels(Window win, int n, int* x, int* y)

{ while (n--) x_pixel(win,x[n],y[n]); }





void x_point(Window win, int x, int y)

{ HPS hps = wlist[win].hps;

  y = YCOORD(win,y);

  MoveTo(hps,x-2,y-2);

  LineTo(hps,x+2,y+2);

  MoveTo(hps,x-2,y+2);

  LineTo(hps,x-1,y+1);

  MoveTo(hps,x+1,y-1);

  LineTo(hps,x+2,y-2);

 }





void x_arc(Window win,int mx,int my,int r1,int r2,double start,double angle)

{ HPS hps = wlist[win].hps;

  POINTL p[3];

  p[0].x = mx + int(r1*cos(start));

  p[0].y = YCOORD(win,my + int(r1*sin(start)));

  p[1].x = mx + int(r1*cos(start+angle/2));

  p[1].y = YCOORD(win,my + int(r1*sin(start+angle/2)));

  p[2].x = mx + int(r1*cos(start+angle));

  p[2].y = YCOORD(win,my + int(r1*sin(start+angle)));

  GpiBeginPath(hps,1L);

  GpiMove(hps,p);

  GpiPointArc(hps,p+1);

  GpiEndPath(hps);

  GpiStrokePath(hps,1L,0L);

}





void x_fill_arc(Window win,int x0,int y0,int r1,int r2,double a1,double a2) {}





void x_ellipse(Window win, int x, int y, int r1, int r2)

{ HPS hps = wlist[win].hps;

  SetArcParams(hps,r1,r2);

  y = YCOORD(win,y);

  MoveTo(hps,x,y);

  GpiFullArc(hps,DRO_OUTLINE,MAKEFIXED(1,0));

}





void x_fill_ellipse(Window win, int x, int y, int r1, int r2)

{ HPS hps = wlist[win].hps;

  SetArcParams(hps,r1,r2);

  y = YCOORD(win,y);

  MoveTo(hps,x,y);

  GpiFullArc(hps,DRO_OUTLINEFILL,MAKEFIXED(1,0));

}





void x_polygon(Window win, int n, int* xcoord, int* ycoord)

{ HPS hps = wlist[win].hps;

  POINTL*  p = new POINTL[n];

  for(int i=0; i < n; i++) 

  { p[i].x = xcoord[i];

    p[i].y = YCOORD(win,ycoord[i]);

   }

  GpiBeginPath(hps,1L);

  GpiPolyLine(hps,n,p);

  GpiEndPath(hps);

  GpiStrokePath(hps,1L,0L);

}





void x_fill_polygon(Window win, int n, int* xcoord, int* ycoord)

{ HPS hps = wlist[win].hps;

  POINTL*  p = new POINTL[n];

  for(int i=0; i < n; i++) 

  { p[i].x = xcoord[i];

    p[i].y = YCOORD(win,ycoord[i]);

   }

  GpiMove(hps,p);

  GpiBeginArea(hps,BA_BOUNDARY | BA_ALTERNATE);

  GpiPolyLine(hps,n,p);

  GpiEndArea(hps);

}





void x_text(Window win, int x, int y, const char* s, int l)

{ int h = x_text_height(win,s);

  int w = x_text_width(win,s);



  if (wlist[win].TMODE == opaque)

  { int save_col = x_set_color(win,white);

    drawing_mode save_mode = x_set_mode(win,src_mode);

    x_box(win,x,y,x+w,y+h);

    x_set_color(win,save_col);

    x_set_mode(win,save_mode);

   }



  y = YCOORD(win,y);



  POINTL pos;

  pos.x = x;

  pos.y = y - wlist[win].fm.lMaxAscender;

  int len = strlen(s);

  if (len > 512) len = 512;

  if (len > l) len = l;

  GpiCharStringAt(wlist[win].hps,&pos,len, (PSZ)s);

 }

  

void x_text(Window win, int x, int y, const char* s)

{ x_text(win, x, y, s, 512); }





void x_ctext(Window win, int x, int y, const char* s)

{ int h = x_text_height(win,s);

  int w = x_text_width(win,s);

  x_text(win,x-w/2,y-h/2,s);

}



 

//------------------------------------------------------------------------------

// pixrects and bitmaps

//------------------------------------------------------------------------------



inline void SWAP(int& x1, int& x2)

{ int t = x1; x1 = x2; x2 = t; }



struct Image {

 short w;

 short h;

 HBITMAP map;

};







char* x_create_pixrect(Window win, int x1, int y1, int x2, int y2)

{ HPS hps = wlist[win].hps;

  Image* im = new Image;



  y1 = YCOORD(win,y1);

  y2 = YCOORD(win,y2);



  if (x1 > x2) SWAP(x1,x2);

  if (y1 > y2) SWAP(y1,y2);



  im->w = x2-x1+1;

  im->h = y2-y1+1;



  // create memory device context and presentation space



  HDC hdc_mem = DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 5L,(PDEVOPENDATA)&dop, 

                                                                NULLHANDLE);

  HPS hps_mem = GpiCreatePS(hab,hdc_mem,&sizel,GPIA_ASSOC|GPIT_NORMAL|PU_PELS);



  BITMAPINFOHEADER2 bmp = {16, 0, 0, 4, 1}; 

  bmp.cx = im->w;

  bmp.cy = im->h;

  im->map = GpiCreateBitmap(hps_mem, &bmp, 0L, NULL, NULL);

  GpiSetBitmap(hps_mem, im->map);



  POINTL aptl[3];

  aptl[0].x = 0;  

  aptl[0].y = 0;

  aptl[1].x = im->w-1;  

  aptl[1].y = im->h-1;

  aptl[2].x = x1; 

  aptl[2].y = y1;

  GpiBitBlt(hps_mem,hps,3,aptl,ROP_SRCCOPY,BBO_IGNORE);

  GpiDestroyPS(hps_mem);

  DevCloseDC(hdc_mem);

  return (char*)im;

}

 



void x_insert_pixrect(Window win, char* rect)

{ x_insert_pixrect(win,0,0,rect); }





void x_insert_pixrect(Window win, int x, int y, char* rect)

{ // (x,y) lower left corner !



  HPS hps = wlist[win].hps;



  HDC hdc_mem = DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 5L,(PDEVOPENDATA)&dop, 

                                                                NULLHANDLE);

  HPS hps_mem = GpiCreatePS(hab,hdc_mem,&sizel,GPIA_ASSOC|GPIT_NORMAL|PU_PELS);



  y = YCOORD(win,y);



  Image* im = (Image*)rect;

  GpiSetBitmap(hps_mem, im->map);

  POINTL aptl[4];

  aptl[0].x = x; 

  aptl[0].y = y;

  aptl[1].x = x + im->w-1; 

  aptl[1].y = y + im->h-1;

  aptl[2].x = 0; 

  aptl[2].y = 0;

  GpiBitBlt(hps,hps_mem,3,aptl,ROP_SRCCOPY,BBO_IGNORE);

  GpiDestroyPS(hps_mem);

  DevCloseDC(hdc_mem);

 }







void x_insert_pixrect(int win, int x, int y, char* rect, int x0, int y0, int x1, int y1)

{ // (x,y) lower left corner !



  HPS hps = wlist[win].hps;



  HDC hdc_mem = DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 5L,(PDEVOPENDATA)&dop, 

                                                                NULLHANDLE);

  HPS hps_mem = GpiCreatePS(hab,hdc_mem,&sizel,GPIA_ASSOC|GPIT_NORMAL|PU_PELS);



  y = YCOORD(win,y);



  if (x0 > x1) SWAP(x0,x1);

  if (y0 > y1) SWAP(y0,y1);



  Image* im = (Image*)rect;

  int wi = x1 - x0 + 1;

  int he = y1 - y0 + 1;



  GpiSetBitmap(hps_mem, im->map);

  POINTL aptl[4];

  aptl[0].x = x; 

  aptl[0].y = y;

  aptl[1].x = x + wi-1; 

  aptl[1].y = y + he-1;

  aptl[2].x = x0; 

  aptl[2].y = x0;

  GpiBitBlt(hps,hps_mem,3,aptl,ROP_SRCCOPY,BBO_IGNORE);

  GpiDestroyPS(hps_mem);

  DevCloseDC(hdc_mem);

 }









void x_delete_pixrect(char* rect)

{ Image* im = (Image*)rect;

  GpiDeleteBitmap(im->map);

 }





void x_copy_pixrect(Window win, int x1, int y1, int x2, int y2, int x, int y)

{ char* p = x_create_pixrect(win,x1,y1,x2,y2);

  x_insert_pixrect(win,x,y,p);

  x_delete_pixrect(p);

 }





static char rev_byte(char c)

{ char c1 = 0x00;

  if (c & 0x01) c1 |= 0x80;

  if (c & 0x02) c1 |= 0x40;

  if (c & 0x04) c1 |= 0x20;

  if (c & 0x08) c1 |= 0x10;

  if (c & 0x10) c1 |= 0x08;

  if (c & 0x20) c1 |= 0x04;

  if (c & 0x40) c1 |= 0x02;

  if (c & 0x80) c1 |= 0x01;

  return ~c1;

 }





char* x_create_bitmap(Window win, int w, int h, char* q)

{ HPS hps = wlist[win].hps;



  int   bw0 = (w+7)/8;

  int   bw1 = 2*((bw0+1)/2);

  char* buf = new char[bw1*h];



  for(int i=h-1; i>=0; i--)

  { char* p = buf+bw1*i;

    for(int j=0; j<bw1; j++) 

       *p++ = (j >= bw0) ? 0 : rev_byte(*q++);

   }



  Image* im = new Image;

  im->w = w;

  im->h = h;



  // create memory device context and presentation space



  HDC hdc_mem = DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 5L,(PDEVOPENDATA)&dop, 

                                                                NULLHANDLE);

  HPS hps_mem = GpiCreatePS(hab,hdc_mem,&sizel,GPIA_ASSOC|GPIT_NORMAL|PU_PELS);



  BITMAPINFOHEADER2 bmih;

  bmih.cbFix = 16;

  bmih.cx = w;

  bmih.cy = h;

  bmih.cPlanes = 1;

  bmih.cBitCount = 1;



  im->map = GpiCreateBitmap(hps_mem,&bmih,CBM_INIT,(PBYTE)buf,(BITMAPINFO2*)&bmih);

  GpiDestroyPS(hps_mem);

  DevCloseDC(hdc_mem);

  delete[] buf;

  return (char*)im;

}



char* x_create_pixrect(Window win, int w, int h, char* data, int, int)

{ return x_create_bitmap(win,w,h,data); }







char* x_create_pixrect(Window win, char** xpm) { return (char*)0; }





void x_pixrect_dimensions(char* rect, int* w, int* h)

{ if (rect)

  { Image* im = (Image*)rect;

    *w = im->w;

    *h = im->h;

   }

}







void  x_insert_bitmap(Window win, int x, int y, char* rect)

{ // (x,y) lower left corner !



  HPS hps = wlist[win].hps;



  HDC hdc_mem = DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 5L,(PDEVOPENDATA)&dop, 

                                                                NULLHANDLE);

  HPS hps_mem = GpiCreatePS(hab,hdc_mem,&sizel,GPIA_ASSOC|GPIT_NORMAL|PU_PELS);



  y = YCOORD(win,y);



  Image* im = (Image*)rect;

  GpiSetBitmap(hps_mem, im->map);

  POINTL aptl[4];

  aptl[0].x = x; 

  aptl[0].y = y;

  aptl[1].x = x + im->w; 

  aptl[1].y = y + im->h;

  aptl[2].x = 0; 

  aptl[2].y = 0;

  GpiBitBlt(hps,hps_mem,3,aptl,ROP_SRCCOPY,BBO_IGNORE);

  GpiDestroyPS(hps_mem);

  DevCloseDC(hdc_mem);

 }





void  x_delete_bitmap(char* rect)

{ Image* im = (Image*)rect;

  GpiDeleteBitmap(im->map);

 }

 





/* fonts and text */



int x_load_text_font(const char* font_name)

{ for(int w=1; w<=wcount; w++) x_set_font(w,font_name);

  return 1; 

 }



int x_load_bold_font(const char* font_name)  { return 0; }

int x_load_fixed_font(const char* font_name) { return 0; }



int x_set_font(Window win, const char* fname)  

{ 

  int scaling = 1;

  if (fname[0] >= '1' && fname[0] <= '9') 

     scaling = fname[0] - '0';



  HPS hps = wlist[win].hps;

  TextFattrs.lMaxBaselineExt = 3*scaling;

  GpiCreateLogFont(hps,(PSTR8)NULL,USER_FONT_ID,&TextFattrs);

  GpiSetCharSet(hps,USER_FONT_ID);

  GpiQueryFontMetrics(hps,sizeof(FONTMETRICS),&wlist[win].fm);

  return 1; 

 }





void x_set_text_font(Window win)

{ HPS hps = wlist[win].hps;

  GpiCreateLogFont(hps,(PSTR8)NULL,TEXT_FONT_ID,&TextFattrs);

  GpiSetCharSet(hps,TEXT_FONT_ID);

  GpiQueryFontMetrics(hps,sizeof(FONTMETRICS),&wlist[win].fm);

}





void x_set_bold_font(Window win)

{ HPS hps = wlist[win].hps;

  GpiCreateLogFont(hps,(PSTR8)NULL,BOLD_FONT_ID,&BoldFattrs);

  GpiSetCharSet(hps,BOLD_FONT_ID);

  GpiQueryFontMetrics(hps,sizeof(FONTMETRICS),&wlist[win].fm);

}





void x_set_fixed_font(Window win)

{ HPS hps = wlist[win].hps;

  GpiCreateLogFont(hps,(PSTR8)NULL,TEXT_FONT_ID,&TextFattrs);

  GpiSetCharSet(hps,TEXT_FONT_ID);

  GpiQueryFontMetrics(hps,sizeof(FONTMETRICS),&wlist[win].fm);

}



int x_text_width(Window win,const char* s)

{ return x_text_width(win,s,strlen(s)); }



int x_text_width(Window win,const char* s, int l)

{ if (l > strlen(s)) l = strlen(s);

  if (!wlist[win].hwnd)

     return  l * wlist[0].fm.lAveCharWidth;

  HPS hps = wlist[win].hps;

  POINTL ptl[TXTBOX_COUNT+1];

  GpiQueryTextBox(hps,l,(PCH)s,TXTBOX_COUNT,ptl);

  return ptl[TXTBOX_TOPRIGHT].x - ptl[TXTBOX_BOTTOMLEFT].x; 

 }





int x_text_height(Window win,const char* s) 

{ if (!wlist[win].hwnd)

     return wlist[0].fm.lMaxBaselineExt;  

  HPS hps = wlist[win].hps;

  POINTL ptl[TXTBOX_COUNT+1];

  GpiQueryTextBox(hps,strlen(s),(PCH)s,TXTBOX_COUNT,ptl);

  return ptl[TXTBOX_TOPRIGHT].y - ptl[TXTBOX_BOTTOMLEFT].y; 

 }

 





/* drawing parameters */



int x_set_color(Window win, int col) 

{ int c = wlist[win].COLOR;

  if (c!=col)

  { GpiSetColor(wlist[win].hps,col); 

    wlist[win].COLOR = col;

   }

  return c;

 }





drawing_mode x_set_mode(Window win, drawing_mode mod) 

{ drawing_mode m = wlist[win].MODE;

  if (m != mod)

  { HPS hps = wlist[win].hps;

    if (hps) GpiSetMix(hps,mode_table[mod]); 

    wlist[win].MODE = mod;

   }

  return m;

 }





int x_set_line_width(Window win, int w) 

{ int lw = wlist[win].LWIDTH;

  if (lw != w)

  { HPS hps = wlist[win].hps;

    if (hps) GpiSetLineWidthGeom(hps,w); 

    wlist[win].LWIDTH = w;

   }

  return lw;

 }





line_style x_set_line_style(Window win, line_style s)

{ line_style ls = wlist[win].LSTYLE;

  if (ls != s)

  { HPS hps = wlist[win].hps;

    if (hps) GpiSetLineType(hps,lstyle_table[s]);

    wlist[win].LSTYLE = s;

   }

  return ls;

 }





text_mode x_set_text_mode(Window win, text_mode tm) 

{ text_mode save = wlist[win].TMODE;

  wlist[win].TMODE = tm;  

  return save;

 }



int x_set_join_style(Window win, int js) 

{ int save = wlist[win].JSTYLE;

  wlist[win].JSTYLE = js;  

  return save;

 }







int           x_get_color(Window win)      { return wlist[win].COLOR;  }

drawing_mode  x_get_mode(Window win)       { return wlist[win].MODE;   }

int           x_get_line_width(Window win) { return wlist[win].LWIDTH; }

line_style    x_get_line_style(Window win) { return wlist[win].LSTYLE; }

text_mode     x_get_text_mode(Window win)  { return wlist[win].TMODE;  }





void x_set_read_gc(Window win)

{ HPS hps = wlist[win].hps;

  GpiSetMix(hps,mode_table[xor_mode]);

  GpiSetColor(hps,black);

  GpiSetLineType(hps,lstyle_table[solid]);

  GpiSetLineWidthGeom(hps,1);

 }



void x_reset_gc(Window win)

{ HPS hps = wlist[win].hps;

  GpiSetMix(hps,mode_table[wlist[win].MODE]);

  GpiSetColor(hps,wlist[win].COLOR);

  GpiSetLineType(hps,lstyle_table[wlist[win].LSTYLE]);

  GpiSetLineWidthGeom(hps,wlist[win].LWIDTH);

 }









/* colors */



void x_set_palette(int i, int r, int g, int b)

{ unsigned char R = (unsigned char)r;

  unsigned char G = (unsigned char)g;

  unsigned char B = (unsigned char)b;

  rgb_table[2*i+1] = LONGFromRGB(R,G,B);

  for(int win=1; win<=wcount; win++)

    GpiCreateLogColorTable(wlist[win].hps,LCOL_PURECOLOR,

                                              LCOLF_INDRGB,0L,32L,rgb_table);

}

 



void x_get_palette(int i, int* red, int* green, int* blue)

{ LONG rgb = rgb_table[i];

  *blue  =  rgb        & 0xFF; 

  *green = (rgb >>  8) & 0xFF;

  *red   = (rgb >> 16) & 0xFF;

 }





int x_new_color(const char*) { return black; }

int x_new_color(int,int,int) { return black; }





/* events */



static QMSG qmsg;

static int putback = 0;

static event last_event;





int x_get_next_event(Window* win, int* val, int* x, int* y, unsigned long *t,

                                                            int msec)

{ // get next event with timeout

  // not implemented

  return x_get_next_event(win,val,x,y,t);

}



int x_get_next_event(Window* win, int* val, int* x, int* y, unsigned long *t)

{ 

  if (putback) 

   { cur_event = last_event;

     putback = 0;

    }

  else

    { cur_event.kind = no_event;

      if (WinGetMsg (hab, &qmsg, 0L, 0, 0))

         WinDispatchMsg (hab, &qmsg);

      else

         exit(0);

      if (cur_event.kind != exposure_event)

         cur_event.t = qmsg.time;

      if (cur_event.kind != no_event) 

          last_event = cur_event;

     } 



  *win = cur_event.win;

  *val = cur_event.val;

  *x   = cur_event.x;

  *y   = cur_event.y;

  *t   = cur_event.t;

  return cur_event.kind;

 }





int x_check_next_event(Window* win, int* val, int* x, int* y, unsigned long *t)

{ 

  if (putback || WinPeekMsg(hab, &qmsg, 0L, 0, 0, PM_NOREMOVE))

     return x_get_next_event(win,val,x,y,t); 

  else

     return no_event;

 }



void x_put_back_event(void) {  putback = 1; }







// not implemented



int x_get_pixel(Window, int, int) 

{ return 0; }



void x_start_timer(Window win, int msec)

{ /* not implemented */ }



void x_stop_timer(Window win)

{ /* not implemented */ }



void x_set_border_width(Window, int) 

{ /* not implemented */ }



void x_grab_pointer(Window) 

{ /* not implemented */ }



void x_ungrab_pointer() 

{ /* not implemented */ }



void x_set_icon_pixmap(Window,char*)

{ /* not implemented */ }



void x_window_to_screen(Window,int*,int*)

{ /* not implemented */ }



void x_screen_to_window(Window,int*,int*)

{ /* not implemented */ }



