//===============================================================
// vsliderc.cxx - SliderCmd - Windows
//
// Copyright (C) 1995,1996,1997,1998  Bruce E. Wampler
//
// This file is part of the V C++ GUI Framework, and is covered
// under the terms of the GNU Library General Public License,
// Version 2. This library has NO WARRANTY. See the source file
// vapp.cxx for more complete information about license terms.
//===============================================================
#include <v/vos2.h>           // for OS/2 stuff
#include <v/vsliderc.h> // our definitions
#include <v/vcmdprnt.h> // a command parent
#include <v/vapp.h>

// the windows slider code requires that when it is set, the
// value it is to be set to must be in the range 0-100 regardless
// of the minval/maxval range it was originally given by the contructor. It
// will however respond with the value in the correct range.  This
// heinously broken behavior is emulated in the OS/2 port by setting
// the following variable (and needs to be set to get the *&%^* V icon
// editor to work correctly...)
#define EMULATE_BROKEN_WINDOZE_CODE

//=================>>> vSliderCmd::vSliderCmd <<<=======================
  vSliderCmd::vSliderCmd(vCmdParent* dp, CommandObject* dc) :
	    vCmd(dp, dc)
  {
    initialize();                       // and initialize
  }

//=======================>>> vSliderCmd::~vSliderCmd <<<=======================
  vSliderCmd::~vSliderCmd()
  {
    SysDebug(Constructor,"vSliderCmd::~vSliderCmd() Destructor\n")
  }

//=====================>>> vSliderCmd::initialize <<<=======================
  void vSliderCmd::initialize()
  {
    SysDebug(Constructor,"vSliderCmd::vSliderCmd() constructor\n")

    _initialPosnSet=0;  // initial slider position not set yet

    long style = SLS_PRIMARYSCALE1 |
		 SLS_SNAPTOINCREMENT | SLS_RIBBONSTRIP;

    if (_parentWin->_dialogType != aCmdBar)
	style |= WS_TABSTOP | WS_GROUP;  // default for a button
    else
	style |= WS_GROUP;

    CopyToLocal();                      // Make local copies of CmdObject

    if (!(dlgCmd->attrs & CA_Hidden))   // Check for Hidden
	style |= WS_VISIBLE;

    // Set the size of the slider
    if (dlgCmd->attrs & CA_Vertical)
    {
      style |= SLS_VERTICAL | SLS_HOMEBOTTOM | SLS_BUTTONSBOTTOM | SLS_LEFT;

      _w = 18;               // set my width
      _h = 76;               // regular size
      // the normal slider has a 0-100 range
      _scd.usScale1Increments = 101;
      _scd.usScale1Spacing = 1;
      if (dlgCmd->attrs & CA_Large)
      {
	_h = 124;
	_scd.usScale1Increments = 101;
	_scd.usScale1Spacing = 2;
      }
      else if (dlgCmd->attrs & CA_Small)
      {
	_h = 50;
        // the small slider has only a 0-50 range
	_scd.usScale1Increments = 51;
	_scd.usScale1Spacing = 1;
      }
      // user override
      if (dlgCmd->size > 0 && dlgCmd->size < 2048)
      {
	_h = 25 + (dlgCmd->size/2);
        // the user defined slider has a used defined range
	_scd.usScale1Increments = dlgCmd->size;
	_scd.usScale1Spacing = 1;
      }
    }
    // else its a horizontal slider
    else
    {
      style |= SLS_HORIZONTAL | SLS_HOMELEFT | SLS_BUTTONSLEFT | SLS_BOTTOM;
      _h = 13;                 // default height

      _w = 100;
      // the normal slider has a 0-100 range
      _scd.usScale1Increments = 101;
      _scd.usScale1Spacing = 1;
      if (dlgCmd->attrs & CA_Large)
      {
	_w = 166;
	_scd.usScale1Increments = 101;
	_scd.usScale1Spacing = 2;
      }
      else if (dlgCmd->attrs & CA_Small)
      {
	_w = 67;
        // the small slider has only a 0-50 range
	_scd.usScale1Increments = 51;
	_scd.usScale1Spacing = 1;
      }
      // user override
      if (dlgCmd->size > 0 && dlgCmd->size < 2048)
      {
	_w = 35 + ((dlgCmd->size*65)/100);
        // the user defined slider has a used defined range
	_scd.usScale1Increments = dlgCmd->size;
	_scd.usScale1Spacing = 1;
      }
    }

    int* minMax = (int *)_itemList;             // giving range?
    _minVal = 0; _maxVal = 100;                 // default min/max

    if (minMax != 0)                            // They gave a range list
    {
	_minVal = minMax[0];
	_maxVal = minMax[1];
    }

    if (_minVal > _maxVal)
    {
	SysDebug2(BadVals,"vSliderCmd:vSliderCmd - bad range %d to %d\n",_minVal,_maxVal)
	_minVal = 0; _maxVal = 100;     // make some sense!
    }

    if (_retVal < _minVal)      // set a legal value for the top
	_curVal = _minVal;
    else if (_retVal > _maxVal)
	_curVal = _maxVal;
    else
	_curVal = _retVal;

    _scd.cbSize = sizeof(SLDCDATA);
    _scd.usScale2Increments = 101;
    _scd.usScale2Spacing = 1;

    // SetPosition will compute the _x and _y position of the control based
    // upon _w and _h and also its relationship to any frames and adjacent
    // controls. In addition, the frame size will be adjusted to make sure
    // it can hold the new control
    _parentWin->SetPosition(_x, _y, _w, _h, dlgCmd->cFrame, dlgCmd->cRightOf,
	dlgCmd->cBelow);

    if (dlgCmd->attrs & CA_Vertical)
    {
      _y += 2;
      _h -= 2;   // we play this game to get better positioning in a frame
    }
    else if (dlgCmd->attrs & CA_Horizontal)
    {
//      _x += 1;
      _y += 2;
      _h -= 2;   // we play this game to get better positioning in a frame
    }

    // AddDlgControl will create the control in the dialog template using
    // the supplied x, y, w, h parameters.
    _CtrlOffset = _parentWin->AddDlgControl(_x, _y, _w, _h, _cmdId,
	style, WC_SLIDER, _title, NULL, _scd.cbSize, &_scd);

  }

//==================>>> vSliderCmd::GetCmdValue <<<=========================
  int vSliderCmd::GetCmdValue(ItemVal id) VCONST
  {
    if (id != _cmdId)
	return -1;
    return _curVal;
  }

//=====================>>> vSliderCmd::SetCmdVal <<<=========================
  void vSliderCmd::SetCmdVal(ItemVal val, ItemSetType st)
  {
    SysDebug2(Misc,"vSliderCmd::SetCmdVal(val:%d, type:%d)\n",val,st)
    HWND myHwnd = GetMyHwnd(_cmdId);

    switch (st)
    {
      case Sensitive:
	_Sensitive = val;               // set
	WinEnableWindow (myHwnd, val);
	break;

      case Hidden:
	if (val)
	  WinShowWindow (myHwnd, FALSE);
	else
	  WinShowWindow (myHwnd, TRUE);
	break;

      case Value:
	if (val < _minVal || val > _maxVal )
	  return;
	_curVal = val;
#ifdef EMULATE_BROKEN_WINDOZE_CODE
        // we assume the input range is always 0-100 to emulate the
        // broken windoze port of V

        // the max slider position is given by _scd.usScale1Increments-1
        // we take care to minimize rounding errors here
        int percent = (_scd.usScale1Increments - 1)*val + 50;
        percent /= 100;
#else
        // otherwise, we do this logically...
	double frac = val - _minVal;
	frac = frac/(_maxVal - _minVal);
        // the max slider position is given by _scd.usScale1Increments-1
	int percent = frac * (_scd.usScale1Increments - 1);
#endif

	// Now set appropriate _curVal, scroll
	WinSendMsg (myHwnd, SLM_SETSLIDERINFO,
	  MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_RANGEVALUE), (MPARAM) percent);
//	  MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE), (MPARAM) percent);

	// set a few tick marks
	SHORT ticksize=4;
	SHORT tickposn[3] = {0, 50, 100};
	tickposn[1] = (_scd.usScale1Increments - 1)/2;
	tickposn[2] = (_scd.usScale1Increments - 1);
/*
	if (dlgCmd->attrs & CA_Small)
	{
	  tickposn[0] = 0;
	  tickposn[1] = 25;
	  tickposn[2] = 50;
	}
*/
	for (int i=0; i<3; i++)
        {
	  WinSendMsg (myHwnd, SLM_SETTICKSIZE,
	      MPFROM2SHORT(tickposn[i], ticksize), (MPARAM) NULL);
        }
	break;
    }
  }

//===================>>> vSliderCmd::vCmdCallback <<<=======================
  void vSliderCmd::CmdCallback(UINT uMsg, MPARAM mp1, MPARAM mp2)
  {
    // See if we are getting a message we care about
    if (uMsg == WM_CONTROL)
    {
//	SysDebug1(OS2Dev,"vSliderCmd::CmdCallBack \n")

      switch (SHORT2FROMMP(mp1))
      {
        case SLN_CHANGE:                // arm moved
        case SLN_SLIDERTRACK:           // arm dragged by mouse
	  int val = LONGFROMMP(mp2);
          // scale by slider length to get percent
          double percent = val*100./(_scd.usScale1Increments - 1);
          _curVal = (int)( (percent * (_maxVal-_minVal) / 100) + _minVal );

//          SysDebug2(OS2Dev,"vSliderCmd::CmdCallBack val=%u _curVal=%u\n", val, _curVal)

  // WorkAround... I'm getting traps because the inital slider position is
  // set during WM_INITDLG which causes the slider to respond with a command
  // message with the updated value and often the code isn't ready
  // to handle that command this early on.  A good example of this is the
  // vopengl shapes program which will trap because the slider command handler
  // needs the timer object which is instantiated after the slider in the
  // commandpane is built and initialized.

          if (_initialPosnSet)
	    _parentWin->ProcessCmd(_cmdId, _curVal, dlgCmd->cmdType);
          else
            _initialPosnSet=1;
      }
    }
  }
