//<copyright>
//
// Copyright (c) 1995
// Institute for Information Processing and Computer Supported New Media (IICM),
// Graz University of Technology, Austria.
//
//</copyright>



//<file>
//
//
// Name:          fslider.C
//
// Purpose:       Implementation of class FieldSlider
//
// Created:       19 May 95   Bernhard Marschall
// Modified:      19 May 95   Bernhard Marschall
//
//
// Description:
//
//</file>


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "fslider.h"

#include <InterViews/adjust.h>
#include <InterViews/font.h>
#include <InterViews/layout.h>
#include <InterViews/observe.h>
#include <IV-look/kit.h>

#include "adjvalue.h"
#include "field.h"


//---------- FieldObserver ----------------------------------------------

class FieldObserver : public Observer {
public:
  FieldObserver(FieldSlider*);
  ~FieldObserver() {}

  virtual void update(Observable*);

private:
  FieldSlider* fslider_;
};


FieldObserver::FieldObserver(FieldSlider* fslider)
{
  fslider_ = fslider;
}


void FieldObserver::update(Observable*)
{
  fslider_->setField();
}

//---------- Callbacks --------------------------------------------------

declareFieldEditorCallback31(FieldSlider)
implementFieldEditorCallback31(FieldSlider)

//---------- FieldSlider ---------------------------------------------

FieldSlider::FieldSlider(float lower, float upper, float initial,
                         int precision, const char* pattern)
: InputHandler(nil, WidgetKit::instance()->style()),
  adjInside_(true)
{
  adj_ = new AdjValue(lower, upper, initial);
  init(precision, pattern);
}

FieldSlider::FieldSlider(Adjustable* adj, int precision, const char* pattern)
: InputHandler(nil, WidgetKit::instance()->style()),
  adjInside_(false)
{
  adj_ = adj;
  init(precision, pattern);
}

void FieldSlider::init(int precision, const char* pattern)
{
  WidgetKit& kit = *WidgetKit::instance();
  const LayoutKit& layout = *LayoutKit::instance();

  // store precision and make format string for (s)printf
  precision_ = precision;
  sprintf(format_, "%%.%df", precision_);

  // scrollbar
  Glyph* scrollbar = kit.hscroll_bar(adj_);
  fobs_ = new FieldObserver(this);
  adj_->attach(Dimension_X, fobs_);

  // field editor
  kit.begin_style("FieldEditor", "EditLabel");
  field_ = new FieldEditor31(
    &kit, kit.style(), "     ",
    new FieldEditorCallback31(FieldSlider)(
      this, &FieldSlider::accept, nil, nil
    )
  );   // ref'd by hbox
  field_->showModifications(0);
  setField();
  append_input_handler(field_);

  // calculate horizontal size of field editor
  const Font* font = kit.font();
  float hsize;
  if (pattern) {
    // use pattern as template
    hsize = font->width(pattern, strlen(pattern));
  }
  else {
    // get width from range and precision
    char buf[32];
    sprintf(buf, format_, adj_->lower(Dimension_X));
    float size = font->width(buf, strlen(buf));
    sprintf(buf, format_, adj_->upper(Dimension_X));
    float size2 = font->width(buf, strlen(buf));
    hsize = (size < size2) ? size2 : size;
    size = font->width('8');
    hsize += precision_ * size;
  }
  hsize += 15;   // some margin
  kit.end_style();

  // build everything together
  body(
    layout.hbox(
      layout.vcenter(layout.hfixed(field_, hsize)),
      layout.hspace(15),
      layout.vcenter(scrollbar)
    )
  );
}

//-----------------------------------------------------------------------

FieldSlider::~FieldSlider()
{
  adj_->detach(Dimension_X, fobs_);
  delete fobs_;
  if (adjInside_) delete adj_;
}

//-----------------------------------------------------------------------

void FieldSlider::set_value(float value)
{
  adj_->scroll_to(Dimension_X, value);
}

float FieldSlider::get_value() const
{
  return adj_->cur_lower(Dimension_X);
}

//-----------------------------------------------------------------------

void FieldSlider::setField()
{
  char buf[32];
  sprintf(buf, format_, get_value());
  field_->field(buf);
}

void FieldSlider::accept(FieldEditor31*, char)
{
  // read & set value
  float val = atof(field_->field());
  set_value(val);
}
