//
// Copyright (C) 1999-2004 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 <WScom.h>
#include <WSCvtoggle.h>
#include <WSCclassInformation.h>
#include <WSCdevice.h>
#include <WSDdev.h>
#include <WSCimageSet.h>
#include <WSDkeyboard.h>
#include <WSkeysym.h>
#include <WSDfont.h>
#include <WSCfontSet.h>
#include <WSClistData.h>
#include <WSCbaseList.h>
#include <WSCblink.h>
#include <WSDappDev.h>

WSMFguiClassInitialize(WSCvtoggle, WSCvlabel);
WSMFversion(WSCvtoggle, WSCvlabel);

WSClistData* WSCvtoggle::_tgl_list = NULL;

WSClistData* WSCvtoggle::_get_toggle_list() {
  if (_tgl_list == NULL) {
    _tgl_list = new WSClistData();
  }
  return _tgl_list;
}


WSCvtoggle::WSCvtoggle(WSCbase* base, char* objname):
             WSCvlabel(base, objname){

  _get_toggle_list()->add(this);
  _register_focus_move();
  _press_status = False;

  _select_string   = NULL;
  _indicator_on    = True;
  _indicator_type  = WS_IN_OUT;
  _indicator_size  = 20;
  _indicator_shadow_thick = 2;
//  _indicator_color = WSGFcolor("gray85");
//  _select_color    = WSGFcolor("gray75");
  _indicator_color = WS_DF_NWBACKCOLOR;
  _select_color    = WS_DF_MENUSELECTCOLOR;
  _indicator_pixmap = -1;
  _select_pixmap   = -1;
  _unique          = False;
  _group_name      = WSGFstrdup("");
  _id              = 0;
  _select_reset    = False;
  _enable_focus_move = True;
  _td_name = WSGFstrdup("");
  _bd_name = WSGFstrdup("");
  _ld_name = WSGFstrdup("");
  _rd_name = WSGFstrdup("");
  _tb_name = WSGFstrdup("");
  _btb_name = WSGFstrdup("");
  _toggle_status = False;
  WSGIappObjectList()->addEvent(this,WSEV_GUI_POLICY_CH);

  WSMFpropertyCreateStart
    WSMFparentCheckVerSrc(WSCvtoggle);

    WSMFpropertyCreate(WSNselectString, char*, _select_string ,WSSselectString);
    WSMFpropertyCreate(WSNindicatorOn, WSCbool,_indicator_on,WSSindicatorOn );
    WSMFpropertySetSelection(WSRbool1, WSRbool1D);
    WSMFpropertyCreate(WSNindicatorType,WSCuchar, _indicator_type,WSSindicatorType);
    WSMFpropertySetSelection(WSRindicatorType, WSRindicatorTypeD);
    WSMFpropertyCreate(WSNindicatorSize,WSCuchar, _indicator_size,WSSindicatorSize);
    WSMFpropertyCreate(WSNindicatorShadow, WSCuchar, _indicator_shadow_thick,WSSindicatorShadow);
    WSMFpropertyCreate(WSNindicatorColor,  short,_indicator_color,WSSindicatorColor );
    WSMFpropertyCreate(WSNindicatorPixmap,short,_indicator_pixmap,WSSindicatorPixmap);
    WSMFpropertyCreate(WSNselectColor, short,_select_color,WSSselectColor );
    WSMFpropertyCreate(WSNselectPixmap, short, _select_pixmap,WSSselectPixmap );
    WSMFpropertyCreate(WSNunique,    WSCbool,   _unique,WSSunique  );
    WSMFpropertySetSelection( WSRbool3, WSRbool3D);
    WSMFpropertyCreate(WSNgroup,           char*,     _group_name,WSSgroup );
    WSMFpropertyCreate(WSNselectReset,     WSCbool,   _select_reset,WSSselectReset);
    WSMFpropertySetSelection(WSRbool1, WSRbool1D);

    WSMFpropertyCreate(WSNid,               short,     _id,WSSid  );
    WSMFpropertyCreate(WSNenableFocusMove, WSCbool,  _enable_focus_move,WSSenableFocusMove);
    WSMFpropertySetSelection(WSRbool1, WSRbool1D);
    WSMFpropertyCreate(WSNupward,    char*,   _td_name,WSSupward);
    WSMFpropertyCreate(WSNdownward, char*,   _bd_name,WSSdownward);
    WSMFpropertyCreate(WSNleftward,   char*,   _ld_name,WSSleftward);
    WSMFpropertyCreate(WSNrightward,  char*,   _rd_name,WSSrightward);
    WSMFpropertyCreate(WSNtab,  char*,   _tb_name,WSStab);
    WSMFpropertyCreate(WSNbacktab,  char*,   _btb_name,WSSbacktab);

    WSMFpropertyCreate(WSNstatus, WSCbool,  _toggle_status,WSSstatus);
    WSMFpropertySetSelection(WSRbool3, WSRbool3D);

    WSMFpropertyDelete(WSNshadowType);

    WSMFaddTrigger(WSEV_VALUE_CH    );
    WSMFaddTrigger(WSEV_KEY_PRESS   );
    WSMFaddTrigger(WSEV_KEY_RELEASE );
    WSMFaddTrigger(WSEV_FOCUS_CH    );


  WSMFpropertyCreateEnd

  _indicator_type = WS_IN_OUT;
}

WSMFproperty( WSCvtoggle, WSNselectString,     char*,     _select_string    ,WSGFstrdup("")      );
WSMFproperty( WSCvtoggle, WSNindicatorOn,      WSCbool,   _indicator_on     ,True    );
WSMFproperty( WSCvtoggle, WSNindicatorType,    WSCuchar,      _indicator_type   ,WS_IN_OUT );
WSMFproperty( WSCvtoggle, WSNindicatorSize,    WSCuchar,     _indicator_size   ,20      );
WSMFproperty( WSCvtoggle, WSNindicatorShadow,  WSCuchar,     _indicator_shadow_thick ,2       );
//WSMFproperty( WSCvtoggle, WSNindicatorColor,   short, _indicator_color  ,WSGFcolor("gray85"));
//WSMFproperty( WSCvtoggle, WSNselectColor,      short, _select_color     ,WSGFcolor("gray75"));
WSMFproperty( WSCvtoggle, WSNindicatorColor,   short, _indicator_color ,WS_DF_NWBACKCOLOR);
WSMFproperty( WSCvtoggle, WSNselectColor,      short, _select_color    ,WS_DF_MENUSELECTCOLOR);
WSMFproperty( WSCvtoggle, WSNindicatorPixmap,  short, _indicator_pixmap ,-1      );
WSMFproperty( WSCvtoggle, WSNselectPixmap,     short,     _select_pixmap    ,-1      );
//WSMFproperty( WSCvtoggle, WSNindicatorImageType, char,     _indicator_image_type, WS_PIXMAP);
WSMFproperty( WSCvtoggle, WSNunique,           WSCbool,   _unique           ,False);
WSMFproperty( WSCvtoggle, WSNgroup,            char*,     _group_name       ,WSGFstrdup(""));
WSMFproperty( WSCvtoggle, WSNid,               short,     _id               ,0);
WSMFproperty( WSCvtoggle, WSNselectReset,      WSCbool,   _select_reset     ,False);
WSMFproperty( WSCvtoggle, WSNenableFocusMove,  WSCbool,   _enable_focus_move,True    );
WSMFproperty(WSCvtoggle, WSNupward,    char*,   _td_name, WSGFstrdup(""));
WSMFproperty(WSCvtoggle, WSNdownward, char*,   _bd_name, WSGFstrdup(""));
WSMFproperty(WSCvtoggle, WSNleftward,   char*,   _ld_name, WSGFstrdup(""));
WSMFproperty(WSCvtoggle, WSNrightward,  char*,   _rd_name, WSGFstrdup(""));
WSMFproperty(WSCvtoggle, WSNtab,  char*,   _tb_name, WSGFstrdup(""));
WSMFproperty(WSCvtoggle, WSNbacktab,  char*,   _btb_name, WSGFstrdup(""));
WSMFproperty( WSCvtoggle, WSNstatus,  WSCbool,   _toggle_status,False    );

void WSCvtoggle::setWorkWSNselectString(char*){}
void WSCvtoggle::getWorkWSNselectString(char** ){}
void WSCvtoggle::setWorkWSNindicatorOn(WSCbool){}
void WSCvtoggle::getWorkWSNindicatorOn(WSCbool* ){}
void WSCvtoggle::setWorkWSNindicatorType(WSCuchar){}
void WSCvtoggle::getWorkWSNindicatorType(WSCuchar* ){}
void WSCvtoggle::setWorkWSNindicatorSize(WSCuchar){}
void WSCvtoggle::getWorkWSNindicatorSize(WSCuchar* ){}
void WSCvtoggle::setWorkWSNindicatorShadow(WSCuchar){}
void WSCvtoggle::getWorkWSNindicatorShadow(WSCuchar* ){}
void WSCvtoggle::setWorkWSNindicatorColor(short){}
void WSCvtoggle::getWorkWSNindicatorColor(short* ){}
void WSCvtoggle::setWorkWSNindicatorPixmap(short){}
void WSCvtoggle::getWorkWSNindicatorPixmap(short* ){}
void WSCvtoggle::setWorkWSNselectColor(short){}
void WSCvtoggle::getWorkWSNselectColor(short* ){}
void WSCvtoggle::setWorkWSNselectPixmap(short){}
void WSCvtoggle::getWorkWSNselectPixmap(short* ){}
void WSCvtoggle::setWorkWSNunique(WSCbool){}
void WSCvtoggle::getWorkWSNunique(WSCbool* ){}
void WSCvtoggle::setWorkWSNgroup(char*){}
void WSCvtoggle::getWorkWSNgroup(char** ){}
void WSCvtoggle::setWorkWSNid(short){}
void WSCvtoggle::getWorkWSNid(short* ){}
void WSCvtoggle::setWorkWSNselectReset(WSCbool){}
void WSCvtoggle::getWorkWSNselectReset(WSCbool* ){}
void WSCvtoggle::setWorkWSNenableFocusMove(WSCbool){}
void WSCvtoggle::getWorkWSNenableFocusMove(WSCbool* ){}
void WSCvtoggle::setWorkWSNupward(char*){}
void WSCvtoggle::getWorkWSNupward(char**){} 
void WSCvtoggle::setWorkWSNdownward(char*){} 
void WSCvtoggle::getWorkWSNdownward(char**){} 
void WSCvtoggle::setWorkWSNleftward(char*){} 
void WSCvtoggle::getWorkWSNleftward(char**){} 
void WSCvtoggle::setWorkWSNrightward(char*){} 
void WSCvtoggle::getWorkWSNrightward(char**){} 
void WSCvtoggle::setWorkWSNtab(char*){} 
void WSCvtoggle::getWorkWSNtab(char**){} 
void WSCvtoggle::setWorkWSNbacktab(char*){} 
void WSCvtoggle::getWorkWSNbacktab(char**){} 
void WSCvtoggle::setWorkWSNstatus(WSCbool fl){
  if (getInitialized() != False){
    if (fl != getStatus()){
      setStatus(fl,True);//create status-ch event
    }
  }
}
void WSCvtoggle::getWorkWSNstatus(WSCbool* fl){
  *fl = getStatus();
}

WSCvtoggle::~WSCvtoggle(){
  WSGIappObjectList()->delEvent(this,WSEV_GUI_POLICY_CH);

  if (getFocus() != False){
    WSGIappKeyboard()->resetFocusInputWorkProc();
  }
  _get_toggle_list()->del(this);
  if (_select_string != NULL){
    delete _select_string;
    _select_string = NULL;
  }
  if (_group_name != NULL){
    delete _group_name;
    _group_name = NULL;
  }
  if (_td_name != NULL){
    delete _td_name;
    _td_name = NULL;
  }
  if (_bd_name != NULL){
    delete _bd_name;
    _bd_name = NULL;
  }
  if (_ld_name != NULL){
    delete _ld_name;
    _ld_name = NULL;
  }
  if (_rd_name != NULL){
    delete _rd_name;
    _rd_name = NULL;
  }
  if (_tb_name != NULL){
    delete _tb_name;
    _tb_name = NULL;
  }
  if (_btb_name != NULL){
    delete _btb_name;
    _btb_name = NULL;
  }

}

void WSCvtoggle::_key_handler(void* ptr, WSDkeyboard* keyboard, WSCbool fl){
  WSCvtoggle* obj = (WSCvtoggle*)ptr;

  if (obj->getVisible() == False){
    return;
  }
  
  WSCulong key = keyboard->getKey(); 
  if (obj->getSensitive() == False){
    return;
  }
  if (fl == True && key == WSK_Return){
    if (obj->_press_status == False){
      obj->setStatus(True, True);
      obj->draw();
    }else{
      obj->setStatus(False, True);
      obj->draw();
    }
  }else if (fl == True && key == WSK_Left) {
     WSCbool fm;
     obj->getPropertyV(WSNenableFocusMove, &fm);
     if (fm == True){
       WSCbase* target = obj->getFocusMoveInstance(WS_LEFT);
       if (target != NULL){
         target->setFocus();
         target->draw();
       }
     }
  }else if (fl == True && (key == WSK_Tab && keyboard->withShift())) {
     WSCbool fm;
     obj->getPropertyV(WSNenableFocusMove, &fm);
     if (fm == True){
       WSCbase* target = obj->getFocusMoveInstance(WS_STAB);
       if (target != NULL){
         target->setFocus();
         target->draw();
       }
     }
  }else if (fl == True && key == WSK_Tab ) {
     WSCbool fm;
     obj->getPropertyV(WSNenableFocusMove, &fm);
     if (fm == True){
       WSCbase* target = obj->getFocusMoveInstance(WS_TAB);
       if (target != NULL){
         target->setFocus();
         target->draw();
       }
     }

  }else if (fl == True && key == WSK_Right) {
     WSCbool fm;
     obj->getPropertyV(WSNenableFocusMove, &fm);
     if (fm == True){
       WSCbase* target = obj->getFocusMoveInstance(WS_RIGHT);
       if (target != NULL){
         target->setFocus();
         target->draw();
       }
     }

  }else if (fl == True && key == WSK_Up){
     WSCbool fm;
     obj->getPropertyV(WSNenableFocusMove, &fm);
     if (fm == True){
       WSCbase* target = obj->getFocusMoveInstance(WS_UP);
       if (target != NULL){
         target->setFocus();
         target->draw();
       }
     }

  }else if (fl == True && key == WSK_Down){
     WSCbool fm;
     obj->getPropertyV(WSNenableFocusMove, &fm);
     if (fm == True){
       WSCbase* target = obj->getFocusMoveInstance(WS_DOWN);
       if (target != NULL){
         target->setFocus();
         target->draw();
       }
     }

  }
  //キーボードイベントの発生
  if (fl == True){
    obj->onKey(keyboard,True);
    obj->execProcedure(WSEV_KEY_PRESS);
  }else{
    obj->onKey(keyboard,False);
    obj->execProcedure(WSEV_KEY_RELEASE);
  }
}

long WSCvtoggle::setStatus(WSCbool state, WSCbool create_event){
  if (state != False){
    state = True;
  }
  if (state == True){
    _press_status = True;
    setAbsoluteDraw(True);
    needUpdate();
    //redraw();
    if (_unique == True){
      long i, num = _get_toggle_list()->getNum();
      for(i=0; i < num; i++){
        WSCvtoggle* tgl = (WSCvtoggle*)_get_toggle_list()->getData(i);
        if (_group_name != NULL && _group_name[0] != 0 && 
            tgl != this &&
            !strcmp(tgl->_group_name, _group_name) ){
          WSCbool bak = tgl->_select_reset;
          tgl->_select_reset = True;
          tgl->setStatus(False, False);
          tgl->_select_reset = bak;
        }
      }
      for(i=0; i < num; i++){
        WSCvtoggle* tgl = (WSCvtoggle*)_get_toggle_list()->getData(i);
        if (_group_name != NULL && _group_name[0] != 0 && 
            tgl != this &&
            !strcmp(tgl->_group_name, _group_name) ){
          WSCbool bak = tgl->_select_reset;
          tgl->_select_reset = True;
          tgl->setStatus(False, True);
          tgl->_select_reset = bak;
          tgl->draw();
        }
      }
    }
    if (create_event == True){
      onValueChange(_press_status);
      execProcedure(WSEV_VALUE_CH);
    }
  }else{
    if (_group_name != NULL && !strcmp(_group_name, "")
         || _unique == False || _select_reset == True ){
      _press_status = False;
      setAbsoluteDraw(True);
      needUpdate();
      if (create_event == True){
        onValueChange(_press_status);
        execProcedure(WSEV_VALUE_CH);
      }
    }
    if (_group_name != NULL && strcmp(_group_name, "") &&
        _unique != False && _select_reset == False ){
      long i, num = _get_toggle_list()->getNum();
      for(i=0; i < num; i++){
        WSCvtoggle* tgl = (WSCvtoggle*)_get_toggle_list()->getData(i);
        if (_group_name != NULL && _group_name[0] != 0 && 
           tgl != this &&
           !strcmp(tgl->_group_name, _group_name) ){
          WSCbool bak = tgl->_select_reset;
          tgl->_select_reset = True;
          tgl->setStatus(False, True);
          tgl->_select_reset = bak;
          tgl->draw();
        }
      }
    }
  }
  return WS_NO_ERR;
}

void WSCvtoggle::onKey(WSDkeyboard*,WSCbool){
}

long WSCvtoggle::_device_initialize(){
  WSDdev* dev = getowndev();
  if (dev == NULL){
    return WS_ERR;
  }
  dev->setEnableEventBit( WSEV_MOUSE_MOVE_BIT | WSEV_MOUSE_OUT_BIT |
                          WSEV_MOUSE_PRESS_BIT | WSEV_MOUSE_RELEASE_BIT );

  WSCvlabel::_device_initialize();

  return WS_NO_ERR;
}
void WSCvtoggle::onFocusChange(WSCbool fl){
  if (getSensitive() == False && fl != False){
    return;
  }
  if (fl == True){
    WSGIappKeyboard()->setFocusInputWorkProc(_key_handler,NULL, this);
    if (getowndev() != NULL){
      WSGIappKeyboard()->resetFep(getowndev());
    }
  }else{
    WSGIappKeyboard()->resetFocusInputWorkProc();
  }
  setAbsoluteDraw(True);
  needUpdate();
}

long WSCvtoggle::draw(){
  if (getVisible() == False){
    return WS_NO_ERR;
  }

  WSDdev* dev = getowndev();
  if (dev == NULL){
    return WS_ERR;
  }

  short x = _x;
  short y = _y;
  WSCushort w = _w;
  WSCushort h = _h;

  WSCbool absolute = getAbsoluteDraw();
  if (absolute == True){

  }else if (dev->isExposed(x, y, w, h) == False ){
    return WS_NO_ERR;
  }

  WSCushort st = _shadow_thick;
  long blinking   = _bl_fl;
  long blinkfore  = WSGIappBlink()->getBlinkFore(_blink_rate);
  long shadowtype = _shadow_type;
  long twinblink  = _tw_fl;
  long blinktype  = _bl_type;
  short fgno         = _fore_color;
  short bgno         = _back_color;
  short blinkcolorno = _blink_color;
  short backblinkno  = _bg_blink_color;
  short tsno         = _ts_color;
  short bsno         = _bs_color;

  if ( shadowtype == WS_SHADOW_NONE &&
       blinking  != False &&
       blinkfore != False &&
       twinblink == False){
    return WS_NO_ERR;
  }
  if (WSGIappDev()->getExtGuiPolicySelected() != False){
    if (_ext_draw_proc == NULL){
      _ext_draw_proc = (void(*)(void*))WSGIappDev()->
                               getExtGuiPolicyProc("WSCvtoggle::draw");
    }
    if (_ext_draw_proc != NULL){
      WSCvtoggle_draw_struct st;
      st._this = this;
      st.dev = dev;
      st.x = _x;
      st.y = _y;
      st.width = _w;
      st.height = _h;
      st.shadow_thickness = _shadow_thick;
      st.blinking = _bl_fl;
      st.blink_fore = WSGIappBlink()->getBlinkFore(_blink_rate);
      st.shadow_type = _shadow_type;
      st.blink_type  = _bl_type;
      st.twin_blink   = _tw_fl;
      st.fore_color   = _fore_color;
      st.back_color   = _back_color;
      st.blink_color  = _blink_color;
      st.select_color = _select_color;
      st.back_blink_color = _bg_blink_color;
      st.top_shadow_color = _ts_color;
      st.bottom_shadow_color = _bs_color;
      st.label_string = _label_string;
      st.select_string = _select_string;
      st.label_pixmap = _label_pixmap;
      st.blink_pixmap = _blink_pixmap;
      st.select_pixmap = _select_pixmap;
      st.press_status = _press_status;
      st.orientation = _orientation;
      st.gradation = _grad_no;
      st.gradation_margin = _grad_margin;
      st.margin_left = _margin_left;
      st.margin_right = _margin_right;
      st.margin_top = _margin_top;
      st.margin_bottom = _margin_bottom;
      st.emboss = _emboss;
      st.font = _font;
      st.reverse_flag = _rv_fl;
      st.enable_focus_move = _enable_focus_move;
      st.toggle_status = _toggle_status;
      st.unique = _unique;
      st.select_reset = _select_reset;
      st.indicator_type = _indicator_type;
      st.indicator_size = _indicator_size;
      st.indicator_on = _indicator_on;
      st.indicator_shadow_thickness = _indicator_shadow_thick;
      st.indicator_size = _indicator_size;
      st.indicator_type = _indicator_type;
      st.indicator_shadow_thickness = _indicator_shadow_thick;
      st.indicator_on = _indicator_on;
      st.indicator_pixmap = _indicator_pixmap;
      st.indicator_color = _indicator_color;

      _ext_draw_proc(&st);
      return WS_NO_ERR;
    }
  }

  WSCstring str;
  if (_press_status == False){
    str.setString( _label_string );
  }else{
    if (_select_string == NULL){
      str.setString( _label_string );
    }else{
      if (_select_string[0] == 0 ){
        str.setString( _label_string );
      }else{
        str.setString( _select_string );
      }
    }
  }
  if (_orientation == WS_VERTICAL) {
    WSGFcreateVerticalString(&str);
  } else {
    str.replaceString("\\n", "\n", 0);
  }

  long err = dev->beginDraw(x, y, w, h, absolute);
  if (err != WS_NO_ERR){
    return WS_NO_ERR;
  }

  WSCbase::update();
  setAbsoluteDraw(False);

  if (_rv_fl == True) {
    if (blinking  != False &&
        blinkfore != False &&
        blinktype != WS_FORE ){
      dev->setForeColor(blinkcolorno);
    } else {
      dev->setForeColor(fgno);
    }
  } else {
    if (blinking  != False &&
        blinkfore != False &&
        blinktype != WS_FORE ){
      dev->setForeColor(backblinkno);
    } else {
      dev->setForeColor(bgno);
    }
  }
  if (_grad_no == 0){
    dev->drawFillRect(0, 0, w, h);
  }else{
    if (_press_status == True  && _indicator_on == False){
      dev->drawGradation(_grad_no,tsno,bgno,bsno,0, 1, w, h,_grad_margin);
    }else{
      dev->drawGradation(_grad_no,tsno,bgno,bsno,0, 0, w, h,_grad_margin);
    }
  }

  short offsetx = 0;
  short left_margin = _margin_left;
  short right_margin = _margin_right;
  short top_margin    = _margin_top;
  short bottom_margin = _margin_bottom;

  if (_indicator_on == True) {
    offsetx = _indicator_size;
  }
  short sx = st + left_margin + offsetx;
  short sy = st + top_margin;
  short sw = 0;
  short sh = 0;
  if ( w > offsetx + st * 2){
    sw = w -offsetx -st * 2;
  }
  if ( sw < left_margin + right_margin ){
    sw = 1;
  }else{
    sw = sw - left_margin - right_margin;
  }

  if ( h > st * 2){
    sh = h - st * 2;
  }

  if (sh < top_margin + bottom_margin){
    sh = 1;
  }else{
    sh = sh - top_margin - bottom_margin;
  }

  WSDimage* image;
  if (blinking  != False &&
      blinktype != WS_BACK &&
      blinkfore != False ){
    if (_blink_pixmap != -1 && twinblink != False){
      image = WSGIappImageSet()->getImage(_blink_pixmap);
      short dy = sy;
      if (_press_status == True  && _indicator_on == False){
        dy++;
      }
      dev->drawImage (sx, dy, sw, sh, image, getAlignment());
    }
  } else {
    if ( _label_pixmap != -1){
      image = WSGIappImageSet()->getImage( _label_pixmap );
      short dy = sy;
      if (_press_status == True  && _indicator_on == False){
        dy++;
      }
      dev->drawImage (sx, dy, sw, sh, image, getAlignment());
    }
  }

  if (st > 0){
    char type = WS_SHADOW_OUT;
    if (_press_status == True  && _indicator_on == False){
      type = WS_SHADOW_IN;
    }
    WSGFdrawBtnShadow(dev, type, st, _fore_color, tsno, bsno,bgno, 0, 0, w, h);
  }

  if (getSensitive() == False ||
      (getPropertyEditMode() != False && (long)getUserData(WS_DET) == 0)){
    if (_emboss != False){
      if (_bl_fl != False &&
        blinkfore != False &&
        _bl_type != WS_BACK &&
        _tw_fl != False) {
        dev->setForeColor(blinkcolorno);
      } else {
        dev->setForeColor(tsno);
      }
      dev->setBackColor(bgno);

      if (blinking  != False &&
          blinktype != WS_BACK &&
          blinkfore != False &&
          twinblink == False){
      }else{
        if (twinblink == False || blinking == False){
          dev->drawString(sx+1, sy+1, sw, sh,
                      &str, _font, getAlignment(), -1, False);
        }
      }
    }else{
      dev->setHatchPattern(8);
    }
  } else {
    dev->setHatchPattern(0);
  }

  if (_indicator_on == True){
     offsetx = _indicator_size;
  }

  if (_rv_fl == True) {
    if (_bl_fl == True &&
        blinkfore == True &&
        _bl_type != WS_BACK &&
        _tw_fl == True){
      dev->setForeColor(_bg_blink_color);
    }else{
      if ( _emboss != False && (getSensitive() == False ||
          (getPropertyEditMode() != False && (long)getUserData(WS_DET) == 0))){
        dev->setForeColor(_bs_color);
      } else {
        dev->setForeColor(_back_color);
      }
    }
  } else {
    if (_bl_fl == True &&
        blinkfore == True &&
        _bl_type != WS_BACK &&
        _tw_fl == True){
      dev->setForeColor(_blink_color);
    }else{
      if ( _emboss != False && (getSensitive() == False ||
          (getPropertyEditMode() != False && (long)getUserData(WS_DET) == 0))){
         dev->setForeColor(_bs_color);
      }else{
         dev->setForeColor(_fore_color);
      }
    }
  }

  if (sw != 0 && sh != 0){

    if (_bl_fl  != False &&
        _bl_type != WS_BACK &&
        blinkfore != False &&
        _tw_fl == False){
        // 描画しない
    }else{


      if (_press_status == True  && _indicator_on == False){
        dev->drawString(sx ,sy  +1,
                        sw ,sh, &str, _font, getAlignment(), -1, False);
      }else{
        dev->drawString(sx, sy, sw, sh,
                      &str, _font, getAlignment(), -1, False);
      }

      //フォーカスの点線のアンダーラインの描画
      // フォーカス移動可否が可の場合のみ
      if (getFocus() == True && _enable_focus_move == True){
        dev->setLineWidth( 1 );
        dev->setLineDashType( 8 );
        if (w > 4 + st*2 && h > 4 + st*2){
          if (_indicator_on == False){
            if (_press_status == True ){
              dev->drawRect(st+2, st+3, w-st*2-4, h-st*2-4);
            }else{
              dev->drawRect(st+2, st+2, w-st*2-4, h-st*2-4);
            }
          }else{
            WSCushort ww = 0;
            if ( w > offsetx + st * 2 +4 + left_margin/2){
              ww = w -offsetx -st * 2 -4 - left_margin/2;
            }
            if (ww >0 && (long)h-(long)st*2 -4 > 0){
              dev->drawRect(st+left_margin/2+2+_indicator_size, st+2, ww, h -st*2 -4);
            }
          }
        }
      }

    }
  }

  if (_indicator_on == True){
    //インジケータの座標の計算
    char itype = _indicator_type;
    WSCushort isize = _indicator_size;
    short ypos = (h - isize)/2;
    short xpos = st + left_margin /2;
    if (h < isize){
        ypos = 0;
    }

    //インジケータ背景の描画
    WSDimage* image;
    if (_press_status == True ){
      if (_select_pixmap == -1){
        dev->setForeColor(_select_color);
        dev->drawFillRect(xpos, ypos, isize, isize);
      }else{
        image = WSGIappImageSet()->getImage(_select_pixmap);
          dev->drawImage (xpos, ypos, isize, isize, image, WS_CENTER);
      }
    }else{
      if (_indicator_pixmap == -1){
        dev->setForeColor(_indicator_color);
        dev->drawFillRect(xpos, ypos, isize, isize);
      }else{
        image = WSGIappImageSet()->getImage(_indicator_pixmap);
          dev->drawImage (xpos, ypos, isize, isize, image, WS_CENTER);
      }
    }
    if (itype != WS_NONE ){
      char type = WS_SHADOW_OUT;
      if (_press_status == True){
        if  ( itype == WS_IN_OUT){
          type = WS_SHADOW_IN;
        }
      }
      if  ( itype == WS_IN){
        type = WS_SHADOW_IN;
      }
      WSGFdrawShadow(dev, type, _indicator_shadow_thick,
                     _fore_color, _ts_color, _bs_color,_back_color,
                     xpos, ypos , isize, isize);
    }
  }

  dev->endDraw();
  return WS_NO_ERR;
}

void WSCvtoggle::onValueChange(WSCbool ){
}

void WSCvtoggle::onSensitiveChange(WSCbool fl){
  if (fl == False){
    setFocus(False);
  }
  setAbsoluteDraw(True);
  needUpdate();
}

void WSCvtoggle::onMousePress(WSCpoint* point){
  if (getSensitive() == False){
    WSCbase::onMousePress(point);
    return;
  }
  setFocus(True);
  if (_press_status == False){
    setStatus(True, True);
  }else{
    setStatus(False, True);
  }
  WSCvlabel::onMousePress(point);
  redraw();
}

void WSCvtoggle::onMouseRelease(WSCpoint* point){
  if (getSensitive() == False){
    return;
  }
  WSCvlabel::onMouseRelease(point);
}

void WSCvtoggle::onMouseOut(){
}

long WSCvtoggle::addProcedure(WSCprocedure* ac){
  if (existTrigger(ac->getTrigger()) == False && ac->getInternal() == False){
WSMFtrace("WSCvtoggle::addProcedure trigger=%d not supported.\n", ac->getTrigger());
    return WS_ERR;
  }

  if (ac->getTrigger() == WSEV_VALUE_CH){
    ac->setEffectiveTriggerMask( WSEV_MOUSE_MOVE_BIT | WSEV_MOUSE_PRESS_BIT |
                                 WSEV_MOUSE_RELEASE_BIT | WSEV_MOUSE_OUT_BIT );

    _event_mask |= ac->getEffectiveTriggerMask();
    _add_prcs(&_prc_list, ac);

    WSDdev* dev = getowndev();
    if (dev != NULL){
      dev->setEnableEventBit(_event_mask);
    }
    return WS_NO_ERR;
  }

  WSCnwbase::addProcedure(ac);
  return WS_NO_ERR;
}

WSCbool WSCvtoggle::getStatus(){
  return _press_status;
}

long WSCvtoggle::getGroupValue(){
  long value = 0;

  long i;
  long num = _get_toggle_list()->getNum();
  for(i=0; i < num; i++){
    WSCvtoggle* tgl = (WSCvtoggle*)_get_toggle_list()->getData(i);
    if (_group_name != NULL && _group_name[0] != 0 && 
       !strcmp(tgl->_group_name, _group_name) ){
       short id = tgl->_id;
       if (tgl->getStatus() == True){
         if (_unique == True){
           return id;
         }else{
           if (id > 0 && id < 33){
             long vl = (1 << (id-1));
             value |= vl;
           }
         }
       }
     }
  }
  return value;
}

long WSCvtoggle::clearGroupValue(){
  long ret = setGroupValue(0);
  return ret;
}

long WSCvtoggle::setGroupValue(long value){
  long i, num = _get_toggle_list()->getNum();
  for(i=0; i < num; i++){
    WSCvtoggle* tgl = (WSCvtoggle*)_get_toggle_list()->getData(i);
    if (_group_name != NULL && _group_name[0] != 0 && 
       !strcmp(tgl->_group_name, _group_name) ){
       short id = tgl->_id;
       if (_unique == True){ //択一の場合
         WSCbool ubak = tgl->_unique;
         tgl->_unique = False;
         if (id == value){
           WSCbool bak = tgl->_select_reset;
           tgl->_select_reset = True;
           tgl->setStatus(True, True);
           tgl->_select_reset = bak;
         }else{
           WSCbool bak = tgl->_select_reset;
           tgl->_select_reset = True;
           tgl->setStatus(False, True);
           tgl->_select_reset = bak;
         }
         tgl->_unique = ubak;
         tgl->setAbsoluteDraw(True);
         tgl->needUpdate();
         tgl->draw();
       }else{      //多重の場合
         long vl;
         if (id >-1 && id < 32){
           vl = (1 << (id-1));
         }else{
           vl = 0;
         }
         if (vl & value){
           WSCbool bak = tgl->_select_reset;
           tgl->_select_reset = True;
           tgl->setStatus(True, True);
           tgl->_select_reset = bak;
         }else{
           WSCbool bak = tgl->_select_reset;
           tgl->_select_reset = True;
           tgl->setStatus(False, True);
           tgl->_select_reset = bak;
         }
       }
     }
  }
  return WS_NO_ERR;
}

void(*WSCvtoggle::_ext_draw_proc)(void*) = NULL;
WSCstring WSCvtoggle::_policy_name;

void WSCvtoggle::onGuiPolicyChange(long policy){
  WSCvlabel::onGuiPolicyChange(policy);
  if (WSGIappDev()->getExtGuiPolicySelected() == False){
    _ext_draw_proc = NULL;
  }else{
    if (!strcmp((char*)_policy_name,(char*)WSGIappDev()->getExtGuiPolicyName())){
    }else{
      _ext_draw_proc = (void(*)(void*))WSGIappDev()->getExtGuiPolicyProc("WSCvtoggle::draw");
    }
  }
  if (getVisible() != False){
    needUpdate();
    setAbsoluteDraw(True);
    redraw();
  }
}

