
#include "win-graph.h"

#include "gtv/xsub.h"
#include "gcore/glaunch.h"
#include "gcore/gcomm.h"
#include "gsys/sic_util.h"
#include "gtv/gtv-message-c.h"
#include "win-greg.h"
#include "gcore/rgb_hsv.h"

#include <commctrl.h>

#define VERSION "$Revision$ $Date$"

#define NB_COLORS 128
#define NFIRST    20
#define NCVAR     8
#define NPEN      16
#define COLOFFSET (NFIRST+NTAB)
#define NDASH     5
#define NWEIGHT   5
#define NSTYLE    5
#define max_intensity 255
#define CTRLZONE(x, y) ((x >= 0) && (x <= L) && (y >= 0) && (y <= L))
#define  BUTTONDOWN (MK_LBUTTON || MK_MBUTTON || MK_RBUTTON)

#define flag_static_display 0

typedef unsigned char Byte;

typedef struct _gwinenv {
    G_env _herit;
	HWND	win_graph;
	HANDLE hThread;  // thread associated to the window
	int IsPaint;
	int IsResized;
    int PrimaryWindow;
	HDC		myGC;
	int		plume_cour;
	HBITMAP	vertical,horizontal;
	HBITMAP	box1,box2,box3,box4;

	unsigned	win_col_size;  /* size of RGB map */
	PALETTEENTRY *win_color;    /* color values in X style */
} G_win_env;

static G_win_env *s_win_env_cour = NULL;

//HBITMAP colHbm[NTAB];
HBITMAP dashHbm[NDASH]; 
HBITMAP weightHbm[NWEIGHT];
HBITMAP styleHbm[NSTYLE];
int Width_graphique, Height_graphique;
HWND hsvwnd[4];
HPEN WhitePen;
HBRUSH WhiteBrush, BlackBrush;

int reverseon;
int ncolors = NB_COLORS;
int L = NB_COLORS - 1;
POINT huepoints[NB_COLORS], satpoints[NB_COLORS], valpoints[NB_COLORS];
float hue[NB_COLORS], hp[NB_COLORS], sat[NB_COLORS], val[NB_COLORS];
float red[NB_COLORS], green[NB_COLORS], blue[NB_COLORS];
int lowbound = 0;
int highbound = 360;

/* flag_cross = TRUE for a large crosshair
                FALSE for a small crosshair*/
static int flag_cross;
static int mode_dithering;
static int flag_color_display;

static int Height_default,Width_default;

static POINT tabpts[1024];
static HPEN hpen[NTAB];
static HBRUSH hbrush[NTAB];

int flag_backingstore;
int palette_disabled;

UINT depth, cplanes;
int X_ancrage,Y_ancrage;
BYTE peRed[256], peGreen[256], peBlue[256];
LPLOGPALETTE     plogPal;
HPALETTE        hPal, hOldPal;
int npts;
int save_pen;
PALETTEENTRY systemcolors[NFIRST];
char testlut[NB_COLORS];

typedef struct {
    HANDLE handle;
    int x0;
    int y0;
    int width;
    int height;
    Byte *data;
} dib_t;
#ifdef _GTV_USE_DIBS
#define MAX_DIB 1024
static dib_t dibs[MAX_DIB];
static int dibs_count = 0;
#endif

#define CLASSNAME "GRAPHIC device" 
#define DIALOGNAME "DIALOG" 

HINSTANCE hInst; // current instance
HMENU hSubMenu1;
char BlackDev[] = "BlackDev"; 
char WhiteDev[] = "WhiteDev"; 
char ClassName[] = CLASSNAME; 
char DialogName[] = DIALOGNAME; 
HWND win_graph;
char window_name[257];

#define X_TAB     20
#define Y_TAB     20
#define XDASH    60
#define Y_DASH    20
#define X_WEIGHT  60
#define Y_WEIGHT  20
#define X_STYLE   64
#define Y_STYLE   64

static POINT s_rect[] = {{5, 5}, {54, 5}, {54, 54}, {5, 54}, {5, 5}};
POINT star[] = {{32, 5}, {40, 24}, {60, 32}, {40, 40},
{32, 60}, {24, 40}, {5, 32}, {24, 24}, {32, 5}};
HBITMAP colHbm[NTAB];
HWND mainwnd=NULL;

/* Macro to determine the number of bytes in a DWORD aligned DIB scanline */
#define BYTESPERLINE(Width, BPP) ((WORD)((((DWORD)(Width) * (DWORD)(BPP) + 31) >> 5)) << 2)

#define MAKE565WORD(r,g,b) ((((WORD)(r) >> 3) << 11) | (((WORD)(g) >> 2) << 5)  | ((WORD)(b) >> 3))    

#define NEW_DIB_FORMAT(lpbih) (lpbih->biSize != sizeof(BITMAPCOREHEADER))

/******************************************************************************
*                                                                            *
*  FUNCTION   : HANDLE CreateRGBDIB(DWORD dwWidth, DWORD dwHeight,           *
*                                    WORD wBPP, DWORD dwComp);               *
*                                                                            *
*  PURPOSE    : Returns a handle to a RGB DIB (no color table) with the      *
*               specified width, height, bits per pixel, and compression.    *
*                                                                            *
*****************************************************************************/
HANDLE CreateRGBDIB(DWORD dwWidth, DWORD dwHeight, WORD wBPP, DWORD dwComp)
{
    HANDLE hDIB;
    LPBITMAPINFOHEADER lpbih;
    DWORD dwSize;
    LPDWORD lpMasks;

    /* We cant support compression so check to see if that's what is being asked for */
    if ((dwComp == BI_RLE8) || (dwComp == BI_RLE4)) return NULL;

    /* Allocate enough memory to hold the DIB */
    switch (wBPP) {
    case  8: dwSize = ((DWORD)BYTESPERLINE(dwWidth, 8) * dwHeight) + sizeof(RGBQUAD) * 256; break;
    case 16: dwSize = ((dwWidth + (dwWidth & 1)) << 1) * dwHeight; break;
    case 24: dwSize = (DWORD)BYTESPERLINE(dwWidth, 24) * dwHeight; break;
    case 32: dwSize = ((dwWidth * dwHeight) << 2); break;
    default: return NULL;
    }                                               

    if (dwComp == BI_BITFIELDS) /* Add in space for DWORD masks */
        hDIB = GlobalAlloc(GPTR, (DWORD)sizeof(BITMAPINFOHEADER) + (sizeof(DWORD) * 3) + dwSize);
    else
        hDIB = GlobalAlloc(GPTR, (DWORD)sizeof(BITMAPINFOHEADER) + dwSize);

    if (!hDIB)
        return NULL;

    lpbih = (LPBITMAPINFOHEADER)hDIB;
    lpbih->biSize         = sizeof(BITMAPINFOHEADER);
    lpbih->biWidth        = dwWidth;
    // revert y axis
    lpbih->biHeight       = -(LONG)dwHeight;
    lpbih->biPlanes       = 1;
    lpbih->biBitCount     = wBPP;
    lpbih->biCompression  = dwComp;    
    lpbih->biSizeImage    = ((DWORD)BYTESPERLINE(dwWidth, wBPP) * dwHeight); 

    lpMasks = (LPDWORD)((LPSTR)lpbih + (WORD)lpbih->biSize);

    if (dwComp == BI_BITFIELDS) 
        if (wBPP == 16) {
            lpMasks[0] = MAKE565WORD(0xff, 0, 0);
            lpMasks[1] = MAKE565WORD(0, 0xff, 0);
            lpMasks[2] = MAKE565WORD(0, 0, 0xff);
        } else if (wBPP == 32) {
            lpMasks[0] = 0xff0000;
            lpMasks[1] = 0x00ff00;
            lpMasks[2] = 0x0000ff;
        }

        return hDIB;
}

/******************************************************************************
*                                                                            *
*  FUNCTION   : DIBNumColors(LPVOID lpv)                                     *
*                                                                            *
*  PURPOSE    : Determines the number of colors in the DIB by looking at     *
*               the BitCount and ClrUsed fields in the info block.           *
*                                                                            *
*  RETURNS    : The number of colors in the DIB. With DIBS with more than    *
*               8-bits-per-pixel that have a color table table included,     *
*               then the return value will be the number of colors in the    *
*               color table rather than the number of colors in the DIB.     *
*                                                                            *
*                                                                            *
*****************************************************************************/
WORD DIBNumColors (LPVOID lpv)
{
    INT                 bits;
    LPBITMAPINFOHEADER  lpbih = (LPBITMAPINFOHEADER)lpv;
    LPBITMAPCOREHEADER  lpbch = (LPBITMAPCOREHEADER)lpv;

    /*  With the BITMAPINFO format headers, the size of the palette
    *  is in biClrUsed, whereas in the BITMAPCORE - style headers, it
    *  is dependent on the bits per pixel ( = 2 raised to the power of
    *  bits/pixel).
    */
    if (NEW_DIB_FORMAT(lpbih)) {
        if (lpbih->biClrUsed != 0)
            return (WORD)lpbih->biClrUsed;
        bits = lpbih->biBitCount;
    }
    else
        bits = lpbch->bcBitCount;

    if (bits > 8) 
        return 0; /* Since biClrUsed is 0, we dont have a an optimal palette */
    else
        return (1 << bits); 
}

/******************************************************************************
*                                                                            *
*  FUNCTION   :  ColorTableSize(LPVOID lpv)                                  *
*                                                                            *
*  PURPOSE    :  Calculates the palette size in bytes. If the info. block    *
*                is of the BITMAPCOREHEADER type, the number of colors is    *
*                multiplied by 3 to give the palette size, otherwise the     *
*                number of colors is multiplied by 4.                        *
*                                                                            *
*  RETURNS    :  Color table size in number of bytes.                        *
*                                                                            *
*****************************************************************************/
WORD ColorTableSize (LPVOID lpv)
{
    LPBITMAPINFOHEADER lpbih = (LPBITMAPINFOHEADER)lpv;

    if (NEW_DIB_FORMAT(lpbih))
    {
        if (((LPBITMAPINFOHEADER)(lpbih))->biCompression == BI_BITFIELDS)
            /* Remember that 16/32bpp dibs can still have a color table */
            return (sizeof(DWORD) * 3) + (DIBNumColors (lpbih) * sizeof (RGBQUAD));
        else
            return (DIBNumColors (lpbih) * sizeof (RGBQUAD));
    }
    else
        return (DIBNumColors (lpbih) * sizeof (RGBTRIPLE));
}

/******************************************************************************
*                                                                            *
*  FUNCTION   : GetDIBPointers(HANDLE hDIB, LPVOID *biPtr,                   *
*                                     LPVOID *rgbqPtr, LPVOID *bmPtr)        *
*                                                                            *
*  PURPOSE    : Given a handle to a DIB in CF_DIB format, this function will *
*               retrieve pointers for the bitmap info, color table, and bits *
*                                                                            *
*****************************************************************************/
BOOL GetDIBPointers(HANDLE hDIB, LPVOID *biPtr, LPVOID *rgbqPtr, LPVOID *bmPtr)
{  
    LPBITMAPINFO pbi;

    pbi = (LPBITMAPINFO)hDIB;  

    if (!pbi)
        return FALSE;

    *biPtr   = (LPVOID)pbi;

    *rgbqPtr = (LPVOID)((LPSTR)pbi + (WORD)((LPBITMAPINFOHEADER)pbi)->biSize);
    if (((LPBITMAPINFOHEADER)pbi)->biCompression == BI_BITFIELDS)
        rgbqPtr = (LPVOID)((LPDWORD)rgbqPtr + 3); 

    *bmPtr   = (LPBYTE)pbi + (WORD)pbi->bmiHeader.biSize + ColorTableSize(pbi); 

    return TRUE;
}

/******************************************************************************
*                                                                            *
*  FUNCTION   : DIBBlt( HDC hDC,                                             *
*                       int x0, int y0,                                      *
*                       int dx, int dy,                                      *
*                       HANDLE hDIB,                                         *
*                       int x1, int y1,                                      *
*                       LONG dwROP)                                          *
*                                                                            *
*  PURPOSE    : Draws a bitmap in CF_DIB format, using SetDIBits to device.  *
*               taking the same parameters as BitBlt().                      *
*                                                                            *
*  RETURNS    : TRUE  - if function succeeds.                                *
*               FALSE - otherwise.                                           *
*                                                                            *
******************************************************************************/
BOOL DIBBlt (HDC hDC,     INT x0, INT y0, INT dx, INT dy, 
             HANDLE hDIB, INT x1, INT y1, LONG  dwROP)
{
    LPBITMAPINFOHEADER   lpbih;
    LPSTR                pBuf;

    if (!hDIB)
        return PatBlt(hDC, x0, y0, dx, dy, dwROP);

    lpbih = (LPBITMAPINFOHEADER)hDIB;

    if (!lpbih)
        return FALSE;

    pBuf = (LPSTR)lpbih + (WORD)lpbih->biSize + ColorTableSize(lpbih);
    SetDIBitsToDevice (hDC, x0, y0, dx, dy, 
        x1, y1, 
        x1, 
        dy, 
        pBuf, (LPBITMAPINFO)lpbih, 
        DIB_RGB_COLORS );

    return TRUE;
}

void update_dib( dib_t *dib)
{
    int i;
    int size;
    LPBITMAPINFOHEADER biDstPtr;
    LPRGBQUAD rgbqDstPtr; 
    LPRGBQUAD bmDstPtr;

    if (dib->handle == NULL || !GetDIBPointers( dib->handle, &biDstPtr, &rgbqDstPtr, &bmDstPtr))
        return;

    size = dib->width * dib->height;
    for (i = 0; i < size; i++) {
        Byte index = dib->data[i] - COLOFFSET;
        bmDstPtr[i].rgbRed = s_win_env_cour->win_color[index].peRed;
        bmDstPtr[i].rgbGreen = s_win_env_cour->win_color[index].peGreen;
        bmDstPtr[i].rgbBlue = s_win_env_cour->win_color[index].peBlue;
    }
}

static int s_create_dib_calls = 0;

dib_t *create_dib( Byte *sdata, int x0, int y0, int width, int height)
{
    dib_t *dib;

    if (s_create_dib_calls)
        return NULL;
    s_create_dib_calls++;

#ifdef _GTV_USE_DIBS
    if (dibs_count == MAX_DIB)
        return NULL;
    dib = &dibs[dibs_count++];
#else
    {
        static dib_t s_dib;
        dib = &s_dib;
    }
#endif

    dib->data = sdata;
    dib->x0 = x0;
    dib->y0 = y0;
    dib->width = width;
    dib->height = height;

    /* Create destination DIB and initialize pointers for it */
    dib->handle = CreateRGBDIB( dib->width, dib->height, 32, BI_RGB);

    update_dib( dib);

    s_create_dib_calls--;

    return dib;
}

void draw_dib( dib_t *dib)
{
    if (dib == NULL || dib->handle == NULL)
        return;
    DIBBlt( s_win_env_cour->myGC, dib->x0, dib->y0, 
        dib->width, dib->height, dib->handle, 0, 0, SRCCOPY);
}

void clear_dibs( )
{
#ifdef _GTV_USE_DIBS
    int i;

    for (i = 0; i < dibs_count; i++) {
        if (dibs[i].handle != NULL) {
            GlobalFree( dibs[i].handle);
            dibs[i].handle = NULL;
        }
    }
    dibs_count = 0;
#endif
}

void update_dibs( )
{
#ifdef _GTV_USE_DIBS
    int i;

    for (i = 0; i < dibs_count; i++) {
        update_dib( dibs + i);
    }
#endif
}

void draw_dibs( )
{
#ifdef _GTV_USE_DIBS
    int i;

    for (i = 0; i < dibs_count; i++) {
        draw_dib( dibs + i);
    }
#endif
}

void win_create_edit_lut_window(void)
{ 
    return;
}

static PALETTEENTRY  tabcolor[NTAB];
/* Nombre de couleurs modifiables des plumes */
static unsigned pen_ncol;
static unsigned pen_col_size;  /* size of RGB map */

COLORREF palette_index( int index)
{
    if (palette_disabled) {
        PALETTEENTRY *c;
        if (index < NFIRST) {
            c = systemcolors + index;
        } else if (index < COLOFFSET) {
            c = tabcolor + index - NFIRST;
        } else {
            c = s_win_env_cour->win_color + index - COLOFFSET;
        }
        return RGB( c->peRed, c->peGreen, c->peBlue); 
    } else {
        return PALETTEINDEX( index);
    }
}

void ClearWindow(G_win_env *env)
{
    HBRUSH OldBrush;
    if (env->_herit.win_backg) OldBrush = SelectObject(env->myGC, WhiteBrush);
    else OldBrush = SelectObject(env->myGC, BlackBrush);
    PatBlt(env->myGC, 0, 0, 
        env->_herit.Width_graphique, env->_herit.Height_graphique, PATCOPY);
    SelectObject(env->myGC, OldBrush); 
}

void refresh( G_win_env *env, int clear)
{
    if (s_create_dib_calls)
        return;
#ifdef _GTV_USE_DIBS
    draw_dibs( ); /* draw only images */
#else
    if (clear) {
        ClearWindow( env);
    }
    {
        extern void CFC_API gtvue(int[2]);
        G_env *old;
        old = set_graph_env( (G_env *)env);
        gtvue( env->_herit.adr_dir);
        set_graph_env( old);
    }
#endif
}

// Installation de la palette privee
// Ne marche correctement que si la fenetre qui installe sa palette a le focus
void MySelectPalette()
{
    if (palette_disabled)
        return;

    SelectPalette(s_win_env_cour->myGC, hOldPal, 0);
    UnrealizeObject(hPal);
    SelectPalette (s_win_env_cour->myGC, hPal, 0);
    RealizePalette (s_win_env_cour->myGC);
}

void set_colors()
{
    if (palette_disabled)
        return;

    SetPaletteEntries(hPal, COLOFFSET, s_win_env_cour->win_col_size, s_win_env_cour->win_color);
    MySelectPalette();
}

void win_pen_colors( void)
{
    if (palette_disabled)
        return;
    SetPaletteEntries(hPal, NFIRST, NTAB, tabcolor); 
}

void pen_colors1() {
    HWND hwndDesktop;
    HDC hdcDesktop,hdcMem;
    int i;
    PALETTEENTRY *color;	

    if (!palette_disabled) {
        SetPaletteEntries(hPal, NFIRST, NTAB, tabcolor); 
        MySelectPalette();
    }
    hwndDesktop = GetDesktopWindow(); 
    hdcDesktop = GetDC(hwndDesktop); 
    hdcMem = CreateCompatibleDC(hdcDesktop); 	
    if (!palette_disabled)
        SelectPalette (hdcMem, hPal, 0);
    color=tabcolor+NCVAR;
    for (i=0; i<NPEN; i++) {
        hbrush[i+NCVAR] = CreateSolidBrush(palette_index( i+NFIRST+NCVAR));
        hpen[i+NCVAR] = CreatePen(PS_SOLID, 0, palette_index( i+NFIRST+NCVAR));
        SelectObject(hdcMem, hbrush[i+NCVAR]); 
        colHbm[i+NCVAR] = CreateCompatibleBitmap(hdcDesktop, X_TAB, Y_TAB);
        SelectObject(hdcMem, colHbm[i+NCVAR]); 
        PatBlt(hdcMem, 0, 0, X_TAB, Y_TAB, PATCOPY);
        color++;
    } 
    for (i = 0; i < NPEN; i++)
        ModifyMenu(hSubMenu1, i+NCVAR, MF_BYPOSITION|MF_BITMAP,
        200+NCVAR+i, (LPCTSTR) colHbm[i+NCVAR]);

    DeleteDC(hdcMem); 
    ReleaseDC(hwndDesktop, hdcDesktop); 
}

/* ---------------------------------------------------------
 */

G_env *win_creer_genv(void)
{
    G_win_env *env;

    if((env=(G_win_env *)calloc(1,sizeof(G_win_env)))!=0)
    {
        unsigned size=s_win_env_cour ? s_win_env_cour->win_col_size : NB_COLORS;

        if(!(env->win_color=(PALETTEENTRY *)malloc(sizeof(PALETTEENTRY)*size)))
            return NULL;
        /* il existe deja une fenetre, on reprends alors les donnees de window_colors */
        env->win_col_size=size;
        if(s_win_env_cour) {
            memcpy(env->win_color,s_win_env_cour->win_color,sizeof(PALETTEENTRY)*size);
            /* recupere les infos globales */
            env->_herit.widthofscreen = s_win_env_cour->_herit.widthofscreen;
            env->_herit.heightofscreen = s_win_env_cour->_herit.heightofscreen;
            env->PrimaryWindow = 0;
        } else {
            env->PrimaryWindow = 1;
        }
    }
    return (G_env *)env;
}

void win_on_set_genv( G_env *_env)
{
    G_win_env *env = (G_win_env *)_env;
    if (s_win_env_cour == env)
        return;
    s_win_env_cour = env;
    clear_dibs( );
    if (env == NULL)
        return;
    SelectObject(env->myGC, hpen[env->plume_cour]);
    SelectObject(env->myGC, hbrush[env->plume_cour]);
    set_colors();
}

void win_on_free_genv( G_env *_env)
{
    HWND tmp;
    G_win_env *env = (G_win_env *)_env;

    ReleaseDC( env->win_graph, env->myGC);
    tmp = env->win_graph;
    env->win_graph = 0;
    SendMessage( tmp, WM_CLOSE, 0, 0);
    free(env->win_color);
    if (flag_cross) {
        DeleteObject( env->horizontal);
        DeleteObject( env->vertical);
    }
    DeleteObject( env->box1);
    DeleteObject( env->box2);
    DeleteObject( env->box3);
    DeleteObject( env->box4);
	//TerminateThread(env->hThread, 0);
}

void win_refresh_window( G_env *env)
{
    InvalidateRect( ((G_win_env *)env)->win_graph, NULL, FALSE);
}

void win_move_window( G_env *env, int x, int y)
{
    SetWindowPos( ((G_win_env *)env)->win_graph, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}

void win_clear_window( G_env *env)
{
    ClearWindow( (G_win_env *)env);
}

void win_get_corners( G_env *env, int x[3], int y[3])
{
    int largeur, hauteur;

    largeur = env->widthofscreen - env->Width_graphique;
    hauteur = env->heightofscreen - env->Height_graphique;
    x[0] = 10;
    x[1] = largeur>>1;
    x[2] = largeur-10;
    y[2] = 25;
    y[1] = hauteur>>1;
    y[0] = hauteur-10;
}

int win_get_image_width( int x)
{
    return x;
}

/* ---------------------------------------------------------
 */

void win_x_close(void)
{
    int error=0;
    clear_dibs( );
    gtv_destroy_all( &error );
}

void win_x_pen_invert()
{
    gtv_c_message(seve_f, "WIN_X_PEN_INVERT", "Not implemented");
}

void draw_dialog_palette( )
{
    PAINTSTRUCT ps;
    HBRUSH hbrushOld;
    int k;

    InvalidateRect( hsvwnd[3], NULL, FALSE);
    BeginPaint( hsvwnd[3], &ps);
    for (k = 0; k < NB_COLORS; k++) {
        hbrushOld = SelectObject( ps.hdc, CreateSolidBrush( palette_index( k + COLOFFSET))); 
        PatBlt( ps.hdc, 3*k, 0, 3, 28, PATCOPY); 
        DeleteObject( SelectObject(ps.hdc, hbrushOld));
    }
    EndPaint( hsvwnd[3], &ps);
}

// Modification dynamique des entrees de la palette 
void activate()
{

    int k;

    for (k = 0; k<ncolors; k++) {
        PALETTEENTRY *c = s_win_env_cour->win_color + k;
        c->peRed=(unsigned char) (255*red[k]); 
        c->peGreen=(unsigned char) (255*green[k]); 
        c->peBlue=(unsigned char) (255*blue[k]);
    }
    if (palette_disabled) {
        draw_dialog_palette( );
#if 1
        InvalidateRect( s_win_env_cour->win_graph, NULL, FALSE);
#else
        /* draw only images */
        update_dibs( );
        draw_dibs( );
#endif
    } else {
        AnimatePalette(hPal, COLOFFSET, s_win_env_cour->win_col_size, s_win_env_cour->win_color);
    }
}

// Actualize the R,G,B values in the Sic Process Address space
void send_lut_to_main_task()
{
    int i;
    FILE *fd;
    char dum[256];

    fd = fopen(testlut, "w");
    for (i=0; i<NB_COLORS; i++)
        fprintf(fd, "%f %f %f\n", red[i], green[i], blue[i]);
    fclose(fd);
    sprintf(dum, "%s%s%s", "GTVL\\LUT \"",  testlut, "\"");
    sic_post_command_text(dum);
}


// initialisation des tableaux hue, saturation, value & red, green, blue
void init_hsv_rgb()
{
    int i;
    float t;

    for (i = 0; i < ncolors; i++) {
        huepoints[i].x = satpoints[i].x = valpoints[i].x = i;
        t = (float) i/L;
        hp[i] = t;
        huepoints[i].y = (long) (L*((float)1.-t));
        satpoints[i].y = valpoints[i].y = 0;
        hue[i] = (float)360.*t;
        val[i] = sat[i] = (float)1.;
    }

    for (i=0; i<ncolors; i++)
        hsv_to_rgb(&hue[i], &sat[i], &val[i], &red[i], &green[i], &blue[i]);
    activate();
}

// trace des fonctions de transfert hue, saturation, value
void trace_fct(HWND hwnd, int x, int y)
{
    int k;
    float i, j, orig, f;
    float t, offset;
    HDC hDC;

    i = (float) x/ncolors;

    if (!reverseon)
        j = (float)1. - i;
    else 
        j = (float)-1. + i;


    orig= ((float)1. - i/j)*(float)0.5;		  

    for (k=0; k<ncolors; k++) {
        t = (float) k/L;

        if (!reverseon)
            offset = ((i/j) + (float)1.)*((float) (L - y)/L) - ((i/j) + orig);
        else
            offset = ((float)1. - (i/j))*((float) (L - y)/L) - orig;

        f = (i/j)*t + orig + offset;

        if (f < (float)0.) f = (float)0.;
        else if (f > 1.) f = (float)1.;

        hDC = GetDC(hwnd);
        PatBlt(hDC, 0, 0, ncolors, ncolors, PATCOPY);
        if (hwnd == hsvwnd[0]) {
            huepoints[k].y = (long) (L*((float)1.-f));
            hp[k] = f;
            hue[k] = (float) (lowbound) + hp[k]*(highbound-lowbound);
        }
        else if (hwnd == hsvwnd[1]) {
            satpoints[k].y = (long) (L*((float)1.-f));
            sat[k] = f;
        }
        else {
            valpoints[k].y = (long) (L*((float)1.-f));
            val[k] = f;
        }
        hsv_to_rgb(&hue[k], &sat[k], &val[k], &red[k], &green[k], &blue[k]);
    }

    activate( );

    if (hwnd == hsvwnd[0]) Polyline(hDC, huepoints, ncolors);
    else if (hwnd == hsvwnd[1]) Polyline(hDC, satpoints, ncolors);
    else Polyline(hDC, valpoints, ncolors);

}

// reinitialisation des fonctions de transfert hue, saturation, value
void reset(HWND hwnd)
{
    int k;
    float t;
    HDC hDC;

    for (k = 0; k<ncolors; k++) {
        if (hwnd == hsvwnd[0]) {
            t = (float) k/L;
            huepoints[k].y = (long) (L*((float)1.-t));
            hp[k] = t;
            hue[k] = (float) (lowbound) + hp[k]*(highbound-lowbound);
        }
        else if (hwnd == hsvwnd[1]) {
            satpoints[k].y = 0;
            sat[k] = (float)1.;
        }
        else {
            valpoints[k].y = 0;
            val[k] = (float)1.;
        }

        hsv_to_rgb(&hue[k], &sat[k], &val[k], &red[k], &green[k], &blue[k]);
    }
    activate();
    hDC = GetDC(hwnd);
    PatBlt(hDC, 0, 0, ncolors, ncolors, PATCOPY);

    if (hwnd == hsvwnd[0]) Polyline(hDC, huepoints, ncolors);
    else if (hwnd == hsvwnd[1]) Polyline(hDC, satpoints, ncolors);
    else Polyline(hDC, valpoints, ncolors);
}

// Fonction de reception des messages de la boite de controle des parametres H,S,V
LONG APIENTRY HsvdrawWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static int ncreate=0;
    PAINTSTRUCT ps;
    HDC hDC;
    int x, y;

    switch (message) {
    case WM_LBUTTONDOWN:
        if (hwnd == hsvwnd[3]) return 0;
        reverseon = 0;
        SetCapture(hwnd);
        x = LOWORD(lParam);
        y = HIWORD(lParam);
        trace_fct(hwnd, x, y);
        return 0;
    case WM_LBUTTONUP:
    case WM_MBUTTONUP:
        ReleaseCapture();
        return 0;
    case WM_MBUTTONDOWN:
        if (hwnd == hsvwnd[3]) return 0;
        reverseon = 1;
        SetCapture(hwnd);
        x = LOWORD(lParam);
        y = HIWORD(lParam);
        trace_fct(hwnd, x, y);
        return 0;
    case WM_RBUTTONDOWN:
        reset(hwnd);
        return 0;
    case WM_MOUSEMOVE:
        if (hwnd == hsvwnd[3]) return 0;
        x = LOWORD(lParam);
        y = HIWORD(lParam);
        if (!CTRLZONE(x, y)) return 0;
        switch(wParam) {
        case MK_LBUTTON:
            reverseon = 0;
            break;
        case MK_MBUTTON:
            reverseon = 1;
            break;
        default:
            return 0;
        }
        trace_fct(hwnd, x, y);
        return 0;
    case WM_PAINT:
        //printf("hsvwnd %d\n", hwnd);
        if (hwnd == hsvwnd[3]) {
            draw_dialog_palette( );
        } else {
            BeginPaint(hwnd, &ps);
            SelectObject(ps.hdc, BlackBrush);
            PatBlt(ps.hdc, 0, 0, ncolors, ncolors, PATCOPY);
            SelectObject(ps.hdc, WhitePen);
            if (hwnd == hsvwnd[0])
                Polyline(ps.hdc, huepoints, ncolors);
            else if (hwnd == hsvwnd[1])
                Polyline(ps.hdc, satpoints, ncolors);
            else /*if (hwnd == hsvwnd[2])*/
                Polyline(ps.hdc, valpoints, ncolors);
            EndPaint(hwnd, &ps);
        }
        return 0;
    case WM_CREATE:
        hDC = GetDC(hwnd);  
        if (!palette_disabled) {
            SelectPalette(hDC, hPal, 0);
            RealizePalette((HDC)hPal);
        }
        hsvwnd[ncreate] = hwnd;
        ncreate++;
        if (ncreate == 4) { 
            ncreate = 0;
        }
        else {
            SelectObject(hDC, WhitePen);
            SelectObject(hDC, BlackBrush);
        }
        return 0;
    case WM_KILLFOCUS:
        send_lut_to_main_task();
        break;
    default:
        return (DefWindowProc(hwnd, message, wParam, lParam));
        break;
    }
    return 0;
}


/******************************/
/*	HSV modeless dialog box   */
/******************************/

HWND hwndHsv;  // window handle of HSV dialog box  

// Fonction de gestion de la boite de controle des parametres H,S,V
BOOL CALLBACK HsvDlgProc(hwndDlg, message, wParam, lParam) 
HWND hwndDlg; 
UINT message; 
WPARAM wParam; 
LPARAM lParam; 
{
    static int ifirst=0;
    int k;
    FILE *fd;
    DWORD dwPos;
    HWND hwndScrollBar, hwndList; 
    int hwndScrollBarId;
    char dum[256];
    char lutname[256];
    static char lutpath[SIC_MAX_PATH_LENGTH];
    static char path[SIC_MAX_TRANSLATION_LENGTH];

    struct _finddata_t lut_file;
    long hFile;

    if (ifirst == 0) {
        strcpy( lutpath, sic_s_get_logical_path( "GAG_LUT:"));
        sprintf( path, "%s*.lut", lutpath) ;
    }

    switch (message) { 
    case WM_INITDIALOG:
        WhitePen = CreatePen(PS_SOLID, 0, RGB(255, 255, 255));

        init_hsv_rgb();
        SendDlgItemMessage(hwndDlg, IDC_SLIDER1, TBM_SETRANGE, 
            (WPARAM) TRUE,                   // redraw flag 
            (LPARAM) MAKELONG(0, 360*5));    // min. & max. positions 
        SendDlgItemMessage(hwndDlg, IDC_SLIDER1, TBM_SETPOS, 
            (WPARAM) TRUE,                   // redraw flag 
            (LPARAM) (0));

        SendDlgItemMessage(hwndDlg, IDC_SLIDER2, TBM_SETRANGE, 
            (WPARAM) TRUE,                   // redraw flag 
            (LPARAM) MAKELONG(0, 360*5));    // min. & max. positions 
        SendDlgItemMessage(hwndDlg, IDC_SLIDER2, TBM_SETPOS, 
            (WPARAM) TRUE,                   // redraw flag 
            (LPARAM) (360));
        if( (hFile = _findfirst(path, &lut_file)) == -1L )
            gtv_c_message(seve_u, "LUT", "No lut files in %s directory!", lutpath);
        else {
            SendDlgItemMessage(hwndDlg, IDC_LIST1, LB_INSERTSTRING,
                (WPARAM) -1, (LPARAM) (LPCTSTR) lut_file.name);
            while(_findnext(hFile, &lut_file) == 0)
                SendDlgItemMessage(hwndDlg, IDC_LIST1, LB_INSERTSTRING,
                (WPARAM) -1, (LPARAM) (LPCTSTR) lut_file.name);
            _findclose(hFile);
        }
        return TRUE;

    case WM_HSCROLL:
        hwndScrollBar = (HWND) lParam;
        dwPos = SendMessage(hwndScrollBar, TBM_GETPOS, 0, 0); 
        hwndScrollBarId = GetDlgCtrlID(hwndScrollBar);
        sprintf(dum, "%d", dwPos);
        switch(hwndScrollBarId) {
        case IDC_SLIDER1:
            SendDlgItemMessage(hwndDlg, IDC_LABEL1, WM_SETTEXT, (WPARAM)0, (LPARAM) (LPCTSTR) dum);
            lowbound = dwPos;
            break;
        case IDC_SLIDER2:
            SendDlgItemMessage(hwndDlg, IDC_LABEL2, WM_SETTEXT, (WPARAM)0, (LPARAM) (LPCTSTR) dum);
            highbound = dwPos;
            break;
        }

        for (k=0; k<ncolors; k++) {
            hue[k] = (float) (lowbound) + hp[k]*(highbound-lowbound);
            hsv_to_rgb(&hue[k], &sat[k], &val[k], &red[k], &green[k], &blue[k]);
        }
        activate();
        return 0;

    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case IDC_DISMISS:
            ShowWindow(hwndDlg, SW_HIDE);
            break;
        case IDC_LIST1:
            switch (HIWORD(wParam)) { 
            case LBN_SELCHANGE: 
                hwndList = GetDlgItem(hwndDlg, IDC_LIST1); 
                k = SendMessage(hwndList, LB_GETCURSEL, 0, 0); 
                SendMessage(hwndList, LB_GETTEXT, (WPARAM)k, (LPARAM)dum);
                sprintf(lutname, "%s%s", lutpath, dum);
                fd = fopen(lutname, "r");

                if (fd == NULL) gtv_c_message(seve_u, "LUT", "No such lut");
                else {
                    for (k=0; k<NB_COLORS; k++) {
                        fscanf(fd, "%f %f %f\n", &red[k], &green[k], &blue[k]);  
                        rgb_to_hsv( &red[k], &green[k], &blue[k], &hue[k], &sat[k], &val[k]);
                        huepoints[k].y = (L - 1) * (1. - hue[k] / 360);
                        satpoints[k].y = (L - 1) * (1. - sat[k]);
                        valpoints[k].y = (L - 1) * (1. - val[k]);
                    }
                    fclose(fd);
                    InvalidateRect( hsvwnd[0], NULL, TRUE);
                    InvalidateRect( hsvwnd[1], NULL, TRUE);
                    InvalidateRect( hsvwnd[2], NULL, TRUE);
                    activate( );
                    sprintf(dum, "%s%s%s", "GTVL\\LUT \"",  lutname, "\"");
                    sic_post_command_text(dum);
                }
                break;
            }
        }
        break;
    case WM_SYSCOMMAND: 
        if (wParam == SC_CLOSE) {
            ShowWindow(hwndDlg, SW_HIDE);
        }
        break;
    }
    return FALSE; 
} 

// Get console window identifier
HWND consolewnd=NULL;
void GetConsoleWnd()
{
    char pszNewWindowTitle[1024]; 
    char pszOldWindowTitle[1024]; 

    GetConsoleTitle(pszOldWindowTitle, 1024);
    // mainwnd = FindWindow(NULL, pszOldWindowTitle);
    // format a "unique" NewWindowTitle

    wsprintf(pszNewWindowTitle,"%d/%d",
        GetTickCount(),
        GetCurrentProcessId());
    SetConsoleTitle(pszNewWindowTitle);
    // ensure window title has been updated

    Sleep(40);

    consolewnd = FindWindow(NULL, pszNewWindowTitle),
        // restore original window title
        SetConsoleTitle(pszOldWindowTitle);

}

/*----------------------------------------------------------------------
*  SUBROUTINE X_CMDWIN
*  set focus back to the command window
*/
void win_x_cmdwin(void)
{
    if (consolewnd == NULL) gtv_c_message(seve_e, "X_CMDWIN", "ERROR CONSOLEWND");
    SetForegroundWindow(consolewnd);

}

/*
*----------------------------------------------------------------------
* Module ??
*   SUBROUTINE x_size
*      Return the window size
*/
void win_x_size(int *larg, int *haut)
{
    RECT rect; 

    GetClientRect(s_win_env_cour->win_graph, &rect);
    *larg=rect.right; *haut=rect.bottom;
}

// Cree les bitmaps de la barre de menu
VOID CreateBitmaps()  
{ 
    HWND hwndDesktop = GetDesktopWindow(); 
    HDC hdcDesktop = GetDC(hwndDesktop); 
    HDC hdcMem = CreateCompatibleDC(hdcDesktop); 
    COLORREF clrMenu = GetSysColor(COLOR_MENU); 
    HBRUSH hbrOld; 
    HPEN hpenOld;
    int fnDrawMode; 
    int i;
    HRGN hRgn;


    hbrOld = SelectObject(hdcMem, CreateSolidBrush(clrMenu)); 

    for (i = 0; i < NDASH; i++) { 
        dashHbm[i] = CreateCompatibleBitmap(hdcDesktop, XDASH, Y_DASH);
        SelectObject(hdcMem, dashHbm[i]); 
        /* backg */
        PatBlt(hdcMem, 0, 0, XDASH, Y_DASH, PATCOPY); 

        hpenOld = SelectObject(hdcMem, CreatePen(PS_SOLID + i, 1, RGB(0, 0, 0))); 

        // Draw the line. To preserve the background color where 
        // the pen is white, use the R2_MASKPEN drawing mode. 
        fnDrawMode = SetROP2(hdcMem, R2_MASKPEN); 
        MoveToEx(hdcMem, 0, Y_DASH / 2, NULL); 
        LineTo(hdcMem, XDASH, Y_DASH / 2); 
        SetROP2(hdcMem, fnDrawMode); 

        DeleteObject(SelectObject(hdcMem, hpenOld));
    } 

    for (i = 0; i < NWEIGHT; i++) { 
        weightHbm[i] = CreateCompatibleBitmap(hdcDesktop, X_WEIGHT, Y_WEIGHT);
        SelectObject(hdcMem, weightHbm[i]); 
        /* backg */
        PatBlt(hdcMem, 0, 0, X_WEIGHT, Y_WEIGHT, PATCOPY); 

        hpenOld = SelectObject(hdcMem, CreatePen(PS_SOLID, i+1, RGB(0, 0, 0))); 

        MoveToEx(hdcMem, 0, Y_DASH / 2, NULL); 
        LineTo(hdcMem, XDASH, Y_DASH / 2);

        DeleteObject(SelectObject(hdcMem, hpenOld));
    } 

    hpenOld = SelectObject(hdcMem, CreatePen(PS_SOLID, 1, RGB(0, 0, 0)));
    for (i = 0; i < NSTYLE; i++) { 
        styleHbm[i] = CreateCompatibleBitmap(hdcDesktop, X_STYLE, Y_STYLE);
        SelectObject(hdcMem, styleHbm[i]); 
        /* backg */
        PatBlt(hdcMem, 0, 0, X_STYLE, Y_STYLE, PATCOPY); 

        if (i == 0) Polyline(hdcMem, s_rect, 5);
        else if (i == 1) {
            MoveToEx(hdcMem, 0, Y_STYLE / 2, NULL); 
            LineTo(hdcMem, X_STYLE, Y_STYLE / 2);
            MoveToEx(hdcMem, X_STYLE / 2, 0, NULL); 
            LineTo(hdcMem, X_STYLE / 2, Y_STYLE);
        }
        else if (i == 2) Polyline(hdcMem, star, 9);
        else if (i == 3) {
            hRgn = CreatePolygonRgn(s_rect, 4, WINDING);
            FillRgn(hdcMem, hRgn, hbrush[0]);
            DeleteObject(hRgn);
        }
        else {
            hRgn = CreatePolygonRgn(star, 8, WINDING);
            FillRgn(hdcMem, hRgn, hbrush[0]);
            DeleteObject(hRgn);
        }
    } 
    DeleteObject(SelectObject(hdcMem, hpenOld));

    DeleteObject(SelectObject(hdcMem, hbrOld));

    if (!palette_disabled) {
        SelectPalette (hdcMem, hPal, 0);
        RealizePalette(hdcMem);
    }

    for (i = 0; i < NTAB; i++) { 
        hbrush[i] = CreateSolidBrush(palette_index(i+NFIRST));
        hpen[i] = CreatePen(PS_SOLID, 0, palette_index(i+NFIRST));
        SelectObject(hdcMem, hbrush[i]); 
        colHbm[i] = CreateCompatibleBitmap(hdcDesktop, X_TAB, Y_TAB);
        SelectObject(hdcMem, colHbm[i]); 
        PatBlt(hdcMem, 0, 0, X_TAB, Y_TAB, PATCOPY);
    } 

    // Delete the memory DC and release the desktop DC. 

    DeleteDC(hdcMem); 
    ReleaseDC(hwndDesktop, hdcDesktop); 
} 

int borderwidth, borderheight, captionheight;
int mainwindow=0;
HWND s_main_window = NULL;

// Thread starting function; each window has its own thread
void create_window(G_win_env *env_param) 
{  
    RECT rect;
    HMENU hMenu=NULL, hSubMenu, hPopupMenu;
    int i;
    char name[80], dum[3];

    rect.left = 0; rect.right = env_param->_herit.Width_graphique;
    rect.top = 0; rect.bottom = env_param->_herit.Height_graphique;

    /* In WIN32, the dimensions of a window include borders and caption 
    so we must adjust the desired dimensions */
    if (mainwindow)
        AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, 1); // Main Window has a menu
    else
        AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, 0); // Zoom WIndow has no menu

    borderwidth = -rect.left; // largeur totale de la fenetre : 2*borderwidth+client_width;
    borderheight = rect.bottom - env_param->_herit.Height_graphique;
    captionheight = -rect.top;       // hauteur totale : captionheight+borderheight+client_height;

    if (mainwindow) {
        hMenu = LoadMenu(hInst, (LPCTSTR) "greg");
        hSubMenu = GetSubMenu(GetSubMenu(hMenu, 0), 0);

        CreateBitmaps();

        for (i = 1; i <NPEN ; i++) {
            sprintf(dum, "%d", i);
            AppendMenu(hSubMenu, MFT_STRING, 100+i, dum);
        }

        hSubMenu = GetSubMenu(hMenu, 0);

        hPopupMenu = CreatePopupMenu();
        AppendMenu(hSubMenu, MF_STRING | MF_POPUP, (UINT) hPopupMenu, "Color");

        hPopupMenu = CreatePopupMenu();
        AppendMenu(hSubMenu, MF_STRING | MF_POPUP, (UINT) hPopupMenu, "Dashed");

        hPopupMenu = CreatePopupMenu();
        AppendMenu(hSubMenu, MF_STRING | MF_POPUP, (UINT) hPopupMenu, "Weight");

        hSubMenu1 = GetSubMenu(GetSubMenu(hMenu, 0), 1);
        for (i = 0; i < NTAB; i++)
            AppendMenu(hSubMenu1, MF_BITMAP, 200+i, (LPCTSTR)colHbm[i]);

        hSubMenu = GetSubMenu(GetSubMenu(hMenu, 0), 2);
        for (i = 0; i < NDASH; i++)
            AppendMenu(hSubMenu, MF_BITMAP, 300+i, (LPCTSTR)dashHbm[i]);

        hSubMenu = GetSubMenu(GetSubMenu(hMenu, 0), 3);
        for (i = 0; i < NWEIGHT; i++)
            AppendMenu(hSubMenu, MF_BITMAP, 400+i, (LPCTSTR)weightHbm[i]);

        hSubMenu = GetSubMenu(GetSubMenu(hMenu, 1), 0);

        for (i = 2; i <= 16 ; i++) {
            sprintf(dum, "%d", i);
            AppendMenu(hSubMenu, MFT_STRING, 500+i, dum);
        }

        hSubMenu = GetSubMenu(hMenu, 1);

        hPopupMenu = CreatePopupMenu();
        AppendMenu(hSubMenu, MF_STRING | MF_POPUP, (UINT) hPopupMenu, "Mstyle");
        hPopupMenu = CreatePopupMenu();
        AppendMenu(hSubMenu, MF_STRING | MF_POPUP, (UINT) hPopupMenu, "Size (1/10 cm)");
        hPopupMenu = CreatePopupMenu();
        AppendMenu(hSubMenu, MF_STRING | MF_POPUP, (UINT) hPopupMenu, "Orientation");

        hSubMenu = GetSubMenu(GetSubMenu(hMenu, 1), 1);
        for (i = 0; i < NSTYLE ; i++)
            AppendMenu(hSubMenu, MF_BITMAP, 600+i, (LPCTSTR)styleHbm[i]);

        hSubMenu = GetSubMenu(GetSubMenu(hMenu, 1), 2);
        for (i = 1; i <= 10 ; i++) {
            sprintf(dum, "%d", i);
            AppendMenu(hSubMenu, MFT_STRING, 700+i, dum);
        }
        hSubMenu = GetSubMenu(GetSubMenu(hMenu, 1), 3);
        for (i = 0; i < 7 ; i++) {
            sprintf(dum, "%d", 15*i);
            AppendMenu(hSubMenu, MFT_STRING, 800+i, dum);
        }
        mainwindow = 0;
    }

    /* Creation of a window */
    /*
    printf("DIMENSIONS:\n   desired: %d %d\n  adjusted %d %d\n",
    env_param->_herit.Width_graphique, env_param->_herit.Height_graphique,
    rect.right-rect.left,rect.bottom-rect.top);
    */
    (env_param->_herit.win_backg)? sprintf(name, "%s", WhiteDev) : sprintf(name, "%s", BlackDev);

    win_graph = CreateWindow(name, window_name,
        WS_OVERLAPPEDWINDOW,
        X_ancrage,Y_ancrage,
        rect.right - rect.left,
        rect.bottom - rect.top,
        //						   consolewnd, hMenu, hInst, (LPSTR) NULL);
        (HWND) NULL, hMenu, hInst, (LPSTR) NULL);

    if (s_main_window == NULL)
        s_main_window = win_graph;

    ShowWindow(win_graph, SW_SHOWNORMAL);
    SetForegroundWindow(win_graph);
    //GetClientRect(win_graph, &rect);
    //env_param->_herit.Width_graphique = rect.right;
}	  

DWORD run_window(G_env *env_param) 
{
    MSG msg;
    create_window( (G_win_env *)env_param);
#if 1
    while (GetMessage(&msg, NULL, 0, 0)) { 
        TranslateMessage(&msg);
        DispatchMessage(&msg); /* Does not return until 
                               the window procedure finishes processing the message */
    }
#else
	// The message loop
	while (1) {
		DWORD dwStatus = MsgWaitForMultipleObjectsEx(0, 
													NULL,
													2000, 
													QS_ALLINPUT, 
													MWMO_INPUTAVAILABLE);
		
		if (dwStatus == WAIT_OBJECT_0) {
			while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
				/*if (!CallMsgFilter(&msg, 0x5300)) */{ 
					TranslateMessage(&msg);
					DispatchMessage(&msg);
				}
			}
		}
	}
#endif
    return 1;
}	  

int querypal;

// Fonction de reception des messages pour les fenetres en mode normal (ni Zoom, ni Draw)

LONG APIENTRY WndProc(
                      HWND hWnd,
                      UINT message,
                      UINT wParam,
                      LONG lParam)
{

    PAINTSTRUCT ps;
    RECT rect;
    G_win_env *env;
    int i;

    switch (message) {
    case WM_USER:
        create_window( (G_win_env *)lParam);
        break;
    case WM_COMMAND:
        switch (LOWORD(wParam)) { 
        case IDM_LUT:
            if (!IsWindow(hwndHsv)) { 
                hwndHsv = CreateDialog(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 
                    hWnd, (DLGPROC) HsvDlgProc); 
            }
            ShowWindow(hwndHsv, SW_SHOW); 
            break;
        case IDM_HARDCOPY:
            sic_post_command_text("GTVL\\HARDCOPY /PRINT");
            break;
        case IDM_DRAW:
            sic_post_command_text("DRAW");
            break;
        case IDM_ZOOM:
            sic_post_command_text("GTVL\\ZOOM");
            break;
        case IDM_ZOOMOFF:
            sic_post_command_text("GTVL\\ZOOM OFF");
            break;
        case IDM_REFRESH:
            sic_post_command_text("GTVL\\ZOOM REFRESH");
            //			i=SetFocus(mainwnd);
            break;
        case IDM_CLEAR:
            sic_post_command_text("GTVL\\CLEAR");
            break;
        default:
            {
                char dum[256];
                i = LOWORD(wParam);

                if (i >=100 && i < 100+NTAB) {
                    sprintf(dum, "%s%d", "PENCIL ", i - 100);
                    printf("%s\n", dum);
                    sic_post_command_text(dum);
                }
                if (i >=200 && i < 200+NTAB) {
                    sprintf(dum, "%s%d", "PENCIL /COLOUR ", i - 200);
                    printf("%s\n", dum);
                    sic_post_command_text(dum);
                }
                if (i >=300 && i < 300+NDASH) {
                    sprintf(dum, "%s%d", "PENCIL /DASHED ", i + 1 - 300);
                    printf("%s\n", dum);
                    sic_post_command_text(dum);
                }
                if (i >=400 && i < 400+NWEIGHT) {
                    sprintf(dum, "%s%d", "PENCIL /WEIGHT ", i + 1 - 400);
                    printf("%s\n", dum);
                    sic_post_command_text(dum);
                }
                if (i >=501 && i <= 500+16) {
                    sprintf(dum, "%s%d%s", "SET MARKER ", i - 500, " * * *");
                    printf("%s\n", dum);
                    sic_post_command_text(dum);
                }
                if (i >=600 && i < 600+5) {
                    sprintf(dum, "%s%d%s", "SET MARKER * ", i - 600, " * *");
                    printf("%s\n", dum);
                    sic_post_command_text(dum);
                }
                if (i >=701 && i <= 700+10) {
                    sprintf(dum, "%s%2.1f%s", 
                        "SET MARKER * * ", (float) (i  - 700)/10., " *");
                    printf("%s\n", dum);
                    sic_post_command_text(dum);
                }
                if (i >=800 && i < 800+7) {
                    sprintf(dum, "%s%d", "SET MARKER * * * ", 15*(i - 800));
                    printf("%s\n", dum);
                    sic_post_command_text(dum);
                }
            }
            break;
        }
        return 0L;

    case WM_CREATE:
        querypal = 0;

        env=s_win_env_cour;
        SetWindowLong(hWnd, GWL_USERDATA, (LONG) env);
        env->win_graph = hWnd;

        env->myGC = GetDC(hWnd);

        if (!palette_disabled)
            hOldPal = SelectPalette(env->myGC, hPal, 1);

        if (!(env->vertical=CreateBitmap(1, Height_graphique, cplanes, depth, NULL)))
            gtv_c_message(seve_u, "?", "Couldn't create a bitmap");
        if (!(env->horizontal=CreateBitmap(Width_graphique, 1, cplanes, depth, NULL)))
            gtv_c_message(seve_u, "?", "Couldn't create a bitmap");
        if (!(env->box1=CreateBitmap(1, Height_graphique, cplanes, depth, NULL)))
            gtv_c_message(seve_u, "?", "Couldn't create a bitmap");
        if (!(env->box2=CreateBitmap(Width_graphique, 1, cplanes, depth, NULL)))
            gtv_c_message(seve_u, "?", "Couldn't create a bitmap");
        if (!(env->box3=CreateBitmap(1, Height_graphique, cplanes, depth, NULL)))
            gtv_c_message(seve_u, "?", "Couldn't create a bitmap");
        if (!(env->box4=CreateBitmap(Width_graphique, 1, cplanes, depth, NULL)))
            gtv_c_message(seve_u, "?", "Couldn't create a bitmap");

        sic_post_widget_created( );

        break;

    case WM_CLOSE:
        env = (G_win_env *) GetWindowLong(hWnd, GWL_USERDATA); 
        if (env->win_graph == NULL) {
            SetWindowLong( hWnd, GWL_USERDATA, 0);
            if (env->PrimaryWindow)
                ShowWindow( hWnd, SW_HIDE); // don't remove primary window
            else
                DestroyWindow( hWnd);
        } else {
            sic_post_command_text("DEV NONE");
            clear_dibs( );
            win_x_cmdwin();
        }
        break;

    case WM_QUERYNEWPALETTE:
        // On ne peut appeler MySelectPalette que lorsque la fenetre est
        // deja affichee et a le focus
        if (querypal) { MySelectPalette(); return TRUE; }
        break;	

    case WM_PAINT:
        env = (G_win_env *) GetWindowLong(hWnd, GWL_USERDATA); 
        if (env == NULL)
            break;
        BeginPaint(hWnd, &ps);
        if (!querypal) {
            MySelectPalette();
            querypal = 1;
        }
        env->IsPaint = 1;
        /////x_size(&largeur,&hauteur); ///dimension de la dernier fenetre creee
        /////printf("%d %d\n",env->_herit.Width_graphique,largeur);
        /////if ((env->_herit.Width_graphique==largeur) &&
        /////   (env->_herit.Height_graphique==hauteur))
        /////refresh(env);
        refresh(env,0);
        EndPaint(hWnd, &ps); 

        break;

    case WM_DESTROY: 
        clear_dibs( );
        for (i = 0; i < NTAB; i++) 
            DeleteObject(colHbm[i]);
        for (i = 0; i < NDASH; i++) 
            DeleteObject(dashHbm[i]);
        for (i = 0; i < NWEIGHT; i++) 
            DeleteObject(weightHbm[i]);
        for (i = 0; i < NSTYLE; i++) 
            DeleteObject(styleHbm[i]);
        break;

    case WM_EXITSIZEMOVE:
        env = (G_win_env *) GetWindowLong(hWnd, GWL_USERDATA);  
        GetClientRect(env->win_graph, &rect);
        if (env->_herit.Width_graphique != rect.right || env->_herit.Height_graphique != rect.bottom) {
            env->IsResized = 1;
            refresh(env,1);
        }
        break;
    default:
        return(DefWindowProc(hWnd, message, wParam, lParam));
        break;
    }
    return 0;
}

   void DisplayError(DWORD dwError)
   {
      LPVOID lpvMessageBuffer;

      FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                    FORMAT_MESSAGE_FROM_SYSTEM,
                    NULL, dwError,
                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
             (LPTSTR)&lpvMessageBuffer, 0, NULL);

      gtv_c_message(seve_e, (LPTSTR)lpvMessageBuffer, "CreateThread error");

      // Free the buffer allocated by the system.
      LocalFree(lpvMessageBuffer);
   }

static int s_first_call = 1;

/*
* ---------------------------------------------------------
* SUBROUTINE NEW_GRAPH
*/
void win_new_graph(
    int backg,
    G_env *env,
    char *dirname,
    int width, int height,
    fortran_type dir_cour,
    int reuse)
{


    G_win_env *cur=s_win_env_cour;
    //Byte *inidatas;
    DWORD dwThreadId, dwThrdParam = 1; 

    if (!cur->_herit.Width_graphique)cur->_herit.Width_graphique=Width_default;
    if (!cur->_herit.Height_graphique)cur->_herit.Height_graphique=Height_default;

    if (cur->_herit.Width_graphique<104)cur->_herit.Width_graphique=104;

    Width_graphique=cur->_herit.Width_graphique;
    Height_graphique=cur->_herit.Height_graphique;

    cur->_herit.adr_dir = dir_cour;
    clear_dibs( );

    /* Donnons un nom a la fenetre */ 
    strcpy( window_name, dirname);

    if(reuse) {
        cur->_herit.win_backg=backg;
        win_graph=cur->win_graph;
        ClearWindow(cur);
    }
    else {
#ifdef GAG_USE_STATICLINK
        init_win_gtv( GetModuleHandle( NULL), DLL_PROCESS_ATTACH, NULL);
#endif /* GAG_USE_STATICLINK */

        /* rappellons nous du fond de cette fenetre */
        cur->_herit.win_backg=backg;

        if (s_first_call) {
            s_first_call = 0;
        cur->hThread = 
            CreateThread(NULL,                 // no security attributes 
            0,                           // use default stack size  
            (LPTHREAD_START_ROUTINE) run_window, // thread function 
            cur,                         // argument to thread function 
            0,                           // use default creation flags 
            &dwThreadId);                // returns the thread identifier 

        // Check the return value for success. 
        if (cur->hThread == NULL) {
            DisplayError( GetLastError( ));
            //gtv_c_message(seve_e, "?", "CreateThread error");
        }
        } else {
            // create window in graphic thread
            SendMessage( s_main_window, WM_USER, 0, (LPARAM)cur);
        }

        sic_wait_widget_created( );
    }
}

/* In place for X11 Allocnamedcolor */
void create_pen_and_brushes(int flag)
{
    int i=0, j=NFIRST; 

    peRed[j] = peGreen[j]= peBlue[j] = (flag) ? 0 : max_intensity; // Foreground

    peRed[j+1] = max_intensity; peGreen[j+1] = 0; peBlue[j+1] = 0; // red
    peGreen[j+2] = max_intensity; peRed[j+2] = 0; peBlue[j+2] = 0; // green
    peBlue[j+3] = max_intensity; peRed[j+3] = 0; peGreen[j+3] = 0; // blue


    peGreen[j+4] = peBlue[j+4] = max_intensity; peRed[j+4] = 0;    // cyan
    peRed[j+5] = peGreen[j+5] = max_intensity; peBlue[j+5] = 0;    // yellow
    peBlue[j+6] = peRed[j+6] = max_intensity; peGreen[j+6] = 0;    // magenta  

    peRed[j+7] = peGreen[j+7] = peBlue[j+7] = (flag) ? max_intensity : 0; // Background

    for (i = j+8; i < j+NTAB; i++) {
        peRed[i] = peGreen[i] = peBlue[i] = max_intensity*(i - j - 8)/NPEN;
    }

    //  for (i = 0; i<NTAB; i++) {
    //    hpen[i] = CreatePen(PS_SOLID, 0, 
    //		      RGB(peRed[i+NFIRST], peGreen[i+NFIRST], peBlue[i+NFIRST]));
    //    hbrush[i] = CreateSolidBrush(
    //		      RGB(peRed[i+NFIRST], peGreen[i+NFIRST], peBlue[i+NFIRST]));
    //  }

    for (i=0; i<NTAB; i++) {
        tabcolor[i].peRed = peRed[i+NFIRST];
        tabcolor[i].peGreen = peGreen[i+NFIRST];
        tabcolor[i].peBlue = peBlue[i+NFIRST];
        tabcolor[i].peFlags = PC_RESERVED;
    }

    //	for (i = 0; i<NTAB; i++) {
    //	  hpen[i] = CreatePen(PS_SOLID, 0, 
    //		      RGB(peRed[i+NFIRST], peGreen[i+NFIRST], peBlue[i+NFIRST]));
    //    hbrush[i] = CreateSolidBrush(
    //		      RGB(peRed[i+NFIRST], peGreen[i+NFIRST], peBlue[i+NFIRST]));
    //	  hbrush[i] = CreateSolidBrush(palette_index(i+20));
    //	}
    win_pen_colors();
    pen_ncol=NPEN;


}

/*
*----------------------------------------------------------------------
* Module 1
* SUBROUTINE OPEN_X
*     OPEN_X Point d'entree pour GTOPEN
*----------------------------------------------------------------------
*/
int win_open_x(
                   char *device,
                   int backg,           /* !=0 if the user wants reverse video */
                   int cross,           /* !=0 if the user wants crosshair cursor  */
                   G_env **graph_env,    /* pointer to graphics environment struct */
                   char *dirname,
                   int *x1, int *x2, int *y1, int *y2,
                   int dir_cour[],
                   int HT, int LT,     /* requested window size  */
                   int col)           /* !=0 if the user want to use color, affected to ncol */
{
    int X, Y, Width, Height, swidth, sheight;
    HDC hdcScreen;
    char rname[] = "X";

    gtv_c_message(seve_d, rname, "WIN32 version %s",VERSION);
    flag_cross = cross;
    flag_backingstore = 0; // backing_store not supported
    mainwindow = 1;

    /* Physical size */
    hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL); 
    sheight=GetDeviceCaps(hdcScreen, VERTRES);
    swidth=GetDeviceCaps(hdcScreen, HORZRES);
    gtv_c_message(seve_d, rname, "Screen size (mm) : height: %d, width: %d",
        GetDeviceCaps(hdcScreen, VERTSIZE), GetDeviceCaps(hdcScreen, HORZSIZE));
    gtv_c_message(seve_d, rname, "Screen pixels : height: %d, width: %d",
        sheight,swidth);

    /* Physical characteristics of screen */
    depth=GetDeviceCaps(hdcScreen, BITSPIXEL);
    gtv_c_message(seve_d, rname, "Screen characteristics: %d plane(s)",depth);

    palette_disabled = (GetDeviceCaps(hdcScreen, RASTERCAPS) & RC_PALETTE) ? FALSE : TRUE;

    cplanes=GetDeviceCaps(hdcScreen, PLANES);

    GetConsoleWnd();

    if (!palette_disabled) {
        GetSystemPaletteEntries(hdcScreen, 0, NFIRST, systemcolors);
        if ((plogPal = (PLOGPALETTE) GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*256))
            == NULL) {
            gtv_c_message(seve_e, rname, "Failed in Memory Allocation for plogPal");
        } else {
            plogPal->palVersion = 0x300;
            plogPal->palNumEntries = (WORD) 256;

            hPal = CreatePalette ((PLOGPALETTE) plogPal) ;
            if (hPal == NULL)
                gtv_c_message(seve_u, rname, "CreatePalette Failed");
        }

        SetPaletteEntries(hPal, 0, NFIRST, systemcolors);
    }
    DeleteDC(hdcScreen);

    flag_color_display=1;

    create_pen_and_brushes( backg);

    /* Creeons le premier contexte graphique. */
    init_genv_chain( win_creer_genv());

    /* Now open a (graphic) window */
    X_ancrage=50; Y_ancrage=50;
    Width= LT; Height= HT;
    if(!Height && !Width) {
        X=(*x2==1) ? (80*swidth)/100 : *x2-*x1+1;
        Y=(*y2==1) ? (66*sheight)/100 : *y2-*y1+1;
        if(X<=swidth && Y<=sheight) { Height=Y; Width=X; }
        else {
            Height=(85*sheight)/100; Width=(X*Height)/Y;
            if(Width>=swidth) { Width=(85*swidth)/100; Height=(Y*Width)/X; }
        }
    }
    /* Gardons ces dimensions pour les autres */
    Width_default=Width; Height_default=Height;
    s_win_env_cour->_herit.Width_graphique=Width;
    s_win_env_cour->_herit.Height_graphique=Height;

    win_new_graph(backg,graph_env,dirname,x1,x2,y1,y2,dir_cour, 0);
    (*graph_env)->widthofscreen = swidth;
    (*graph_env)->heightofscreen = sheight;

    win_x_cmdwin();

    return(1);  

}

/*
*----------------------------------------------------------------------
* Module 11
*
*  SUBROUTINE X_FLUSH
*      X_FLUSH 
*      Tracer
*----------------------------------------------------------------------
*/

void win_x_flush(void)
{

    if(npts) {
        Polyline(s_win_env_cour->myGC, tabpts, npts);
        npts=0;
    }

}
/*
*----------------------------------------------------------------------
* Module 9
*      SUBROUTINE X_MOVP1
*      X_MOV_P1
*      Se placer  plume haute
*----------------------------------------------------------------------
* modifie le 19.06.92
*/
void win_x_movp1(int ix, int iy)
{
    //printf("x_movp1\n");
    if(npts) {
        Polyline(s_win_env_cour->myGC,tabpts,npts);
    }
    tabpts->x = ix; tabpts->y = iy; npts = 1;
}

/*
*----------------------------------------------------------------------
* Module 10
*
*  SUBROUTINE X_MOV_P2
*  deplacement  plume basse
*----------------------------------------------------------------------
* modifie le 19.06.92
*/
void win_x_movp2(int ix, int iy)
{
    tabpts[npts].x = ix; tabpts[npts].y = iy;
    if(++npts==1024) {
        Polyline(s_win_env_cour->myGC,tabpts,1024);
        npts=0;
    }
}
/*
* ---------------------------------------------------------------------
* SUBROUTINE X_FILL_POLY
*
* Remplissage de polygone
* ---------------------------------------------------------------------
*/
void win_x_fill_poly(int npts_poly, int *tabx, int *taby)
{
    POINT tab_fill[1024];
    HRGN hRgn;  
    int i;

    for(i=0;i<npts_poly;i++)
    { tab_fill[i].x=tabx[i]; tab_fill[i].y=taby[i]; }

    hRgn = CreatePolygonRgn(tab_fill, npts_poly, WINDING);
    if ((s_win_env_cour->plume_cour < 0) || (s_win_env_cour->plume_cour > 23)) 
        gtv_c_message(seve_e, "X_FILL_POLY", "error in x_fill_poly");
    else {
        FillRgn(s_win_env_cour->myGC, hRgn, 
            SelectObject(s_win_env_cour->myGC, hbrush[s_win_env_cour->plume_cour]));
    }
    DeleteObject(hRgn);
}
/*----------------------------------------------------------------------
* SUBROUTINE X_WEIGH(width)
*
* appelle par le fortran, cette routine place la largeur de ligne.
*/
void win_x_weigh(int width)
{
    if(npts) {
        Polyline(s_win_env_cour->myGC,tabpts,npts);
        npts=0;
    }


}
/*----------------------------------------------------------------------
* SUBROUTINE X_DASH(dashed,pattern)
*
* appelle par le fortran, cette routine place le style de pointille.
*/
void win_x_dash(int flag_dash, int ds[4])
{

    if(npts) {
        Polyline(s_win_env_cour->myGC,tabpts,npts);
        npts=0;
    }


}

int pointer_step=1;


/*
*----------------------------------------------------------------------
* Module 15
* Restaure les pixmaps vertical et horizontal
*----------------------------------------------------------------------
*/
void rest_pix_cross(int x, int y, int width, int height, int flg_zoom)
{
    G_win_env *cur=s_win_env_cour;
    int gwidth=cur->_herit.Width_graphique,gheight=cur->_herit.Height_graphique;
    HWND win_graph=cur->win_graph;
    HDC hMemDC = CreateCompatibleDC(cur->myGC);

    SelectObject(hMemDC, cur->vertical);
    BitBlt(cur->myGC, x, 0, 1, gheight, hMemDC, 0, 0, SRCCOPY); 
    SelectObject(hMemDC, cur->horizontal);
    BitBlt(cur->myGC, 0, y, gwidth, 1, hMemDC, 0, 0, SRCCOPY);

    if(flg_zoom) {
        SelectObject(hMemDC, cur->box1);
        BitBlt(cur->myGC, x-width, 0, 1, gheight, hMemDC, 0, 0, SRCCOPY); 
        SelectObject(hMemDC, cur->box3);
        BitBlt(cur->myGC, x+width, 0, 1, gheight, hMemDC, 0, 0, SRCCOPY);
        SelectObject(hMemDC, cur->box2);
        BitBlt(cur->myGC, 0, y-height, gwidth, 1, hMemDC, 0, 0, SRCCOPY); 
        SelectObject(hMemDC, cur->box4);
        BitBlt(cur->myGC, 0, y+height, gwidth, 1, hMemDC, 0, 0, SRCCOPY);
    }

    DeleteDC(hMemDC);
}

int press3=0;
int firstcross=1;
int drawinit = 1;
int x_oldcurs,y_oldcurs,x_newcurs,y_newcurs;
int xycar;
int dozoom = 0;

// Fonction de reception des messages pour les fenetres en mode Zoom ou Draw

LONG APIENTRY DrawProc(
                       HWND hWnd,
                       UINT message,
                       UINT wParam,
                       LONG lParam)
{
#if 0
    POINT pt;
    RECT rect;
    HDC hMemDC;
    int largeur,hauteur;
    PAINTSTRUCT ps;

    G_win_env *env = (G_win_env *) GetWindowLong(hWnd, GWL_USERDATA);
    float zoom=env->_herit.zoom_factor;
    int flg_zoom=(dozoom==1);

    int width=env->_herit.Width_graphique,height=env->_herit.Height_graphique;
    int zwidth = (int)(env->_herit.sizex*env->_herit.gsclx*(zoom*0.5));
    int zheight = (int)(-env->_herit.sizey*env->_herit.gscly*(zoom*0.5));

    switch (message) {
    case WM_PAINT:
        BeginPaint(hWnd, &ps); 
        env->IsPaint = 1;
        EndPaint(hWnd, &ps); 
        break;
    case WM_KEYDOWN:  
        switch (wParam) { 
        case VK_F1:
            pointer_step=1;
            break;
        case VK_F2:
            pointer_step=4;
            break;
        case VK_F3:
            pointer_step=16;
            break;
        case VK_F4:
            pointer_step=64;
            break;

        case VK_LEFT: 
            GetCursorPos(&pt);
            SetCursorPos(pt.x-pointer_step, pt.y);
            break; 

        case VK_RIGHT: 
            GetCursorPos(&pt);
            SetCursorPos(pt.x+pointer_step, pt.y);
            break; 

        case VK_UP: 
            GetCursorPos(&pt);
            SetCursorPos(pt.x, pt.y-pointer_step);
            break; 

        case VK_DOWN: 
            GetCursorPos(&pt);
            SetCursorPos(pt.x, pt.y+pointer_step);
            break; 
        default :
            break;
        }
        break;
    case WM_CHAR:
        xycar = wParam;
        drawinit = 0;
        goto fin;
        break;
    case WM_MOUSEMOVE:
        if (press3) { press3 = 0; return 0; }
        x_newcurs=LOWORD(lParam); y_newcurs=HIWORD(lParam);
        /*
        printf("oldx, oldy %d %d newx, newy %d %d\n",
        x_oldcurs, y_oldcurs, x_newcurs, y_newcurs);
        */
        hMemDC = CreateCompatibleDC(env->myGC);

        if (firstcross) firstcross = 0;
        else 
            rest_pix_cross(x_oldcurs,y_oldcurs,zwidth,zheight,flg_zoom);
        x_oldcurs=x_newcurs; y_oldcurs=y_newcurs;

        if(flg_zoom) {
            SelectObject(hMemDC, env->box1);
            BitBlt(hMemDC, 0, 0, 1, height, env->myGC, x_oldcurs-zwidth, 0, SRCCOPY); 
            SelectObject(hMemDC, env->box3);
            BitBlt(hMemDC, 0, 0, 1, height, env->myGC, x_oldcurs+zwidth, 0, SRCCOPY);
            SelectObject(hMemDC, env->box2);
            BitBlt(hMemDC, 0, 0, width, 1, env->myGC, 0, y_oldcurs-zheight, SRCCOPY); 
            SelectObject(hMemDC, env->box4);
            BitBlt(hMemDC, 0, 0, width, 1, env->myGC, 0, y_oldcurs+zheight, SRCCOPY);
        }

        SelectObject(hMemDC, env->vertical);
        BitBlt(hMemDC, 0, 0, 1, height, env->myGC, x_oldcurs, 0, SRCCOPY); 
        SelectObject(hMemDC, env->horizontal);
        BitBlt(hMemDC, 0, 0, width, 1, env->myGC, 0, y_oldcurs, SRCCOPY);

        DeleteDC(hMemDC);

        if (flg_zoom) {
            PatBlt(env->myGC, x_oldcurs-zwidth, y_oldcurs-zheight, zwidth*2, 1, PATCOPY);
            PatBlt(env->myGC, x_oldcurs+zwidth, y_oldcurs-zheight, 1, zheight*2, PATCOPY);
            PatBlt(env->myGC, x_oldcurs-zwidth, y_oldcurs+zheight, zwidth*2, 1, PATCOPY);
            PatBlt(env->myGC, x_oldcurs-zwidth, y_oldcurs-zheight, 1, zheight*2, PATCOPY);
        }

        PatBlt(env->myGC, x_oldcurs, 0, 1, height, PATCOPY);
        PatBlt(env->myGC, 0, y_oldcurs, width, 1, PATCOPY);

        break;


    case WM_EXITSIZEMOVE:
        env = (G_win_env *) GetWindowLong(hWnd, GWL_USERDATA);  
        GetClientRect(env->win_graph, &rect);
        if (env->_herit.Width_graphique != rect.right || env->_herit.Height_graphique != rect.bottom) {
                xycar = '*';
                drawinit = 1;
                env->IsResized = 1;
                goto fin;
        }


        break;
    case WM_LBUTTONDOWN:
        drawinit=0;
        xycar = '^';
        goto fin;
    case WM_MBUTTONDOWN:
        drawinit = 0;
        xycar = '&';
        goto fin;
    case WM_RBUTTONDOWN:
        press3 = 1;
        xycar = '*';
        drawinit = 1;
        goto fin;

    case WM_CLOSE:
        /* Do nothing, wait for the end of zoom mode */
        break;

    default:
        return(DefWindowProc(hWnd, message, wParam, lParam));
        break;
    }
    return 0;

fin:
    if(!firstcross) {
        rest_pix_cross(x_oldcurs,y_oldcurs,zwidth,zheight,flg_zoom);
        firstcross = 1;
    }

    /* End zoom mode */
    sic_post_command_text( "");
#endif
    return 0;	
}

POINT mempoint;

//Fonction d'entree dans le mode curseur; On surcharge la fonction de reception
//des messages de la fenetre (WndProc est remplacee par DrawProc)
void win_x_curs(int *xpos_curs, int *ypos_curs, CFC_FString cde, int fzoom)
{
    RECT rect;
    int pen_cour=save_pen;
    G_win_env *cur=s_win_env_cour;
    int zero = 0;
    win_graph = cur->win_graph;

    dozoom = fzoom;

    // win_x_pen(zero);

    SetWindowLong(win_graph, GWL_WNDPROC, (LONG) DrawProc);
    SetForegroundWindow(win_graph);

    GetWindowRect(win_graph, &rect); 

    if(drawinit) {
        SetCursorPos((rect.right+rect.left)/2, (rect.bottom+rect.top)/2);
    }
    else {
        SetCursorPos(mempoint.x, mempoint.y);
    }

    /* Wait until zoom mode ends */
    {
        command_line_t tmp;
        sic_command_from_t tmp2;
        sic_wait_command( &tmp, &tmp2);
    }

    // On revient a la fonction normale de reception des messages
    SetWindowLong(win_graph, GWL_WNDPROC, (LONG) WndProc);

    // win_x_pen(pen_cour);

    *xpos_curs = x_newcurs;
    *ypos_curs = y_newcurs;

    mempoint.x = x_newcurs;
    mempoint.y = y_newcurs;

    ClientToScreen(win_graph, &mempoint); 

    CFC_f2c_string( cde)[0] = xycar;

}

// X_TEST_EVENT est appelle pour chaque fenetre
int win_x_test_event(int *ix1, int *ix2, int *iy1, int *iy2)
{
    int compteur=0, val_ret=0;
    int largeur,hauteur;
    G_win_env *cur=s_win_env_cour;
    HWND win_graph=cur->win_graph;
    int resized=0;

    //printf("X_TEST_EVENT\n");
    if (cur->IsPaint) {
        cur->IsPaint = 0;
        val_ret+=!flag_backingstore;
        *ix1= *iy2=1; 
        *ix2=cur->_herit.Width_graphique-1;
        *iy1=cur->_herit.Height_graphique-1;
    }
    if (cur->IsResized) {
        cur->IsResized = 0;
        win_x_size(&largeur,&hauteur);

        if(cur->_herit.Width_graphique!=largeur) {
            Width_default=cur->_herit.Width_graphique=largeur; val_ret++;resized=1;
            DeleteObject(cur->horizontal);
            if (!(cur->horizontal=CreateBitmap(largeur, 1, cplanes, depth, NULL)))
                gtv_c_message(seve_u, "?", "Couldn't create a bitmap");
            DeleteObject(cur->box2);
            if (!(cur->box2=CreateBitmap(largeur, 1, cplanes, depth, NULL)))
                gtv_c_message(seve_u, "?", "Couldn't create a bitmap");
            DeleteObject(cur->box4);
            if (!(cur->box4=CreateBitmap(largeur, 1, cplanes, depth, NULL)))
                gtv_c_message(seve_u, "?", "Couldn't create a bitmap");
        }
        if(cur->_herit.Height_graphique!=hauteur) {
            Height_default=cur->_herit.Height_graphique=hauteur; val_ret++;resized=1;
            DeleteObject(cur->vertical);
            if (!(cur->vertical=CreateBitmap(1, hauteur, cplanes, depth, NULL)))
                gtv_c_message(seve_u, "?", "Couldn't create a bitmap");
            DeleteObject(cur->box1);
            if (!(cur->box1=CreateBitmap(1, hauteur, cplanes, depth, NULL)))
                gtv_c_message(seve_u, "?", "Couldn't create a bitmap");
            DeleteObject(cur->box3);
            if (!(cur->box3=CreateBitmap(1, hauteur, cplanes, depth, NULL)))
                gtv_c_message(seve_u, "?", "Couldn't create a bitmap");
        }
        *ix1= *iy2=1; *ix2=largeur-1; *iy1=hauteur-1;
    }
    if(val_ret) val_ret=1+resized;
    return(val_ret);

}


void win_ximage_loadrgb(int red[], int green[], int blue[], int n, int dir)
{
    int i,j,mcol = n;
    PALETTEENTRY *color;

    free(s_win_env_cour->win_color);
    /* il y en a toujours au moins une: celle par defaut, et bien, on la vire */

    color=s_win_env_cour->win_color=(PALETTEENTRY *)malloc(sizeof(PALETTEENTRY)*mcol);
    s_win_env_cour->win_col_size=mcol;
    /* on va mettre cette nouvelle a la place. change for version 3.3 */

    for(i=0;i<mcol;i++,color++) {
        j=(!dir) ? i /* sens direct */ : mcol-1-i /* sens indirect */;

        color->peRed=(unsigned char) (255*((float) red[j]/65535.));
        color->peGreen=(unsigned char) (255*((float) green[j]/65535.));
        color->peBlue=(unsigned char) (255*((float) blue[j]/65535.));
        color->peFlags = PC_RESERVED;
    }
    InvalidateRect( s_win_env_cour->win_graph, NULL, TRUE);

    /* il n'y a plus qu'a l'activer */
    set_colors();
}

int win_ximage_inquire(
                           int *lcol, int *ocol, int *nx, int *ny, int *is_color, int *is_static)
{
    *lcol=s_win_env_cour->win_col_size;
    *ocol=COLOFFSET;
    *is_color=flag_color_display; *is_static=flag_static_display;
    *nx=Width_default; *ny=Height_default; return(1);
}

void win_x_affiche_image( size_t *adr_data, int n_x0, int n_y0, int n_larg, int n_haut, int val_trou)
{
    Byte *sdata = (Byte *)(*adr_data);	/* source data */
    int largeur = n_larg;
    int hauteur = n_haut;
    HBITMAP hBitmap = NULL;

    if (palette_disabled) {
        dib_t *dib = create_dib( sdata, n_x0, n_y0, largeur, hauteur);
        draw_dib( dib);
#ifndef _GTV_USE_DIBS
        GlobalFree( dib->handle);
#endif _GTV_USE_DIBS
    } else {
        if ((hBitmap  = CreateBitmap(largeur, hauteur, cplanes, depth, sdata)) != 0) {
            HDC hMemDC = CreateCompatibleDC(s_win_env_cour->myGC);

            SelectObject(hMemDC, hBitmap);

            BitBlt(s_win_env_cour->myGC, n_x0, n_y0, 
                largeur, hauteur, hMemDC, 
                0, 0, SRCCOPY);

            DeleteDC(hMemDC);

            DeleteObject(hBitmap);
        }
        else {
            gtv_c_message(seve_u, "?", "Couldn't create a bitmap. Check number of Colours");
        }
    }
}

/*-------------------------
*   SUBROUTINE X_CLAL
*    Clear Alpha 
*/
void win_x_clal(void) 
{
    ShowWindow(s_win_env_cour->win_graph, SW_RESTORE);
    SetForegroundWindow(s_win_env_cour->win_graph);
    clear_dibs( );
}

/*------------------------------
*   SUBROUTINE X_CLPL
*    Clear Plot(Lower Window) 
*/  
void win_x_clpl(void) 
{
    ShowWindow(s_win_env_cour->win_graph, SW_MINIMIZE);
}

/*-------------------------
*   SUBROUTINE X_GRAPHW
*    Set Focus back to the graph window 
*/  
void x_graphw(void) 
{
    SetForegroundWindow(s_win_env_cour->win_graph);
}

static graph_api_t s_win_graph_api = {
    win_creer_genv,
    win_on_set_genv,
    win_on_free_genv,
    win_refresh_window,
    NULL,
    win_move_window,
    win_clear_window,
    win_get_corners,
    win_get_image_width,
    win_new_graph,
    win_pen_colors,
    win_create_edit_lut_window,
    win_open_x,
    win_x_pen_invert,
    win_x_movp1,
    win_x_movp2,
    win_x_fill_poly,
    win_x_curs,
    NULL,
    NULL,
    win_x_weigh,
    win_x_dash,
    win_x_test_event,
    win_ximage_loadrgb,
    win_ximage_inquire,
    win_x_affiche_image,
    win_x_clal,
    win_x_clpl,
    win_x_cmdwin,
    win_x_size,
    win_x_flush,
    win_x_close,
};

BOOL init_win_gtv(HANDLE hInstance, DWORD ul_reason_being_called, LPVOID lpReserved)
{
    WNDCLASS wc;
    unsigned long err;
    MSG msg;

    switch( ul_reason_being_called ) {
    case DLL_PROCESS_ATTACH:

        hInst = hInstance;

        wc.style         =  CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc   = (WNDPROC) WndProc;
        wc.cbClsExtra    = 0;
        wc.cbWndExtra    = 0;
        wc.hInstance     = hInstance;
        wc.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
        wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        wc.lpszMenuName  = ClassName;
        wc.lpszClassName = WhiteDev;

        if (!RegisterClass(&wc)) {
            err = GetLastError();
            gtv_c_message(seve_e, "?", "RegisterClass failed err = %d", err);
        }

        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+2);
        wc.lpszMenuName  = ClassName;
        wc.lpszClassName = BlackDev;


        if (!RegisterClass(&wc)) {
            err = GetLastError();
            gtv_c_message(seve_e, "?", "RegisterClass failed err = %d", err);
        }

        wc.style         =  CS_OWNDC;
        wc.lpfnWndProc   = (WNDPROC) HsvdrawWndProc;
        wc.lpszClassName = (LPSTR) TEXT("HSVDRAW");

        if (!RegisterClass (&wc)) {
            MessageBox (NULL,
                (LPCTSTR) "DllMain(): RegisterClass() failed",
                (LPCTSTR) "Err! - DIALOGS.DLL",
                MB_OK | MB_ICONEXCLAMATION);

            return FALSE;
        }


        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
            continue;
        }

        BlackBrush = CreateSolidBrush(RGB(0, 0, 0));
        WhiteBrush = CreateSolidBrush(RGB(255, 255, 255)); 

        InitCommonControls(); // Necessary for TrackBars

        sprintf(testlut, "%s", "colortest.lut");

        break;
    }

    return(1);
}

#define init_graph_api CFC_EXPORT_NAME( init_graph_api)

void CFC_API init_graph_api()
{
    set_graph_api( &s_win_graph_api);
}
