/*
  mffm Time Code
  Time Code for multimedia systems

  Copyright (C) 2000, 2001 Matt R. Flax <flatmax@ieee.org>
  
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
  
  You have received a copy of the GNU Lesser General Public License
  along with this library.
*/
#ifndef FIELDINTERFACE_H_
#define FIELDINTERFACE_H_

#include <iostream>
#include "../../X/gtkInterface.H"
#include "../field.H"
#include "commonTimeCodeX.H"
#include "XPMDigits.H"

class FieldInterface : public field, public HBox {
  GtkPixmap **digitsGtk; /// The digit GtkPixmaps
  GtkWidget **digitsEventBox; /// The event box for handling button presses

  void eventSetup(void){
    for (int i=0; i<digitCnt();i++){
      gtk_widget_add_events(digitsEventBox[i], GDK_BUTTON_RELEASE_MASK);
      gtk_signal_connect (GTK_OBJECT(digitsEventBox[i]), "button-release-event", GTK_SIGNAL_FUNC(digitPress), this);
    }
  }

public:
  FieldInterface(int minVal, int startVal, int maxVal): field (minVal, startVal, maxVal){
#if DEBUG > 1
    std::cout<<"FieldInterface::FieldInterface(minVal, startVal, maxVal)"<<std::endl;
#endif
    //Init the Gtk pixmaps
    digitsGtk =new GtkPixmap*[digitCnt()];
    if (!digitsGtk){
      std::cerr <<"XPM Alloc b: Out of memory"<<std::endl;
      exit(-1);
    }
    for (int i=0;i<digitCnt();i++)
      digitsGtk[i]=NULL;
    

    // Init the GtkEventBoxs
    digitsEventBox = new GtkWidget*[digitCnt()];
    if (!digitsEventBox){
      std::cerr <<"XPM Alloc a: Out of memory"<<std::endl;
      exit(-1);
    }
    for (int i=0;i<digitCnt();i++)
      digitsEventBox[i]=(GtkWidget*)NULL;
    
    for (int i=0;i<digitCnt();i++){
      digitsGtk[i]=(GtkPixmap*)gtk_pixmap_new(digitsGdk[10], digitsMasks[10]);
      if (!digitsGtk[i]) {
	std::cerr <<"XPM Alloc 1a: Out of memory"<<std::endl;
	exit(-1);
      }
      //flatmax
      gtk_object_ref(GTK_OBJECT(digitsGtk[i]));
      gtk_object_sink(GTK_OBJECT(digitsGtk[i]));

      digitsEventBox[i]=gtk_event_box_new();
      if (!digitsEventBox[i]) {
	std::cerr <<"XPM Alloc 1: Out of memory"<<std::endl;
	exit(-1);
      }
      //flatmax
      gtk_object_ref(GTK_OBJECT(digitsEventBox[i]));
      gtk_object_sink(GTK_OBJECT(digitsEventBox[i]));

      gtk_widget_show(digitsEventBox[i]);
      gtk_container_add (GTK_CONTAINER (digitsEventBox[i]), GTK_WIDGET(digitsGtk[i]));
      gtk_widget_show(GTK_WIDGET(digitsGtk[i]));
    }
    
    // Layout the pixmaps ...
    for (int i=0;i<digitCnt();i++)
      *this<<digitsEventBox[i];
    
    eventSetup(); // Set up the digit press events
    show();
    update();
  }

  ~FieldInterface(void){
#if DEBUG > 1
    std::cout<<"FieldInterface::~FieldInterface"<<std::endl;
#endif
    for (int i=0;i<digitCnt();i++){
      gtk_object_unref(GTK_OBJECT(digitsGtk[i]));
      gtk_object_unref(GTK_OBJECT(digitsEventBox[i]));
    }
    /*    for (int i=0;i<digitCnt();i++)
      if (digitsGtk[i]) gtk_widget_destroy(digitsGtk[i]);
    */
    if (digitsGtk) delete [] digitsGtk;
    /*for (int i=0;i<digitCnt();i++)
      if (digitsEventBox[i]) gtk_widget_destroy(digitsEventBox[i]);
    */
    if (digitsEventBox) delete [] digitsEventBox;
  }

  void update(void){
    //#if DEBUG > 1
    //std::cout <<"FieldInterface::update"<<std::endl;
    ///*for (int i=0;i<digitCnt();i++)
    //  std::cout<<digitsGtk[i]<<'\t';
    //std::cout<<std::endl;
    //*/
    //#endif

    int which;
    for (int i=0;i<digitCnt();i++){
      which=field::digits[digitCnt()-i-1];
      gtk_pixmap_set(GTK_PIXMAP(digitsGtk[i]), digitsGdk[which], digitsMasks[which]);
    }
  }

  void eventReSetup(GtkSignalFunc func, gpointer data){
    // First disconnect the events
    for (int i=0; i<digitCnt();i++){
      gtk_signal_disconnect_by_func(GTK_OBJECT(digitsEventBox[i]), GTK_SIGNAL_FUNC(digitPress),this);
      gtk_signal_connect (GTK_OBJECT(digitsEventBox[i]), "button-release-event", GTK_SIGNAL_FUNC(func), data);
    }
  }

  void eventReSetup(GtkSignalFunc func, GtkSignalFunc oldFunc, gpointer data, gpointer oldData){
    // First disconnect the events
    for (int i=0; i<digitCnt();i++){
      gtk_signal_disconnect_by_func(GTK_OBJECT(digitsEventBox[i]), GTK_SIGNAL_FUNC(oldFunc), oldData);
      gtk_signal_connect (GTK_OBJECT(digitsEventBox[i]), "button-release-event", GTK_SIGNAL_FUNC(func), data);
    }
  }

  inline int whichDigit(GtkWidget *widget, unsigned int button){
    int cnt=digitCnt(), which=0;
    for (int i=0;i<cnt;i++)
      if (digitsEventBox[i]==widget){
	which =(int)rint(pow(10.0,(double)(cnt-i-1)));
	i=cnt;
      }
    if (button==DOWNBUTTON) return -which;
    return which;
  }

  // The digit press callback function
  static int digitPress(GtkWidget *widget, GdkEventButton *event, gpointer data){
    //std::cout<<"FieldInterface: digitPress"<<std::endl;
    FieldInterface *fi=(FieldInterface *)data;
    // Find which digit has been clicked
    int which=fi->whichDigit(widget, event->button);

    if (which !=0){
      if (which>0)
	(*fi)+=which;
      else
	(*fi)-=-which;
    }
    return which;
  }

  FieldInterface& operator =(const counter& f){field::operator =(f); update(); return *this;}
  FieldInterface& operator =(const int& f){field::operator =(f); update(); return *this;}
  FieldInterface& operator+=(const counter& f){field::operator+=(f); update(); return *this;}
  FieldInterface& operator+=(const int& f){field::operator+=(f); update(); return *this;}
  FieldInterface& operator-=(const counter& f){field::operator-=(f); update(); return *this;}
  FieldInterface& operator-=(const int& f){field::operator-=(f); update(); return *this;}
  FieldInterface& operator*=(const counter& f){field::operator*=(f); update(); return *this;}
  FieldInterface& operator*=(const int& f){field::operator*=(f); update(); return *this;}
  FieldInterface& operator/=(const counter& f){field::operator/=(f); update(); return *this;}
  FieldInterface& operator/=(const int& f){field::operator/=(f); update(); return *this;}
};
#endif //FIELDINTERFACE_H_
