//
// Copyright (C) 1999-2002 Toshikaz Hirabayashi
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// TOSHIKAZ HIRABAYASHI BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Except as contained in this notice, the name of Toshikaz Hirabayashi shall
// not be used in advertising or otherwise to promote the sale, use or other
// dealings in this Software without prior written authorization from
// Toshikaz Hirabayashi.

#include <basic.h>
#include <btron/WSDbtronAppDev.h>
#include <btron/WSDbtronDraw.h>
#include <WSCbase.h>
#include <WSDfont.h>
#include <WSCfontSet.h>
#include <WSDcolor.h>
#include <WSCcolorSet.h>
#include <WSDimage.h>
#include <WSCimageSet.h>
#include <WSCstring.h>
#include <WSClocaleSet.h>
#include <tstring.h>

#define MEMGID
//#define F_MEMGID

//#define TDBG

WSMFclassInit(WSDbtronDraw,WSCroot);
extern void WSGFbtronDrawString(TC* str,WSDfont* fn,GID gid,W fg,W bg,long len,short,short,long,WSCbool,long,long,long);
 
#if 0
static long fgcolor = -100;
static long bgcolor = -100;
static WSCulong _fg_value_no = 0xffffffff;
static WSCulong _bg_value_no = 0xffffffff;
static signed char _fill_type = -1;

static char _line_dash_type1[] = {3, 3};
static char _line_dash_type2[] = {10, 10};
static char _line_dash_type3[] = {20, 20};
static char _line_dash_type4[] = {20, 5, 5, 5};
static char _line_dash_type5[] = {20, 5, 5, 5, 5, 5};
static char _line_dash_type6[] = {40, 5, 5, 5};
static char _line_dash_type7[] = {40, 5, 5, 5, 5, 5};
static char _line_dash_type8[] = {1, 2};

static int _line_dash_type_seg1 = 2;
static int _line_dash_type_seg2 = 2;
static int _line_dash_type_seg3 = 2;
static int _line_dash_type_seg4 = 4;
static int _line_dash_type_seg5 = 6;
static int _line_dash_type_seg6 = 4;
static int _line_dash_type_seg7 = 6;
static int _line_dash_type_seg8 = 2;
#endif

static UB _hatch_pattern1[] = {0x03, 0, 0x03, 0, 0x0c, 0, 0x0c, 0, 0x30, 0, 0x30, 0, 0xc0, 0, 0xc0};
static UB _hatch_pattern2[] = {0xc0, 0, 0xc0, 0, 0x30, 0, 0x30, 0, 0x0c, 0, 0x0c, 0, 0x03, 0, 0x03};
static UB _hatch_pattern3[] = {0xcc, 0, 0xcc, 0, 0xcc, 0, 0xcc, 0, 0xcc, 0, 0xcc, 0, 0xcc, 0, 0xcc};
static UB _hatch_pattern4[] = {0xff, 0, 0xff, 0, 0x00, 0, 0x00, 0, 0xff, 0, 0xff, 0, 0x00, 0, 0x00};
static UB _hatch_pattern5[] = {0xcc, 0, 0xcc, 0, 0x33, 0, 0x33, 0, 0xcc, 0, 0xcc, 0, 0x33, 0, 0x33};
static UB _hatch_pattern6[] = {0xff, 0, 0xff, 0, 0xcc, 0, 0xcc, 0, 0xff, 0, 0xff, 0, 0xcc, 0, 0xcc};
static UB _hatch_pattern7[] = {0xcc, 0, 0xcc, 0, 0x00, 0, 0x00, 0, 0xcc, 0, 0xcc, 0, 0x00, 0, 0x00};
static UB _hatch_pattern8[] = {0xcc, 0, 0xaa, 0, 0xcc, 0, 0xaa, 0, 0xcc, 0, 0xaa, 0, 0xcc, 0, 0xaa};
#if 0
static Pixmap _hatch[9] = { 0,0,0,0,0,0,0,0,0 };
static short _clip_x = -1;
static short _clip_y = -1;
static short _clip_w = -1;
static short _clip_h = -1;
#endif

WSDbtronDraw::WSDbtronDraw(){
  _fg_cno = -100;
  _bg_cno = -100;
  _fg_value = 0;
  _bg_value = 0;
  _fg_col = NULL;
  _bg_col = NULL;
  _line_type_val = LN_SOLID;
  _line_width = -1;
  _line_type = -1;
  _clipping = False;
  _fill_mask = FILL100;
}
WSDbtronDraw::~WSDbtronDraw(){}

long WSDbtronDraw::setForeColor(short cno){
  short ret = _fg_cno;
  if (_fg_cno != cno){
    _fg_col = WSGIappColorSet()->getColor(cno);
    if (_fg_col != NULL){
      _fg_cno = cno;
      _fg_value = (W)_fg_col->getValue1();
    }
  }else{
    if (_fg_col != NULL){
      _fg_value = (W)_fg_col->getValue1();
    }
  }
  return (long)ret;
}

long WSDbtronDraw::setBackColor(short cno){
  short ret = _bg_cno;
  if (_bg_cno != cno){
    _bg_col = WSGIappColorSet()->getColor(cno);
    if (_bg_col != NULL){
      _bg_cno = cno;
      _bg_value = (W)_bg_col->getValue1();
    }
  }else{
    if (_bg_col != NULL){
      _bg_value = (W)_bg_col->getValue1();
    }
  }
  return (long)ret;
}
long WSDbtronDraw::setForeColor(WSDcolor* color){
  short bk = _fg_cno;
  if (color == NULL){
    return bk;
  }
  short cno = color->getId();
  if (_fg_cno == cno){
    _fg_value = (W)color->getValue1();
  }else{
    _fg_col = color;
    _fg_cno = _fg_col->getId();
    _fg_value = (W)_fg_col->getValue1();
  }
  return bk;
}

long WSDbtronDraw::setBackColor(WSDcolor* color){
  short bk = _bg_cno;
  if (color == NULL){
    return bk;
  }
  short cno = color->getId();
  if (_bg_cno == cno){
    _bg_value = (W)color->getValue1();
  }else{
    _bg_col = color;
    _bg_cno = _bg_col->getId();
    _bg_value = (W)_bg_col->getValue1();
  }
  return bk;
}
long WSDbtronDraw::setLineWidth(short width){
  if (width == 0){
    width = 1;
  }
  if (_line_width == width){
    return _line_width;
  }

  long bk = _line_width;
  _line_width = width;

  long linet = _line_type;
  _line_type = -1; 
  setLineDashType(linet);

  return bk;
}


long WSDbtronDraw::setLineDashType(char type){
  if (_line_type == type){
    return type;
  }
  long bk = _line_type;
  _line_type = type;
  switch(type){
    case 0:
      _line_type_val = LN_SOLID;
      break;
    case 1:
      _line_type_val = LN_DOT;
      break;
    case 2:
      _line_type_val = LN_DASH;
      break;
    case 3:
      _line_type_val = LN_DASH;
      break;
    case 4:
      _line_type_val = LN_DDASH;
      break;
    case 5:
      _line_type_val = LN_DDDASH;
      break;
    case 6:
      _line_type_val = LN_DDASH;
      break;
    case 7:
      _line_type_val = LN_DDDASH;
       break;
    case 8:
      _line_type_val = LN_DOT;
       break;
    default:
       break;
  }
  return bk;
}
long WSDbtronDraw::setHatchPattern(char type){
  if (_fill_type == type){
    return type;
  }
  _fill_mask = FILL100;
  long bk = _fill_type;
  _fill_type = type;
  switch(type){
    case 1: _fill_mask = _hatch_pattern1;
            break;
    case 2: _fill_mask = _hatch_pattern2;
            break;
    case 3: _fill_mask = _hatch_pattern3;
            break;
    case 4: _fill_mask = _hatch_pattern4;
            break;
    case 5: _fill_mask = _hatch_pattern5;
            break;
    case 6: _fill_mask = _hatch_pattern6;
            break;
    case 7: _fill_mask = _hatch_pattern7;
            break;
    case 8: _fill_mask = _hatch_pattern8;
            break;
  }
  return bk;
}
long WSDbtronDraw::beginDraw(WSDdev* dev,long val1,long val2,long val3){
  _dev = dev;
  _window = (W)val2;
  _fdev = (WSDbtronFormDev*)dev->cast("WSDbtronFormDev");
  short dx=0,dy=0;
  WSCushort dw = 32767,dh = 32767;

  if (_fdev == NULL){
    WSDdev* pdev = dev->getParentDev();
    if (pdev != NULL){
      _fdev = (WSDbtronFormDev*)pdev->cast("WSDbtronFormDev");
    }
    if (_fdev != NULL){
      _fdev->getAbstSize(&dx,&dy,&dw,&dh);
      _x = -1;
      _y = -1;
      _w = -1;
      _h = -1;
    }
  }else{
    _fdev->getAbstSize(&dx,&dy,&dw,&dh);
    _x = dx;
    _y = dy;
    _w = dw;
    _h = dh;
  }

  if (_gid != (W)val3){
    _gid =     (W)val3;
    _fill_type = -1;
    _fg_cno = WSGFcolor("#000000");
    _fg_col = WSGIappColorSet()->getColor(_fg_cno);
    _fg_value = (W)_fg_col->getValue1();

    _bg_cno = WSGFcolor("#ffffff");
    _bg_col = WSGIappColorSet()->getColor(_bg_cno);
    _bg_value = (W)_bg_col->getValue1();
  }
  _line_width = 1;
  _line_type = 0;
  _line_type_val = LN_SOLID;
  _fill_mask = FILL100;

  if (_fill_type != 0){
    _fill_type = 0;
  }

  if (_fg_col == NULL){
    _fg_col = WSGIappColorSet()->getColor("#000000");
    if (_fg_col == NULL){
      return WS_ERR;
    }
    _fg_cno = _fg_col->getId();
    _fg_value = (W)_fg_col->getValue1();
  }
  if (_bg_col == NULL){
    _bg_col = WSGIappColorSet()->getColor("#ffffff");
    if (_bg_col == NULL){
      return WS_ERR;
    }
    _bg_cno = _bg_col->getId();
    _bg_value = (W)_bg_col->getValue1();
  }
//dbprintf("WSDbtronDraw::beginDraw region=%d,%d,%d,%d dev=%s\n",dx,dy,dw,dh,_dev->getAttachedClient()->getInstanceName());
  RECT r;
  r.c.left = 0+dx;
  r.c.top = 0+dy;
  r.c.right = dw+dx;
  r.c.bottom = dh+dy;
  _clip_x = dx;
  _clip_y = dy;
  _clip_w = dw;
  _clip_h = dw;

//printf("gset_vis4 %d,%d,%d,%d\n",r.c.left,r.c.top,r.c.right,r.c.bottom);
  gset_vis(_gid,r);

  if (_fdev != NULL){
    _fdev->setDefaultRegion();
  }

  return WS_NO_ERR;
}

long WSDbtronDraw::endDraw(){
//dbprintf("WSDbtronDraw::endDraw dev=%s\n",_dev->getAttachedClient()->getInstanceName());
//if (_fdev != NULL){
//dbprintf("WSDbtronDraw::endDraw fdev=%s\n",_fdev->getAttachedClient()->getInstanceName());
//}
#ifdef MEMGID
#ifndef F_MEMGID
  if (_dev->cast("WSDbtronFormDev") != NULL &&
    _w != -1 && _h != -1 &&
     _fdev != NULL && _fdev->getUseMemGID() != False){

    W gid = _fdev->getParentGID();

    RECT from;
    from.c.left = _x;
    from.c.top = _y;
    from.c.right = _x + _w;
    from.c.bottom = _y + _h;

    RECT to;
    to.c.left = _x;
    to.c.top = _y;
    to.c.right = _x + _w;
    to.c.bottom = _y + _h;
dbprintf("WSDbtronDraw::endDraw() start copy bmp %d,%d,%d,%d gid=-0x%x -> 0x%x\n",_x,_y,_w,_h,_gid,gid);
//printf("CP> WSDbtronDraw::endDraw() start copy bmp %d,%d,%d,%d gid=-0x%x -> 0x%x\n",_x,_y,_w,_h,_gid,gid);
    gset_vis(gid,to);
    gcop_bmp(_gid,&from,gid,&to,NULL,G_STORE);
    return WS_NO_ERR;
  }else{
    if (_dev->cast("WSDbtronFormDev") == NULL){
      WSDdev* pdev = _dev->getParentDev();
      if ( pdev != NULL ){
        _dev = pdev; 
        _fdev = (WSDbtronFormDev*)_dev->cast("WSDbtronFormDev");
      }
    }
  }
#endif
#endif
#if 0
  if (_clipping == True){
//    XSetClipMask(_display, _gc ,None);
    _clipping = False;
    _clip_x = -1;
    _clip_y = -1;
    _clip_w = -1;
    _clip_h = -1;
  }
#endif
  return WS_NO_ERR;
}
long WSDbtronDraw::setRegion(short x,short y,WSCushort w,WSCushort h){
//dbprintf("RR> WSDbtronDraw::setRegion %d,%d,%d,%d gid=0x%x dev=%s\n",x,y,w,h,_gid,_dev->getAttachedClient()->getInstanceName());
  RECT r;
  r.c.left = x;
  r.c.top = y;
  r.c.right = x+w;
  r.c.bottom = y+h;
  if (_fdev != NULL){
    short px,py;
    WSCushort pw,ph;
    _fdev->getAbstSize(&px,&py,&pw,&ph);
    short px2,py2;
    _fdev->getAbstPos(&px2,&py2);
    long dx,dy;
    WSCulong dw,dh;
    WSGFandArea(px2 +x, py2 +y,w,h, px,py,pw,ph,&dx,&dy,&dw,&dh);
    r.c.left = dx;
    r.c.top = dy;
    r.c.right = dx+dw;
    r.c.bottom = dy+dh;
    _clip_x = dx;
    _clip_y = dy;
    _clip_w = dw;
    _clip_h = dh;
//dbprintf("RR> fdev=!!!! WSDbtronDraw::setRegion %d,%d,%d,%d return!!! gid=0x%x dev=%s\n",dx,dy,dw,dh,_gid,_dev->getAttachedClient()->getInstanceName());
  }else{
    r.c.left = x;
    r.c.top = y;
    r.c.right = x+w;
    r.c.bottom = y+h;
    _clip_x = x;
    _clip_y = y;
    _clip_w = w;
    _clip_h = h;
//dbprintf("RR> fdev=NULL! WSDbtronDraw::setRegion %d,%d,%d,%d return!!! gid=0x%x dev=%s\n",_clip_x,_clip_y,_clip_w,_clip_h,_gid,_dev->getAttachedClient()->getInstanceName());
  }
  if (_clip_w == 0 || _clip_h == 0){
//dbprintf("RR> WSDbtronDraw::setRegion %d,%d,%d,%d return!!! gid=0x%x dev=%s\n",_clip_x,_clip_y,_clip_w,_clip_h,_gid,_dev->getAttachedClient()->getInstanceName());
    return WS_NO_ERR;
  }
//dbprintf("RR> WSDbtronDraw::setRegion real-> %d,%d,%d,%d gid=0x%x dev=%s\n",_clip_x,_clip_y,_clip_w,_clip_h,_gid,_dev->getAttachedClient()->getInstanceName());
//printf("gset_vis5 %d,%d,%d,%d\n",r.c.left,r.c.top,r.c.right,r.c.bottom);
  if ( _x == -1 && _y == -1 && _w == -1 && _h == -1){
    _x = _clip_x;
    _y = _clip_y;
    _w = _clip_w;
    _h = _clip_h;
  }
  gset_vis(_gid,r);
  return WS_NO_ERR;
}

long WSDbtronDraw::drawArc(short x,short y,WSCushort w,WSCushort h,short a1,short a2){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_gid == 0){
    return WS_ERR;
  }
//  PAT pat = {0,16,16,_fg_value,_fg_value,FILL100};
  PAT pat;
  pat.spat.kind = 0;
  pat.spat.hsize = 8;
  pat.spat.vsize = 8;
  pat.spat.fgcol = _fg_value;
  pat.spat.bgcol = _fg_value;
  pat.spat.mask = FILL100;
  RECT r;
  if (_fdev != NULL){
    short dx,dy;
    _fdev->getAbstPos(&dx,&dy);
    r.c.left = x+dx;
    r.c.top = y+dy;
    r.c.right = x+dx + w;
    r.c.bottom = y+dy + h;
  }else{
    r.c.left = x;
    r.c.top = y;
    r.c.right = x + w;
    r.c.bottom = y + h;
  }
  if (!(((a2 - a1)/64) % 360)){
    gfra_ovl(_gid,r,(_line_type_val<<8)+_line_width,&pat,0,G_STORE);
  }else{
    double vx1 = x + w/2 + cos(3.141592 *a1/64.0/180.0)*w/2;
    double vy1 = y + h/2 - sin(3.141592 *a1/64.0/180.0)*h/2;
    double vx2 = x + w/2 + cos(3.141592 *(a1+a2)/64.0/180.0)*w/2;
    double vy2 = y + h/2 - sin(3.141592 *(a1+a2)/64.0/180.0)*h/2;
    PNT p1;
    PNT p2;
    p2.x = (H)vx1;
    p2.y = (H)vy1;
    p1.x = (H)vx2;
    p1.y = (H)vy2;
    gdra_arc(_gid,r,p1,p2,(_line_type_val<<8)+_line_width,&pat,0,G_STORE);
  }
  return WS_NO_ERR;
}
long WSDbtronDraw::drawFillArc(short x,short y,WSCushort w,WSCushort h,short a1,short a2,char kind){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_gid == 0){
    return WS_ERR;
  }
//  PAT pat = {0,16,16,_fg_value,_fg_value,FILL100};
  PAT pat;
  pat.spat.kind = 0;
  pat.spat.hsize = 8;
  pat.spat.vsize = 8;
  pat.spat.fgcol = _fg_value;
  pat.spat.bgcol = -1;
  pat.spat.mask = _fill_mask;
  RECT r;
  if (_fdev != NULL){
    short dx,dy;
    _fdev->getAbstPos(&dx,&dy);
    r.c.left = x+dx;
    r.c.top = y+dy;
    r.c.right = x+dx + w;
    r.c.bottom = y+dy + h;
  }else{
    r.c.left = x;
    r.c.top = y;
    r.c.right = x + w;
    r.c.bottom = y + h;
  }
  if (!(((a2 - a1)/64) % 360)){
    gfil_ovl(_gid,r,&pat,0,G_STORE);
  }else{
    double vx1 = x + w/2 + cos(3.141592 *a1/64.0/180.0)*w/2;
    double vy1 = y + h/2 - sin(3.141592 *a1/64.0/180.0)*h/2;
    double vx2 = x + w/2 + cos(3.141592 *(a1+a2)/64.0/180.0)*w/2;
    double vy2 = y + h/2 - sin(3.141592 *(a1+a2)/64.0/180.0)*h/2;
    PNT p1;
    PNT p2;
    p2.x = (H)vx1;
    p2.y = (H)vy1;
    p1.x = (H)vx2;
    p1.y = (H)vy2;
    if (kind == WS_PI){
      gfil_sec(_gid,r,p1,p2,&pat,0,G_STORE);
    }else{
      gfil_cho(_gid,r,p1,p2,&pat,0,G_STORE);
    }
  }
  return WS_NO_ERR;
}
long WSDbtronDraw::drawLine(short x1,short y1,short x2,short y2){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_gid == 0){
    return WS_ERR;
  }
//  PAT pat = {0,16,16,_fg_value,_fg_value,FILL100};
  PAT pat;
  pat.spat.kind = 0;
  pat.spat.hsize = 8;
  pat.spat.vsize = 8;
  pat.spat.fgcol = _fg_value;
  pat.spat.bgcol = _fg_value;
  pat.spat.mask = FILL100;
  PNT p1;
  PNT p2;
  if (_fdev != NULL){
    short dx,dy;
    _fdev->getAbstPos(&dx,&dy);
    p1.x = x1+dx;
    p1.y = y1+dy;
    p2.x = x2+dx;
    p2.y = y2+dy;
  }else{
    p1.x = x1;
    p1.y = y1;
    p2.x = x2;
    p2.y = y2;
  }
  gdra_lin(_gid,p1,p2,(_line_type_val<<8)+_line_width,&pat,G_STORE);
  return WS_NO_ERR;
}
long WSDbtronDraw::drawLines(WSCpoint* points,long num){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_gid == 0){
    return WS_ERR;
  }
//  PAT pat = {0,16,16,_fg_value,_fg_value,FILL100};
  PAT pat;
  pat.spat.kind = 0;
  pat.spat.hsize = 8;
  pat.spat.vsize = 8;
  pat.spat.fgcol = _fg_value;
  pat.spat.bgcol = _fg_value;
  pat.spat.mask = FILL100;
  PNT p1;
  PNT p2;
  if (_fdev != NULL){
    short dx,dy;
    _fdev->getAbstPos(&dx,&dy);
    long i;
    for(i=0; i<num-1;i++){
      p1.x = points[i].x+dx;
      p1.y = points[i].y+dy;
//      if (i== num-1){
//        p2.x = points[0].x+dx;
//        p2.y = points[0].y+dy;
//      }else{
      p2.x = points[i+1].x+dx;
      p2.y = points[i+1].y+dy;
//      }
      gdra_lin(_gid,p1,p2,(_line_type_val<<8)+_line_width,&pat,G_STORE);
    }
  }else{
    long i;
    for(i=0; i<num-1;i++){
      p1.x = points[i].x;
      p1.y = points[i].y;
//      if (i== num-1){
//        p2.x = points[0].x;
//        p2.y = points[0].y;
//      }else{
      p2.x = points[i+1].x;
      p2.y = points[i+1].y;
//      }
      gdra_lin(_gid,p1,p2,(_line_type_val<<8)+_line_width,&pat,G_STORE);
    }
  }
  return WS_NO_ERR;
}
long WSDbtronDraw::drawRect(short x,short y,WSCushort w,WSCushort h){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_gid == 0){
    return WS_ERR;
  }
//  PAT pat = {0,16,16,_fg_value,_fg_value,FILL100};
  PAT pat;
  pat.spat.kind = 0;
  pat.spat.hsize = 8;
  pat.spat.vsize = 8;
  pat.spat.fgcol = _fg_value;
  pat.spat.bgcol = _fg_value;
  pat.spat.mask = FILL100;
  RECT r;
  if (_fdev != NULL){
    short dx,dy;
    _fdev->getAbstPos(&dx,&dy);
    r.c.left = x+dx;
    r.c.top = y+dy;
    r.c.right = x+dx + w;
    r.c.bottom = y+dy + h;
  }else{
    r.c.left = x;
    r.c.top = y;
    r.c.right = x + w;
    r.c.bottom = y + h;
  }
  gfra_rec(_gid,r,(_line_type_val<<8)+_line_width,&pat,0,G_STORE);
  return WS_NO_ERR;
}
long WSDbtronDraw::drawFillRect(short x,short y,WSCushort w,WSCushort h){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_gid == 0){
    return WS_ERR;
  }
//  PAT pat = {0,16,16,_fg_value,_fg_value,FILL100};
  PAT pat;
  pat.spat.kind = 0;
  pat.spat.hsize = 8;
  pat.spat.vsize = 8;
  pat.spat.fgcol = _fg_value;
  pat.spat.bgcol = -1;
  pat.spat.mask = _fill_mask;
  RECT r;
  if (_fdev != NULL){
    short dx,dy;
    _fdev->getAbstPos(&dx,&dy);
    r.c.left = x+dx;
    r.c.top = y+dy;
    r.c.right = x+dx + w;
    r.c.bottom = y+dy + h;
  }else{
    r.c.left = x;
    r.c.top = y;
    r.c.right = x + w;
    r.c.bottom = y + h;
  }
//dbprintf("WSDbtronDraw::drawFillRect %d,%d,(real=%d,%d),%d,%d gid=0x%x\n",x,y,r.c.left,r.c.top,w,h,_gid);
  gfil_rec(_gid,r,&pat,0,G_STORE);
  return WS_NO_ERR;
}
long WSDbtronDraw::drawRects(WSCrect* rects,long num){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_gid == 0){
    return WS_ERR;
  }
//  PAT pat = {0,16,16,_fg_value,_fg_value,FILL100};
  PAT pat;
  pat.spat.kind = 0;
  pat.spat.hsize = 8;
  pat.spat.vsize = 8;
  pat.spat.fgcol = _fg_value;
  pat.spat.bgcol = _fg_value;
  pat.spat.mask = FILL100;
  long i;
  RECT r;
  short dx=0,dy=0;
  if (_fdev != NULL){
    _fdev->getAbstPos(&dx,&dy);
  }
   for(i=0; i<num; i++){
    r.c.left = rects[i].x+dx;
    r.c.top = rects[i].y+dy;
    r.c.right = rects[i].x+dx + rects[i].width;
    r.c.bottom = rects[i].y+dy + rects[i].height;
    gfra_rec(_gid,r,(_line_type_val<<8)+_line_width,&pat,0,G_STORE);
  }
  return WS_NO_ERR;
}

long WSDbtronDraw::drawFillRects(WSCrect* rects,long num){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_gid == 0){
    return WS_ERR;
  }
//  PAT pat = {0,16,16,_fg_value,_fg_value,FILL100};
  PAT pat;
  pat.spat.kind = 0;
  pat.spat.hsize = 8;
  pat.spat.vsize = 8;
  pat.spat.fgcol = _fg_value;
  pat.spat.bgcol = -1;
  pat.spat.mask = _fill_mask;
  long i;
  RECT r;
  short dx=0,dy=0;
  if (_fdev != NULL){
    _fdev->getAbstPos(&dx,&dy);
  }
  for(i=0; i<num; i++){
    r.c.left = rects[i].x +dx;
    r.c.top = rects[i].y +dy;
    r.c.right = rects[i].x +dx + rects[i].width;
    r.c.bottom = rects[i].y +dy + rects[i].height;
    gfil_rec(_gid,r,&pat,0,G_STORE);
  }
  return WS_NO_ERR;
}
long WSDbtronDraw::drawPoly(WSCpoint* points,long num){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_gid == 0){
    return WS_ERR;
  }
//  PAT pat = {0,16,16,_fg_value,_fg_value,FILL100};
  PAT pat;
  pat.spat.kind = 0;
  pat.spat.hsize = 8;
  pat.spat.vsize = 8;
  pat.spat.fgcol = _fg_value;
  pat.spat.bgcol = _fg_value;
  pat.spat.mask = FILL100;
  POLY* poly = new POLY[num];
  if (_fdev != NULL){
    short dx,dy;
    _fdev->getAbstPos(&dx,&dy);
    long i;
    for(i=0; i<num;i++){
      poly->pt[i].x = points[i].x+dx;
      poly->pt[i].y = points[i].y+dy;
    }
    poly->round = 0;
    poly->size = num;
  }else{
    long i;
    for(i=0; i<num;i++){
      poly->pt[i].x = points[i].x;
      poly->pt[i].y = points[i].y;
    }
    poly->round = 0;
    poly->size = num;
  }
  gfra_pol(_gid,poly,(_line_type_val<<8)+_line_width,&pat,G_STORE);
  return WS_NO_ERR;
}

long WSDbtronDraw::drawFillPoly(WSCpoint* points,long num){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_gid == 0){
    return WS_ERR;
  }
//  PAT pat = {0,16,16,_fg_value,_fg_value,FILL100};
  PAT pat;
  pat.spat.kind = 0;
  pat.spat.hsize = 8;
  pat.spat.vsize = 8;
  pat.spat.fgcol = _fg_value;
  pat.spat.bgcol = -1;
  pat.spat.mask = _fill_mask;
  POLY* poly = new POLY[num];
  if (_fdev != NULL){
    short dx,dy;
    _fdev->getAbstPos(&dx,&dy);
    long i;
    for(i=0; i<num;i++){
      poly->pt[i].x = points[i].x+dx;
      poly->pt[i].y = points[i].y+dy;
    }
    poly->round = 0;
    poly->size = num;
  }else{
    long i;
    for(i=0; i<num;i++){
      poly->pt[i].x = points[i].x;
      poly->pt[i].y = points[i].y;
    }
    poly->round = 0;
    poly->size = num;
  }
  gfil_pol(_gid,poly,&pat,G_STORE);
  return WS_NO_ERR;
}

long WSDbtronDraw::drawImage(short x,short y,WSCushort w,WSCushort h,WSDimage* image,char align){
dbprintf(">> WSDbtronDraw::drawImage start\n");
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_gid == 0){
    return WS_ERR;
  }
  GID mem_gid1 = (GID)image->getValue1();
  GID mem_gid2 = (GID)image->getValue2();
dbprintf(">> WSDbtronDraw::drawImage mem_gid1=0x%x\n",mem_gid1);
  WSCushort pw = image->getImageWidth();
  WSCushort ph = image->getImageHeight();
  short xoff = 0;
  short yoff = 0;
  if (align == WS_CENTER){
    xoff = ((short)w - (short)pw)/2;
    yoff = ((short)h - (short)ph)/2;
  }else
  if (align == WS_LEFT){
    yoff = ((short)h - (short)ph)/2;
  }else
  if (align == WS_LEFT_TOP){
    xoff = 0;
    yoff = 0;
  }else
  if (align == WS_TOP){
    xoff = ((short)w - (short)pw)/2;
    yoff = 0;
  }else
  if (align == WS_RIGHT){
    xoff = ((short)w - (short)pw);
    yoff = ((short)h - (short)ph)/2;
  }else
  if (align == WS_BOTTOM){
    xoff = ((short)w - (short)pw)/2;
    yoff = ((short)h - (short)ph);
  }else
  if (align == WS_LEFT_BOTTOM){
    xoff = 0;
    yoff = ((short)h - (short)ph);
  }else
  if (align == WS_RIGHT_TOP){
    xoff = ((short)w - (short)pw);
    yoff = 0;
  }else
  if (align == WS_RIGHT_BOTTOM){
    xoff = ((short)w - (short)pw);
    yoff = ((short)h - (short)ph);
  }
  if ((long)mem_gid1 == -1 || mem_gid1 == 0){
    return WS_NO_ERR;
  }
//  if ((long)mem_gid2 != -1 && mem_gid2 != 0){
//dbprintf("WSDbtronDraw::drawImage need implement about mask pix\n");
//  }
  short px,py;
  if (_fdev != NULL){
    _fdev->getAbstPos(&px,&py);
  }else{
    px = 0;
    py = 0;
  }
  long dx1,dy1;
  long dw1,dh1;
  long dx,dy;
  long dw,dh;
  WSGFandArea(x,y,w,h,_clip_x-px,_clip_y-py,_clip_w,_clip_h,&dx1,&dy1,(WSCulong*)&dw1,(WSCulong*)&dh1);
  WSGFandArea(dx1,dy1,dw1,dh1,x+xoff,y+yoff,pw,ph,&dx,&dy,(WSCulong*)&dw,(WSCulong*)&dh);
  if ((long)mem_gid2 != -1 && mem_gid2 != 0){
    if (WSGIbtronAppDev()->haveColorMap() != False){
      RECT from;
      from.c.left = 0;
      from.c.top = 0;
      from.c.right = pw;
      from.c.bottom = ph;
      RECT to;
      to.c.left = 0;
      to.c.top = 0;
      to.c.right = pw;
      to.c.bottom = ph;
      gcop_bmp(mem_gid2,&from,mem_gid1,&to,NULL,G_AND);
    }
  }
  RECT from;
  from.c.left = dx -x -xoff;
  from.c.top = dy -y -yoff;
  from.c.right = dw +dx -x -xoff;
  from.c.bottom = dh +dy -y -yoff;
  RECT to;
  to.c.left = dx+px;
  to.c.top = dy+py;
  to.c.right = dw +dx + px;
  to.c.bottom = dh +dy + py;
dbprintf("WSDbtronDraw::drawImage() start copy bmp %d,%d,%d,%d\n",dx+px,dy+py,dw,dh);
  if ((long)mem_gid2 != -1 && mem_gid2 != 0){
    if (WSGIbtronAppDev()->haveColorMap() == False){
      gcop_bmp(mem_gid2,&from,_gid,&to,NULL,G_AND);
    }else{
      gcop_bmp(mem_gid2,&from,_gid,&to,NULL,G_ANDN);
    }
    gcop_bmp(mem_gid1,&from,_gid,&to,NULL,G_OR);
  }else{
    gcop_bmp(mem_gid1,&from,_gid,&to,NULL,G_STORE);
  }
dbprintf("WSDbtronDraw::drawImage() done\n");
#if 0
  XCopyArea(_display,pix1,_window,_gc, dx -x -xoff,dy -y -yoff, dw,dh,dx,dy);
  if ((long)pix2 != -1 && pix2 != 0){
    short clx = _clip_x;
    _clip_x = -1;
    setRegion(clx,_clip_y,_clip_w,_clip_h);
  }
#endif
  return WS_NO_ERR;
}
long WSDbtronDraw::drawStretchedImage(short x,short y,WSCushort w,WSCushort h,WSDimage* image){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_gid == 0){
    return WS_ERR;
  }
  GID mem_gid1 = (GID)image->getValue1();
  GID mem_gid2 = (GID)image->getValue2();

dbprintf(">> WSDbtronDraw::drawStretchedImage mem_gid=0x%x\n",mem_gid1);
  if ((long)mem_gid1 == -1 || mem_gid1 == 0){
    return WS_NO_ERR;
  }
//  if ((long)mem_gid2 != -1 && mem_gid2 != 0){
//dbprintf("WSDbtronDraw::drawStretchedImage need implement about mask pix\n");
//  }

  WSCulong iw = image->getImageWidth();
  WSCulong ih = image->getImageHeight();

  short px,py;
  if (_fdev != NULL){
    _fdev->getAbstPos(&px,&py);
  }else{
    px = 0;
    py = 0;
  }
  if ((long)mem_gid2 != -1 && mem_gid2 != 0){
    if (WSGIbtronAppDev()->haveColorMap() != False){
      RECT from;
      from.c.left = 0;
      from.c.top = 0;
      from.c.right = iw;
      from.c.bottom = ih;
      RECT to;
      to.c.left = 0;
      to.c.top = 0;
      to.c.right = iw;
      to.c.bottom = ih;
      gcop_bmp(mem_gid2,&from,mem_gid1,&to,NULL,G_AND);
    }
  }
  RECT from;
  from.c.left = 0;
  from.c.top = 0;
  from.c.right = iw;
  from.c.bottom = ih;

  RECT to;
  to.c.left = x + px;
  to.c.top = y + py;
  to.c.right = w +x + px;
  to.c.bottom = h +y + py;
dbprintf("WSDbtronDraw::drawStretchedImage() start copy bmp\n");
  if ((long)mem_gid2 != -1 && mem_gid2 != 0){
    if (WSGIbtronAppDev()->haveColorMap() == False){
      gcop_bmp(mem_gid2,&from,_gid,&to,NULL,G_AND);
    }else{
      gcop_bmp(mem_gid2,&from,_gid,&to,NULL,G_ANDN);
    }
    gcop_bmp(mem_gid1,&from,_gid,&to,NULL,G_OR);
  }else{
    gcop_bmp(mem_gid1,&from,_gid,&to,NULL,G_STORE);
  }
dbprintf("WSDbtronDraw::drawStretchedImage() done\n");

  return WS_NO_ERR;
}


long WSDbtronDraw::drawImage(short x,short y,short sx,short sy,WSCushort w,WSCushort h,WSDimage* image){
dbprintf(">> WSDbtronDraw::drawImage start\n");
  if (_clip_w == 0 || _clip_h == 0){
    return WS_ERR;
  }
  if (_gid == 0){
    return WS_ERR;
  }
  GID mem_gid1 = (GID)image->getValue1();
  GID mem_gid2 = (GID)image->getValue2();
dbprintf(">> WSDbtronDraw::drawImage mem_gid=0x%x\n",mem_gid1);

  if ((long)mem_gid1 == -1 || mem_gid1 == 0){
    return WS_NO_ERR;
  }
//  if ((long)mem_gid2 != -1 && mem_gid2 != 0){
//dbprintf("WSDbtronDraw::drawImage need implement about mask pix\n");
//  }
  short px,py;
  if (_fdev != NULL){
    _fdev->getAbstPos(&px,&py);
  }else{
    px = 0;
    py = 0;
  }

  long dx,dy;
  long dw,dh;
  WSGFandArea(x,y,w,h,_clip_x-px,_clip_y-py,_clip_w,_clip_h,&dx,&dy,(WSCulong*)&dw,(WSCulong*)&dh);
  if ((long)mem_gid2 != -1 && mem_gid2 != 0){
    if (WSGIbtronAppDev()->haveColorMap() != False){
      WSCushort pw = image->getImageWidth();
      WSCushort ph = image->getImageHeight();
      RECT from;
      from.c.left = 0;
      from.c.top = 0;
      from.c.right = pw;
      from.c.bottom = ph;
      RECT to;
      to.c.left = 0;
      to.c.top = 0;
      to.c.right = pw;
      to.c.bottom = ph;
      gcop_bmp(mem_gid2,&from,mem_gid1,&to,NULL,G_AND);
    }
  }
 
  RECT from;
  from.c.left = dx -x +sx;
  from.c.top = dy -y +sy;
  from.c.right = dw +dx -x +sx;
  from.c.bottom = dh +dy -y +sy;
  RECT to;
  to.c.left = dx + px;
  to.c.top = dy + py;
  to.c.right = dw +dx + px;
  to.c.bottom = dh +dy + py;
dbprintf("WSDbtronDraw::drawImage() start copy bmp\n");
  if ((long)mem_gid2 != -1 && mem_gid2 != 0){
    if (WSGIbtronAppDev()->haveColorMap() == False){
      gcop_bmp(mem_gid2,&from,_gid,&to,NULL,G_AND);
    }else{
      gcop_bmp(mem_gid2,&from,_gid,&to,NULL,G_ANDN);
    }
    gcop_bmp(mem_gid1,&from,_gid,&to,NULL,G_OR);
  }else{
    gcop_bmp(mem_gid1,&from,_gid,&to,NULL,G_STORE);
  }
dbprintf("WSDbtronDraw::drawImage() done\n");

  return WS_NO_ERR;
}
long WSDbtronDraw::drawUString(long x,long y,WSCulong w,WSCulong h,
         WSCushort* str,char font,char align,long cur,WSCbool inter_cur,
         long scur1,long scur2){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  char* str1 = WSGFgetString(str,WS_EN_UTF8);
  WSCstring str2(str1,WS_EN_UTF8);
  long ret = drawString(x,y,w,h,&str2,font,align,cur,inter_cur,scur1,scur2);
  delete str1;
  return ret;
}
long WSDbtronDraw::drawFillUString(long x,long y,WSCulong w,WSCulong h,
           WSCushort* str,char font,char align,short cur,WSCbool inter_cur){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  char* str1 = WSGFgetString(str,WS_EN_UTF8);
  WSCstring str2(str1,WS_EN_UTF8);
  long ret = drawFillString(x,y,w,h,&str2,font,align,cur,inter_cur);
  delete str1;
  return ret;
}
long WSDbtronDraw::drawString(long x,long y,WSCulong w,WSCulong h,
         WSCstring* str,char font,char align,long cur,WSCbool inter_cur,
         long scur1,long scur2){
#ifdef TDBG
//printf("WSDbtronDraw::drawString start %d\n",WSGFclocktime());
#endif
dbprintf("ST WSDbtronDraw::drawString start %d %s fg=%s xy=%d,%d\n",WSGFclocktime(),str->getString(WS_EN_EUCJP),WSGIappColorSet()->getColor(_fg_cno)->getColorName(),x,y);
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }

  if (scur1 == scur2){
    scur1 = scur2 = 0;
  }
  if (scur1 > scur2){
    long bk = scur1;
    scur1 = scur2;
    scur2 = bk;
  }
  short dx=0,dy=0;
  if (_fdev != NULL){
    _fdev->getAbstPos(&dx,&dy);
    x = x+dx;
    y = y+dy;
  }

  short clx_bk = _clip_x;
  short cly_bk = _clip_y;
  WSCushort clw_bk = _clip_w;
  WSCushort clh_bk = _clip_h;
  long clx,cly;
  WSCulong clw,clh;
  WSGFandArea(x,y,w,h,_clip_x,_clip_y,_clip_w,_clip_h,&clx,&cly,&clw,&clh);

  RECT r;
  r.c.left = clx;
  r.c.top = cly;
  r.c.right = clx+clw;
  r.c.bottom = cly+clh;
  gset_vis(_gid,r);

  WSDfont* fn = WSGIappFontSet()->getFont(font);
  if (fn == NULL){
    fn = WSGIappFontSet()->getDefaultFont();
    if (fn == NULL){
      return WS_ERR;
    }
  }
  FSSPEC* fnt = (FSSPEC*)fn->getValue1();
  gset_fon(_gid,fnt); //TEST

  long fheight = fn->getFontHeight();
  long fheight2 = fn->getFontHeight();

  if (str->isExist("\n") == -1){
    WSCrect   area;
    area.setRect(x,y,w,h);
    WSCpoint  point;
    WSGFcalcOneLineStringAddr(str,&area,align,fn,&point);
    char* tstr;
    tstr = str->getString(WS_EN_UTF8);

extern TC* WSGFbtronStringToTc(char*,long*);
    long tclen=0;
    TC* tstr2 = WSGFbtronStringToTc(tstr,&tclen);
    if (tstr2 == NULL){
      return 0;
    }
dbprintf("ST WSDbtronDraw::drawString draw %s fg=%s xy=%d,%d fh=%d\n",str->getString(WS_EN_EUCJP),WSGIappColorSet()->getColor(_fg_cno)->getColorName(),point.x,point.y+fheight,fheight);
//    gset_chp(_gid,x,y + fheight,(Bool)True);
    WSGFbtronDrawString(tstr2,fn,_gid,_fg_value,_bg_value,
                        tclen,point.x,point.y+fheight,
                        cur,inter_cur,_line_width,scur1,scur2);

    delete tstr2;

    r.c.left = clx_bk;
    r.c.top = cly_bk;
    r.c.right = clx_bk+clw_bk;
    r.c.bottom = cly_bk+clh_bk;
    gset_vis(_gid,r);

    return WS_NO_ERR;
  }

  long num;
  WSCrect area;
  area.setRect(x,y,w,h);
  WSCpoint* points;

  WSGFcalcStringAddr(str,&area,align,fn,&points,&num);
  long i;
  str->seek(0);
  long lpos =0;
  long prelpos =0;
  for(i=0; i < num; i++){

    if (points[i].y + fheight < cly){
      lpos += prelpos;
      prelpos = str->_seek_next_line() +1;
      continue;
    }
    WSCstring lstr;
    lstr = str->gets();

    lpos += prelpos;
    prelpos = lstr.getChars() +1;
    if ((long)(cly + clh) < points[i].y){
      break;
    }
    char* tstr;
    tstr = lstr.getString(WS_EN_UTF8);
    if (cur == -1){
extern TC* WSGFbtronStringToTc(char*,long*);
      long tclen=0;
      TC* tstr2 = WSGFbtronStringToTc(tstr,&tclen);
      if (tstr2 == NULL){
//printf("ST WSDbtronDraw::drawString draw tstr=NULL!!!\n");
        return 0;
      }

      gset_chp(_gid,points[i].x,points[i].y + fn->getFontHeight(),(Bool)True);
      WSGFbtronDrawString(tstr2,fn,_gid,_fg_value,_bg_value,
                          tclen,points[i].x,points[i].y + fn->getFontHeight(),
                          -1,inter_cur,_line_width,scur1 - lpos,scur2 - lpos);
      delete tstr2;
    }else{
extern TC* WSGFbtronStringToTc(char*,long*);
      long tclen=0;
      TC* tstr2 = WSGFbtronStringToTc(tstr,&tclen);
      if (tstr2 == NULL){
        return 0;
      }

      gset_chp(_gid,points[i].x,points[i].y + fn->getFontHeight(),(Bool)True);
      WSGFbtronDrawString(tstr2,fn,_gid,_fg_value,_bg_value,
                 tclen,points[i].x,points[i].y + fn->getFontHeight(),
                 cur - lpos,inter_cur,_line_width,scur1 - lpos,scur2 - lpos);
      delete tstr2;
    }
  }
  str->seek(0);
  if (num != 0){
    delete points;
  }

  r.c.left = clx_bk;
  r.c.top = cly_bk;
  r.c.right = clx_bk+clw_bk;
  r.c.bottom = cly_bk+clh_bk;
  gset_vis(_gid,r);

  return WS_NO_ERR;
}

long WSDbtronDraw::drawFillString(long x,long y,WSCulong w,WSCulong h,
           WSCstring* str,char font,char align,short cur,WSCbool inter_cur){

  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  W bk = _fg_value;
  _fg_value = _bg_value;
  drawFillRect(x,y,w,h);
  _fg_value = bk;
  drawString(x,y,w,h,str,font,align,cur,inter_cur);

  return WS_NO_ERR;
}

extern WSCulong WSGFxcolorval(WSDcolor*,WSCuchar,WSCuchar,WSCuchar);

long WSDbtronDraw::drawGradation(long type,short c1,short c2,short c3,
                  short x,short y,WSCushort w,WSCushort h,WSCuchar gradm){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
static WSDcolor* color = NULL;
  if (_gid == 0 || _window == 0){
    return WS_ERR;
  }
  short clx_bk = _clip_x;
  short cly_bk = _clip_y;
  WSCushort clw_bk = _clip_w;
  WSCushort clh_bk = _clip_h;

  short dx = 0,dy = 0;
  if (_fdev != NULL){
    _fdev->getAbstPos(&dx,&dy);
    clx_bk = _clip_x - dx;
    cly_bk = _clip_y - dy;
  }

  long clx,cly;
  WSCulong clw,clh;
  WSGFandArea(x,y,w,h,clx_bk,cly_bk,clw_bk,clh_bk,&clx,&cly,&clw,&clh);

  RECT r;
  r.c.left = clx + dx;
  r.c.top = cly + dy;
  r.c.right = clx+clw + dx;
  r.c.bottom = cly+clh + dy;
  gset_vis(_gid,r);

  setForeColor(c2);
  drawFillRect(x,y,w,h);

  WSDcolor* col1 = WSGIappColorSet()->getColor(c1);
  WSDcolor* col2 = WSGIappColorSet()->getColor(c2);
  WSDcolor* col3 = WSGIappColorSet()->getColor(c3);
  long r1,g1,b1;
  long r2,g2,b2;
  long r3,g3,b3;

  if (col1 == NULL || col2 == NULL || col3 == NULL){
    r.c.left = _clip_x;
    r.c.top = _clip_y;
    r.c.right = _clip_x + _clip_w;
    r.c.bottom = _clip_y + _clip_h;
    gset_vis(_gid,r);
    return WS_ERR;
  }



  col1->getRGB(&r1,&g1,&b1);
  col2->getRGB(&r2,&g2,&b2);
  col3->getRGB(&r3,&g3,&b3);
  color = WSGIappColorSet()->getColor((short)0);
  if (color == NULL){
    color = WSGIappColorSet()->getNewColor();
    color->setId(0);
    color->setUsePrivateCell(True);
    WSGIappColorSet()->addColor(color);
  }
  if (gradm != 0){
    setForeColor(c2);
    drawFillRect(x,y,w,h);
  }
  long i;
  if (type == WS_GR_LT_RB || type == WS_GR_RB_LT){
    long max = (w+h)* (100 -gradm)/100;
    long wval = max/64+1;
    for(i=0; i<max;i+=wval){
      long x1 = x +i;
      long y1 = y +i;
      if (i > max/2){ 
        x1 = x + (w+h)*gradm/100 + i;
        y1 = y + (w+h)*gradm/100 + i;
      }
      long val1,val2,val3;
      if (type == WS_GR_LT_RB){
        if (i < max/2){ 
          val1 = (r1 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g1 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b1 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max *2 -i*2)  + r3 * (i *2 -max)) /max;
          val2 = (g2 * (max *2 -i*2)  + g3 * (i *2 -max)) /max;
          val3 = (b2 * (max *2 -i*2)  + b3 * (i *2 -max)) /max;
        }
      }else{
        if (i < max/2){ 
          val1 = (r3 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g3 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b3 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max *2 -i*2)  + r1 * (i *2 -max)) /max;
          val2 = (g2 * (max *2 -i*2)  + g1 * (i *2 -max)) /max;
          val3 = (b2 * (max *2 -i*2)  + b1 * (i *2 -max)) /max;
        }
      }
      if (val1 < 0){
        val1 = 0;
      }
      if (val2 < 0){
        val2 = 0;
      }
      if (val3 < 0){
        val3 = 0;
      }
      if (val1 > 0xff){
        val1 = 0xff;
      }
      if (val2 > 0xff){
        val2 = 0xff;
      }
      if (val3 > 0xff){
        val3 = 0xff;
      }
      long cval = 0x10000000;
      cval |= val1 << 16;
      cval |= val2 << 8;
      cval |= val3;

      PAT pat;
      pat.spat.kind = 0;
      pat.spat.hsize = 8;
      pat.spat.vsize = 8;
      pat.spat.fgcol = cval;
      pat.spat.bgcol = cval;
      pat.spat.mask = FILL100;

      PNT p1;
      PNT p2;
      p1.x = x1+dx;
      p1.y = y +dy;
      p2.x = x +dx;
      p2.y = y1+dy;
      gdra_lin(_gid,p1,p2,(_line_type_val<<8)+wval,&pat,G_STORE);
    }
  }else
  if (type == WS_GR_LB_RT || type == WS_GR_RT_LB){
    long max = (w+h)* (100 -gradm)/100;
    long wval = max/64+1;
    for(i=0; i<max;i+=wval){
      long x1 = x +i;
      long y1 = y +h -i;
      if (i >= max/2){
        x1 = x +i + (w+h) * gradm/100;
        y1 = y +h -i - (w+h) * gradm/100;
      }
      long val1,val2,val3;
      if (type == WS_GR_LB_RT){
        if (i < max/2){ 
          val1 = (r1 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g1 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b1 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max *2 -i*2)  + r3 * (i *2 -max)) /max;
          val2 = (g2 * (max *2 -i*2)  + g3 * (i *2 -max)) /max;
          val3 = (b2 * (max *2 -i*2)  + b3 * (i *2 -max)) /max;
        }
      }else{
        if (i < max/2){ 
          val1 = (r3 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g3 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b3 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max *2 -i*2)  + r1 * (i *2 -max)) /max;
          val2 = (g2 * (max *2 -i*2)  + g1 * (i *2 -max)) /max;
          val3 = (b2 * (max *2 -i*2)  + b1 * (i *2 -max)) /max;
        }
      }
      if (val1 < 0){
        val1 = 0;
      }
      if (val2 < 0){
        val2 = 0;
      }
      if (val3 < 0){
        val3 = 0;
      }
      if (val1 > 0xff){
        val1 = 0xfff;
      }
      if (val2 > 0xff){
        val2 = 0xff;
      }
      if (val3 > 0xff){
        val3 = 0xff;
      }
      long cval = 0x10000000;
      cval |= val1 << 16;
      cval |= val2 << 8;
      cval |= val3;

      PAT pat;
      pat.spat.kind = 0;
      pat.spat.hsize = 8;
      pat.spat.vsize = 8;
      pat.spat.fgcol = cval;
      pat.spat.bgcol = cval;
      pat.spat.mask = FILL100;

      PNT p1;
      PNT p2;
      p1.x = x +dx;
      p1.y = y1+dy;
      p2.x = x1+dx;
      p2.y = y +h+dy;
      gdra_lin(_gid,p1,p2,(_line_type_val<<8)+wval,&pat,G_STORE);
    }
  }else
  if (type == WS_GR_T_B || type == WS_GR_B_T){
    long max = h* (100 -gradm)/100;
    long wval = max/64+1;
    for(i=0; i<max;i+=wval){
      long h1 = i;
      if (h1 >= max/2){
        h1 = i+ h * gradm/100;
      }
      long val1,val2,val3;
      if (type == WS_GR_T_B){
        if (i < max/2){ 
          val1 = (r1 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g1 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b1 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max*2 -i*2)  + r3 * (i *2 -max)) /max;
          val2 = (g2 * (max*2 -i*2)  + g3 * (i *2 -max)) /max;
          val3 = (b2 * (max*2 -i*2)  + b3 * (i *2 -max)) /max;
        }
      }else{
        if (i < max/2){ 
          val1 = (r3 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g3 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b3 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max*2 -i*2)  + r1 * (i *2 -max)) /max;
          val2 = (g2 * (max*2 -i*2)  + g1 * (i *2 -max)) /max;
          val3 = (b2 * (max*2 -i*2)  + b1 * (i *2 -max)) /max;
        }
      }
      if (val1 < 0){
        val1 = 0;
      }
      if (val2 < 0){
        val2 = 0;
      }
      if (val3 < 0){
        val3 = 0;
      }
      if (val1 > 0xff){
        val1 = 0xff;
      }
      if (val2 > 0xff){
        val2 = 0xff;
      }
      if (val3 > 0xff){
        val3 = 0xff;
      }
      long cval = 0x10000000;
      cval |= val1 << 16;
      cval |= val2 << 8;
      cval |= val3;

      PAT pat;
      pat.spat.kind = 0;
      pat.spat.hsize = 8;
      pat.spat.vsize = 8;
      pat.spat.fgcol = cval;
      pat.spat.bgcol = cval;
      pat.spat.mask = FILL100;

      PNT p1;
      PNT p2;
      p1.x = x+dx;
      p1.y = y+h1 +dy;
      p2.x = x+w +dx;
      p2.y = y+h1+dy;
      gdra_lin(_gid,p1,p2,(_line_type_val<<8)+wval,&pat,G_STORE);
    }
  }else{
    long max = w* (100 -gradm)/100;
    long wval = max/64+1;
    for(i=0; i<max; i+=wval){
      long w1 = i;
      if (w1 >= max/2){
        w1 = i+ w * gradm/100;
      }
      long val1,val2,val3;
      if (type == WS_GR_L_R){
        if (i < max/2){ 
          val1 = (r1 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g1 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b1 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max*2 -i*2)  + r3 * (i *2 -max)) /max;
          val2 = (g2 * (max*2 -i*2)  + g3 * (i *2 -max)) /max;
          val3 = (b2 * (max*2 -i*2)  + b3 * (i *2 -max)) /max;
        }
      }else{
        if (i < max/2){ 
          val1 = (r3 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g3 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b3 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max*2 -i*2)  + r1 * (i *2 -max)) /max;
          val2 = (g2 * (max*2 -i*2)  + g1 * (i *2 -max)) /max;
          val3 = (b2 * (max*2 -i*2)  + b1 * (i *2 -max)) /max;
        }
      }
      if (val1 < 0){
        val1 = 0;
      }
      if (val2 < 0){
        val2 = 0;
      }
      if (val3 < 0){
        val3 = 0;
      }
      if (val1 > 0xff){
        val1 = 0xff;
      }
      if (val2 > 0xff){
        val2 = 0xff;
      }
      if (val3 > 0xff){
        val3 = 0xff;
      }
      long cval = 0x10000000;
      cval |= val1 << 16;
      cval |= val2 << 8;
      cval |= val3;

      PAT pat;
      pat.spat.kind = 0;
      pat.spat.hsize = 8;
      pat.spat.vsize = 8;
      pat.spat.fgcol = cval;
      pat.spat.bgcol = cval;
      pat.spat.mask = FILL100;

      PNT p1;
      PNT p2;
      p1.x = x+w1+dx;
      p1.y = y +dy;
      p2.x = x+w1 +dx;
      p2.y = y+h+dy;
      gdra_lin(_gid,p1,p2,(_line_type_val<<8)+wval,&pat,G_STORE);
    }
  }
  long linet = _line_type;
  _line_type = -1;
  setLineDashType(linet);
  r.c.left = clx_bk + dx;
  r.c.top = cly_bk + dy;
  r.c.right = clx_bk+clw_bk + dx;
  r.c.bottom = cly_bk+clh_bk + dy;

  gset_vis(_gid,r);

  return WS_NO_ERR;
}

