// @(#)root/gui:$Name:  $:$Id: TGDoubleSlider.cxx,v 1.5 2001/06/07 11:14:19 rdm Exp $
// Author: Reiner Rohlfs   30/09/98

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/
/**************************************************************************

    This source is based on Xclass95, a Win95-looking GUI toolkit.
    Copyright (C) 1996, 1997 David Barth, Ricky Ralston, Hector Peraza.

    Xclass95 is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

**************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGDoubleSlider, TGDoubleVSlider and TGDoubleHSlider                  //
//                                                                      //
// DoubleSlider widgets allow easy selection of a min and a max value   //
// out of a range.                                                      //
// DoubleSliders can be either horizontal or vertical oriented and      //
// there is a choice of three different types of tick marks.            //
//                                                                      //
// To change the min value press the mouse near to the left / bottom    //
// edge of the slider.                                                  //
// To change the max value press the mouse near to the right / top      //
// edge of the slider.                                                  //
// To change both values simultaneously press the mouse near to the     //
// center of the slider.                                                //
//                                                                      //
// TGDoubleSlider is an abstract base class. Use the concrete           //
// TGDoubleVSlider and TGDoubleHSlider.                                 //
//                                                                      //
// Dragging the slider will generate the event:                         //
// kC_VSLIDER, kSL_POS, slider id, 0  (for vertical slider)             //
// kC_HSLIDER, kSL_POS, slider id, 0  (for horizontal slider)           //
//                                                                      //
// Pressing the mouse will generate the event:                          //
// kC_VSLIDER, kSL_PRESS, slider id, 0  (for vertical slider)           //
// kC_HSLIDER, kSL_PRESS, slider id, 0  (for horizontal slider)         //
//                                                                      //
// Releasing the mouse will generate the event:                         //
// kC_VSLIDER, kSL_RELEASE, slider id, 0  (for vertical slider)         //
// kC_HSLIDER, kSL_RELEASE, slider id, 0  (for horizontal slider)       //
//                                                                      //
// Use the functions GetMinPosition(), GetMaxPosition() and             //
// GetPosition() to retrieve the position of the slider.                //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGDoubleSlider.h"


ClassImp(TGDoubleSlider)
ClassImp(TGDoubleVSlider)
ClassImp(TGDoubleHSlider)

//______________________________________________________________________________
TGDoubleSlider::TGDoubleSlider(const TGWindow *p, UInt_t w, UInt_t h, UInt_t type, Int_t id,
                               UInt_t options, ULong_t back,
                               Bool_t reversed, Bool_t mark_ends)
   : TGFrame(p, w, h, options, back)
{
   // Slider constructor.

   fWidgetId    = id;
   fWidgetFlags = kWidgetWantFocus;
   fMsgWindow   = p;

   fScaleType = type;
   fScale = 10;

   fReversedScale = reversed;
   fMarkEnds = mark_ends;

   gVirtualX->GrabButton(fId, kAnyButton, kAnyModifier,
                    kButtonPressMask | kButtonReleaseMask |
                    kPointerMotionMask, kNone, kNone);
}



//______________________________________________________________________________
TGDoubleVSlider::TGDoubleVSlider(const TGWindow *p, UInt_t h, UInt_t type, Int_t id,
                                 UInt_t options, ULong_t back,
                                 Bool_t reversed, Bool_t mark_ends)
    : TGDoubleSlider(p, kDoubleSliderWidth, h, type, id, options, back,
                     reversed, mark_ends)
{
   // Create a vertical slider widget.

   // set initial values
   fSmin = h/8*3; fSmax = h/8*5; fVmin = 0; fVmax = h;
}

//______________________________________________________________________________
TGDoubleVSlider::~TGDoubleVSlider()
{
   // Delete vertical slider widget.
}

//______________________________________________________________________________
void TGDoubleVSlider::DoRedraw()
{
   // Redraw vertical slider widget.

   // cleanup the drawable
   gVirtualX->ClearWindow(fId);

   if (fSmin < fVmin) fSmin = fVmin;
   if (fSmax < fVmin) fSmax = fVmin;
   if (fSmin > fVmax) fSmin = fVmax;
   if (fSmax > fVmax) fSmax = fVmax;
   if (fSmin > fSmax) fSmin = fSmax = (fSmin + fSmax) / 2;

   int relMin = (int)((fHeight-16) * (fSmin - fVmin) / (fVmax - fVmin)) + 1;
   int relMax = (int)((fHeight-16) * (fSmax - fVmin) / (fVmax - fVmin) + 15);

   gVirtualX->DrawLine(fId, fgHilightGC(), fWidth/2-6, relMin, fWidth/2+5, relMin);
   gVirtualX->DrawLine(fId, fgHilightGC(), fWidth/2-6, relMin, fWidth/2-6, relMax);
   gVirtualX->DrawLine(fId, fgBlackGC(),   fWidth/2+5, relMax, fWidth/2-6, relMax);
   gVirtualX->DrawLine(fId, fgBlackGC(),   fWidth/2+5, relMax, fWidth/2+5, relMin);

   if (relMin-1 > 8) {
      gVirtualX->DrawLine(fId, fgShadowGC(),  fWidth/2-1, 8, fWidth/2-1, relMin-1);
      gVirtualX->DrawLine(fId, fgHilightGC(), fWidth/2+1, 8, fWidth/2+1, relMin-1);
      gVirtualX->DrawLine(fId, fgBlackGC(),   fWidth/2,   8, fWidth/2,   relMin-1);
   }
   if (relMax+1 < (int)fHeight-8) {
      gVirtualX->DrawLine(fId, fgShadowGC(),  fWidth/2-1, relMax+1, fWidth/2-1, fHeight-8);
      gVirtualX->DrawLine(fId, fgHilightGC(), fWidth/2+1, relMax+1, fWidth/2+1, fHeight-8);
      gVirtualX->DrawLine(fId, fgBlackGC(),   fWidth/2,   relMax+1, fWidth/2,   fHeight-8);
   }

   // check scale
   if (fScale == 1) fScale++;
   if (fScale * 2 > (int)fHeight) fScale = 0;
   if (fScale > 0 && !(fScaleType & kDoubleScaleNo)) {
      int lines = ((int)fHeight-16) / fScale;
      int remain = ((int)fHeight-16) % fScale;
      if (lines < 1) lines = 1;
      for (int i = 0; i <= lines; i++) {
         int y = i * fScale + (i * remain) / lines;
         gVirtualX->DrawLine(fId, fgBlackGC(), fWidth/2+8, y+7, fWidth/2+10, y+7);
         if ((fScaleType && kDoubleScaleBoth))
            gVirtualX->DrawLine(fId, fgBlackGC(), fWidth/2-9, y+7, fWidth/2-11, y+7);
      }
   }

   if (fMarkEnds) {
      // Draw scaling zones.
      int y1 = (relMax - relMin) / 4 + relMin;
      int y2 = (relMax - relMin) / 4 * 3 + relMin;
      gVirtualX->DrawLine(fId, fgBlackGC(), fWidth/2-6, y1, fWidth/2+5, y1);
      gVirtualX->DrawLine(fId, fgBlackGC(), fWidth/2-6, y2, fWidth/2+5, y2);
   }
}

//______________________________________________________________________________
Bool_t TGDoubleVSlider::HandleButton(Event_t *event)
{
   // Handle mouse button event in vertical slider.

   if (event->fType == kButtonPress && event->fCode == kButton1) {
      fPressPoint = event->fY;
      fPressSmin  = fSmin;
      fPressSmax  = fSmax;

      int relMin = (int)((fHeight-16) * (fSmin - fVmin) / (fVmax - fVmin)) + 1;
      int relMax = (int)((fHeight-16) * (fSmax - fVmin) / (fVmax - fVmin) + 15);
      if (fPressPoint < (relMax - relMin) / 4 + relMin)
         // move only min value
         fMove = 1;
      else if (fPressPoint > (relMax - relMin) / 4 * 3 + relMin)
         // move only max value
         fMove = 2;
      else
         // move min and max value
         fMove = 3;

      SendMessage(fMsgWindow, MK_MSG(kC_VSLIDER, kSL_PRESS), fWidgetId, 0);
      fClient->ProcessLine(fCommand, MK_MSG(kC_VSLIDER, kSL_PRESS), fWidgetId, 0);
      Pressed();

      // last argument kFALSE forces all specified events to this window
      gVirtualX->GrabPointer(fId, kButtonPressMask | kButtonReleaseMask |
                             kPointerMotionMask, kNone, kNone,
                             kTRUE, kFALSE);
   } else if (event->fType == kButtonRelease && event->fCode == kButton1) {
      SendMessage(fMsgWindow, MK_MSG(kC_VSLIDER, kSL_RELEASE), fWidgetId, 0);
      fClient->ProcessLine(fCommand, MK_MSG(kC_VSLIDER, kSL_RELEASE), fWidgetId, 0);
      Released();
      fMove = 0;

      gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);  // ungrab pointer
   } else
      fMove = 0;

   return kTRUE;
}

//______________________________________________________________________________
Bool_t TGDoubleVSlider::HandleMotion(Event_t *event)
{
   // Handle mouse motion event in vertical slider.

   int       diff;
   Float_t   oldMin, oldMax;

   diff    = event->fY - fPressPoint;
   oldMin  = fSmin;
   oldMax  = fSmax;

   if (fMove == 1) {
      // change of min value
      fSmin = fPressSmin + diff * (fVmax - fVmin) / (fHeight-16);
      if (fSmin < fVmin) fSmin = fVmin;
      if (fSmin > fSmax) fSmin = fSmax;
   } else if (fMove == 2) {
      // change of max value
      fSmax = fPressSmax + diff * (fVmax - fVmin) / (fHeight-16);
      if (fSmax > fVmax) fSmax = fVmax;
      if (fSmax < fSmin) fSmax = fSmin;
   } else if (fMove == 3) {
      // change of min and of max value
      Float_t logicalDiff;
      logicalDiff = diff * (fVmax - fVmin) / (fHeight-16);
      if (fPressSmax + logicalDiff > fVmax)
         logicalDiff = fVmax - fPressSmax;
      if (fPressSmin + logicalDiff < fVmin)
         logicalDiff = fVmin - fPressSmin;
      fSmax = fPressSmax + logicalDiff;
      fSmin = fPressSmin + logicalDiff;
   }

   // check if position has changed
   if (fMove != 0 && (fSmax != oldMax || fSmin != oldMin)) {
      fClient->NeedRedraw(this);
      SendMessage(fMsgWindow, MK_MSG(kC_VSLIDER, kSL_POS), fWidgetId, 0);
      fClient->ProcessLine(fCommand, MK_MSG(kC_VSLIDER, kSL_POS), fWidgetId, 0);
      PositionChanged();
   }
   return kTRUE;
}

//______________________________________________________________________________
 TGDoubleHSlider::TGDoubleHSlider(const TGWindow *p, UInt_t w, UInt_t type, Int_t id,
                                 UInt_t options, ULong_t back,
                                 Bool_t reversed, Bool_t mark_ends)
    : TGDoubleSlider(p, w, kDoubleSliderHeight, type, id, options, back,
                     reversed, mark_ends)
{
   // Create horizontal slider widget.

   // set initial values
   fSmin = w/8*3; fSmax = w/8*5; fVmin = 0; fVmax = w;
}

//______________________________________________________________________________
 TGDoubleHSlider::~TGDoubleHSlider()
{
   // Delete a horizontal slider widget.

}

//______________________________________________________________________________
 void TGDoubleHSlider::DoRedraw()
{
   // Redraw horizontal slider widget.

   // cleanup drawable
   gVirtualX->ClearWindow(fId);

   if (fSmin < fVmin) fSmin = fVmin;
   if (fSmax > fVmax) fSmax = fVmax;
   if (fSmin > fSmax) fSmin = fSmax = (fSmin + fSmax) / 2;

   int relMin = (int)((fWidth-16) * (fSmin - fVmin) / (fVmax - fVmin)) + 1;
   int relMax = (int)((fWidth-16) * (fSmax - fVmin) / (fVmax - fVmin) + 15);

   gVirtualX->DrawLine(fId, fgHilightGC(), relMin, fHeight/2-6, relMin, fHeight/2+5);
   gVirtualX->DrawLine(fId, fgHilightGC(), relMax, fHeight/2-6, relMin, fHeight/2-6);
   gVirtualX->DrawLine(fId, fgBlackGC(),   relMax, fHeight/2+5, relMax, fHeight/2-6);
   gVirtualX->DrawLine(fId, fgBlackGC(),   relMin, fHeight/2+5, relMax, fHeight/2+5);

   if (relMin-1 > 8) {
      gVirtualX->DrawLine(fId, fgShadowGC(),  8, fHeight/2-1, relMin-1, fHeight/2-1);
      gVirtualX->DrawLine(fId, fgHilightGC(), 8, fHeight/2+1, relMin-1, fHeight/2+1);
      gVirtualX->DrawLine(fId, fgBlackGC(),   8, fHeight/2,   relMin-1, fHeight/2);
   }
   if (relMax+1 < (int)fWidth-8) {
      gVirtualX->DrawLine(fId, fgShadowGC(),  relMax+1, fHeight/2-1, fWidth-8, fHeight/2-1);
      gVirtualX->DrawLine(fId, fgHilightGC(), relMax+1, fHeight/2+1, fWidth-8, fHeight/2+1);
      gVirtualX->DrawLine(fId, fgBlackGC(),   relMax+1, fHeight/2,   fWidth-8, fHeight/2);
   }

   if (fScale == 1) fScale++;
   if (fScale * 2 > (int)fWidth) fScale = 0;
   if (fScale > 0 && !(fScaleType & kDoubleScaleNo)) {
      int lines = ((int)fWidth-16) / fScale;
      int remain = ((int)fWidth-16) % fScale;
      if (lines < 1) lines = 1;
      for (int i = 0; i <= lines; i++) {
         int x = i * fScale + (i * remain) / lines;
         gVirtualX->DrawLine(fId, fgBlackGC(), x+7, fHeight/2+8, x+7, fHeight/2+10);
         if ((fScaleType && kDoubleScaleBoth))
            gVirtualX->DrawLine(fId, fgBlackGC(), x+7, fHeight/2-9, x+7, fHeight/2-11);
      }
   }

   if (fMarkEnds) {
      // Draw scaling zones.
      int x1 = (relMax - relMin) / 4 + relMin;
      int x2 = (relMax - relMin) / 4 * 3 + relMin;
      gVirtualX->DrawLine(fId, fgBlackGC(), x1, fHeight/2-6, x1, fHeight/2+5);
      gVirtualX->DrawLine(fId, fgBlackGC(), x2, fHeight/2-6, x2, fHeight/2+5);
   }
}

//______________________________________________________________________________
 Bool_t TGDoubleHSlider::HandleButton(Event_t *event)
{
   // Handle mouse button event in horizontal slider widget.

   if (event->fType == kButtonPress && event->fCode == kButton1) {
      fPressPoint = event->fX;
      fPressSmin  = fSmin;
      fPressSmax  = fSmax;

      int relMin = (int)((fWidth-16) * (fSmin - fVmin) / (fVmax - fVmin)) + 1;
      int relMax = (int)((fWidth-16) * (fSmax - fVmin) / (fVmax - fVmin) + 15);
      if (fPressPoint < (relMax - relMin) / 4 + relMin)
         // move only min value
         fMove = 1;
      else if (fPressPoint > (relMax - relMin) / 4 * 3 + relMin)
         // move only max value
         fMove = 2;
      else
         // move min and max value
         fMove = 3;

      SendMessage(fMsgWindow, MK_MSG(kC_HSLIDER, kSL_PRESS), fWidgetId, 0);
      fClient->ProcessLine(fCommand, MK_MSG(kC_HSLIDER, kSL_PRESS), fWidgetId, 0);
      Pressed();

      // last argument kFALSE forces all specified events to this window
      gVirtualX->GrabPointer(fId, kButtonPressMask | kButtonReleaseMask |
                             kPointerMotionMask, kNone, kNone,
                             kTRUE, kFALSE);
   } else if (event->fType == kButtonRelease && event->fCode == kButton1) {
      SendMessage(fMsgWindow, MK_MSG(kC_HSLIDER, kSL_RELEASE), fWidgetId, 0);
      fClient->ProcessLine(fCommand, MK_MSG(kC_HSLIDER, kSL_RELEASE), fWidgetId, 0);
      Released();
      fMove = 0;

      gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);  // ungrab pointer
   } else
      fMove = 0;

   return kTRUE;
}

//______________________________________________________________________________
 Bool_t TGDoubleHSlider::HandleMotion(Event_t *event)
{
   // Handle mouse motion event in horizontal slide widget.

   int     diff;
   Float_t oldMin, oldMax;

   diff    = event->fX - fPressPoint;
   oldMin  = fSmin;
   oldMax  = fSmax;

   if (fMove == 1) {
      // change of min value
      fSmin = fPressSmin + diff * (fVmax - fVmin) / (fWidth-16);
      if (fSmin < fVmin) fSmin = fVmin;
      if (fSmin > fSmax) fSmin = fSmax;
   } else if (fMove == 2) {
      // change of max value
      fSmax = fPressSmax + diff * (fVmax - fVmin) / (fWidth-16);
      if (fSmax > fVmax) fSmax = fVmax;
      if (fSmax < fSmin) fSmax = fSmin;
   } else if (fMove == 3) {
      // change of min and of max value
      Float_t logicalDiff;
      logicalDiff = diff * (fVmax - fVmin) / (fWidth-16);
      if (fPressSmax + logicalDiff > fVmax)
         logicalDiff = fVmax - fPressSmax;
      if (fPressSmin + logicalDiff < fVmin)
         logicalDiff = fVmin - fPressSmin;
      fSmax = fPressSmax + logicalDiff;
      fSmin = fPressSmin + logicalDiff;
   }

   // check if position has changed
   if (fMove != 0 && (fSmax != oldMax || fSmin != oldMin)) {
      fClient->NeedRedraw(this);
      SendMessage(fMsgWindow, MK_MSG(kC_HSLIDER, kSL_POS), fWidgetId, 0);
      fClient->ProcessLine(fCommand, MK_MSG(kC_HSLIDER, kSL_POS), fWidgetId, 0);
      PositionChanged();
   }
   return kTRUE;
}


ROOT page - Class index - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.