
/* 
A* -------------------------------------------------------------------
B* This file contains source code for the PyMOL computer program
C* copyright 1998-2002 by Warren Lyford Delano of DeLano Scientific. 
D* -------------------------------------------------------------------
E* It is unlawful to modify or remove this copyright notice.
F* -------------------------------------------------------------------
G* Please see the accompanying LICENSE file for further information. 
H* -------------------------------------------------------------------
I* Additional authors of this source file include:
-* 
-* 
-*
Z* -------------------------------------------------------------------
*/
#include"os_gl.h"
#include"Base.h"
#include"Block.h"
#include"Ortho.h"
#include"ScrollBar.h"
#include"CGO.h"

bool ScrollBar::isMaxed() const
{
  if(m_ValueMax > 0.0F) {
    return m_Value == m_ValueMax;
  } else
    return false;
}

void ScrollBar::update()
{
  int range;

  if(m_HorV) {
    range = (rect.right - rect.left);
  } else {
    range = (rect.top - rect.bottom);
  }
  m_ExactBarSize = (range * m_DisplaySize) / static_cast<float>(m_ListSize);
  m_BarSize = static_cast<int> (0.499F + m_ExactBarSize);
  if(m_BarSize < 4)
    m_BarSize = DIP2PIXEL(4);
  m_BarRange = range - m_BarSize;
  if(m_BarRange < 2)
    m_BarRange = 2;
  m_ValueMax = static_cast<float>(m_ListSize - m_DisplaySize);
  if(m_ValueMax < 1)
    m_ValueMax = 1;
  m_Value = std::clamp(m_Value, 0.0f, m_ValueMax);
}

void ScrollBar::fill(CGO* orthoCGO)
{
  if (orthoCGO)
    CGOColorv(orthoCGO, BackColor);
#ifndef PURE_OPENGL_ES_2
  else
    glColor3fv(BackColor);
#endif
  Block::fill(orthoCGO);
}

void ScrollBar::drawImpl(bool bFill, CGO* orthoCGO)
{
  int top, left, bottom, right;

  if (bFill)
    fill(orthoCGO);

  update();

  float value = std::min(m_Value, m_ValueMax);

  if(m_HorV) {
    top = rect.top - 1;
    bottom = rect.bottom + 1;
    left = (int) (0.499F + rect.left + (m_BarRange * value) / m_ValueMax);
    right = left + m_BarSize;
    m_BarMin = left;
    m_BarMax = right;
  } else {
    top = (int) (0.499F + rect.top - (m_BarRange * value) / m_ValueMax);
    bottom = top - m_BarSize;
    left = rect.left + 1;
    right = rect.right - 1;
    m_BarMin = top;
    m_BarMax = bottom;
  }

  if(m_G->HaveGUI && m_G->ValidContext) {

    if (orthoCGO){
      CGOColor(orthoCGO, 0.8F, 0.8F, 0.8F);
      CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
      CGOVertex(orthoCGO, right, top, 0.f);
      CGOVertex(orthoCGO, right, bottom + 1, 0.f);
      CGOVertex(orthoCGO, left, top, 0.f);
      CGOVertex(orthoCGO, left, bottom + 1, 0.f);
      CGOEnd(orthoCGO);
    } else {
      glColor3f(0.8F, 0.8F, 0.8F);
      glBegin(GL_POLYGON);
      glVertex2i(right, top);
      glVertex2i(right, bottom + 1);
      glVertex2i(left, bottom + 1);
      glVertex2i(left, top);
      glEnd();
    }

    if (orthoCGO){
      CGOColor(orthoCGO, 0.3F, 0.3F, 0.3F);
      CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
      CGOVertex(orthoCGO, right, top - 1, 0.f);
      CGOVertex(orthoCGO, right, bottom, 0.f);
      CGOVertex(orthoCGO, left + 1, top - 1, 0.f);
      CGOVertex(orthoCGO, left + 1, bottom, 0.f);
      CGOEnd(orthoCGO);
    } else {
      glColor3f(0.3F, 0.3F, 0.3F);
      glBegin(GL_POLYGON);
      glVertex2i(right, top - 1);
      glVertex2i(right, bottom);
      glVertex2i(left + 1, bottom);
      glVertex2i(left + 1, top - 1);
      glEnd();
    }

    if (orthoCGO){
      CGOColor(orthoCGO, 0.3F, 0.3F, 0.3F);
      CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
      CGOVertex(orthoCGO, right, bottom + 1, 0.f);
      CGOVertex(orthoCGO, right, bottom, 0.f);
      CGOVertex(orthoCGO, left, bottom + 1, 0.f);
      CGOVertex(orthoCGO, left, bottom, 0.f);
      CGOEnd(orthoCGO);
    } else {
      glColor3f(0.3F, 0.3F, 0.3F);
      glBegin(GL_POLYGON);
      glVertex2i(right, bottom + 1);
      glVertex2i(right, bottom);
      glVertex2i(left, bottom);
      glVertex2i(left, bottom + 1);
      glEnd();
    }

    if (orthoCGO){
      CGOColorv(orthoCGO, m_BarColor);
      CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
      CGOVertex(orthoCGO, right - 1, top - 1, 0.f);
      CGOVertex(orthoCGO, right - 1, bottom + 1, 0.f);
      CGOVertex(orthoCGO, left + 1, top - 1, 0.f);
      CGOVertex(orthoCGO, left + 1, bottom + 1, 0.f);
      CGOEnd(orthoCGO);
    } else {
      glColor3fv(m_BarColor);
      glBegin(GL_POLYGON);
      glVertex2i(right - 1, top - 1);
      glVertex2i(right - 1, bottom + 1);
      glVertex2i(left + 1, bottom + 1);
      glVertex2i(left + 1, top - 1);
      glEnd();
    }
  }
}

void ScrollBar::drawHandle(float alpha, CGO* orthoCGO)
{
  float value;
  int top, left, bottom, right;

  value = std::min(m_Value, m_ValueMax);

  if(m_HorV) {
    top = rect.top - 1;
    bottom = rect.bottom + 1;
    left = (int) (0.499F + rect.left + (m_BarRange * value) / m_ValueMax);
    right = left + m_BarSize;
  } else {
    top = (int) (0.499F + rect.top - (m_BarRange * value) / m_ValueMax);
    bottom = top - m_BarSize;
    left = rect.left + 1;
    right = rect.right - 1;
  }

  if(m_G->HaveGUI && m_G->ValidContext) {

    glEnable(GL_BLEND);
    if (orthoCGO){
      CGOAlpha(orthoCGO, alpha);
      CGOColor(orthoCGO, 0.8F, 0.8F, 0.8F);
      CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
      CGOVertex(orthoCGO, right, top, 0.f);
      CGOVertex(orthoCGO, right, bottom + 1, 0.f);
      CGOVertex(orthoCGO, left, top, 0.f);
      CGOVertex(orthoCGO, left, bottom + 1, 0.f);
      CGOEnd(orthoCGO);
      CGOAlpha(orthoCGO, 1.f);
    } else {
      glColor4f(0.8F, 0.8F, 0.8F, alpha);
      glBegin(GL_POLYGON);
      glVertex2i(right, top);
      glVertex2i(right, bottom + 1);
      glVertex2i(left, bottom + 1);
      glVertex2i(left, top);
      glEnd();
    }

    if (orthoCGO){
      CGOAlpha(orthoCGO, alpha);
      CGOColor(orthoCGO, 0.3F, 0.3F, 0.3F);
      CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
      CGOVertex(orthoCGO, right, top - 1, 0.f);
      CGOVertex(orthoCGO, right, bottom, 0.f);
      CGOVertex(orthoCGO, left + 1, top - 1, 0.f);
      CGOVertex(orthoCGO, left + 1, bottom, 0.f);
      CGOEnd(orthoCGO);
      CGOAlpha(orthoCGO, 1.f);
    } else {
      glColor4f(0.3F, 0.3F, 0.3F, alpha);
      glBegin(GL_POLYGON);
      glVertex2i(right, top - 1);
      glVertex2i(right, bottom);
      glVertex2i(left + 1, bottom);
      glVertex2i(left + 1, top - 1);
      glEnd();
    }

    if (orthoCGO){
      CGOAlpha(orthoCGO, alpha);
      CGOColor(orthoCGO, 0.3F, 0.3F, 0.3F);
      CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
      CGOVertex(orthoCGO, right, bottom + 1, 0.f);
      CGOVertex(orthoCGO, right, bottom, 0.f);
      CGOVertex(orthoCGO, left, bottom, 0.f);
      CGOVertex(orthoCGO, left, bottom + 1, 0.f);
      CGOEnd(orthoCGO);
      CGOAlpha(orthoCGO, 1.f);
    } else {
      glColor4f(0.3F, 0.3F, 0.3F, alpha);
      glBegin(GL_POLYGON);
      glVertex2i(right, bottom + 1);
      glVertex2i(right, bottom);
      glVertex2i(left, bottom);
      glVertex2i(left, bottom + 1);
      glEnd();
    }

    if (orthoCGO){
      CGOAlpha(orthoCGO, alpha);
      CGOColor(orthoCGO, m_BarColor[0], m_BarColor[1], m_BarColor[2]);
      CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
      CGOVertex(orthoCGO, right - 1, top - 1, 0.f);
      CGOVertex(orthoCGO, right - 1, bottom + 1, 0.f);
      CGOVertex(orthoCGO, left + 1, top - 1, 0.f);
      CGOVertex(orthoCGO, left + 1, bottom + 1, 0.f);
      CGOEnd(orthoCGO);
      CGOAlpha(orthoCGO, 1.f);
    } else {
      glColor4f(m_BarColor[0], m_BarColor[1], m_BarColor[2], alpha);
      glBegin(GL_POLYGON);
      glVertex2i(right - 1, top - 1);
      glVertex2i(right - 1, bottom + 1);
      glVertex2i(left + 1, bottom + 1);
      glVertex2i(left + 1, top - 1);
      glEnd();
    }
    glDisable(GL_BLEND);
  }
}

int ScrollBar::click(int button, int x, int y, int mod)
{
  int grab = 0;

  if(button == P_GLUT_MIDDLE_BUTTON) {
    if(m_HorV) {
      if(x < m_BarMin || x > m_BarMax)
        setValue((m_ListSize * (x - rect.left)) /
            (rect.right - rect.left) - m_DisplaySize * 0.5F);
      grab = x;
    } else {
      if(y > m_BarMin || y < m_BarMax)
        setValue((m_ListSize * (y - rect.top)) /
            (rect.bottom - rect.top) - m_DisplaySize * 0.5F);
      grab = y;
    }
  } else {
    if(m_HorV) {
      if(x > m_BarMax) {
        m_Value += m_DisplaySize;
      } else if(x < m_BarMin) {
        m_Value -= m_DisplaySize;
      } else {
        grab = x;
      }
    } else {
      if(y > m_BarMin) {
        m_Value -= m_DisplaySize;
      } else if(y < m_BarMax) {
        m_Value += m_DisplaySize;
      } else {
        grab = y;
      }
    }
  }

  if(grab) {
    OrthoGrab(m_G, this);
    m_StartPos = grab;
    m_StartValue = m_Value;
  }

  OrthoDirty(m_G);
  return 0;
}

int ScrollBar::drag(int x, int y, int mod)
{
  int displ;
  if(m_HorV)
    displ = m_StartPos - x;
  else
    displ = y - m_StartPos;
  setValue(m_StartValue - (m_ValueMax * displ) / m_BarRange);
  OrthoDirty(m_G);
  return true;
}

int ScrollBar::release(int button, int x, int y, int mod)
{
  OrthoUngrab(m_G);
  OrthoDirty(m_G);
  return 0;
}

void ScrollBar::setLimits(int list_size, int display_size)
{
  m_ListSize = list_size;
  m_DisplaySize = display_size;
  update();
}

void ScrollBar::setBox(int top, int left, int bottom, int right)
{
  rect.top = top;
  rect.left = left;
  rect.bottom = bottom;
  rect.right = right;
}

