/*
* File name: childframe.cpp
* Location:  ...\Matrox Imaging\MILxxx\Examples\LinuxSpecific\MdispGtk
*             
*/
//
// Copyright (C) Matrox Electronic Systems Ltd., 1992-2015.
// All Rights Reserved


#include <gtk/gtk.h>
#include <X11/Xlib.h>
#include <mil.h>
#include "MdispGtk.h"
#include <gdk/gdkx.h>
#include "childframe.h"
#include "mdispgtkview.h"
#include "mainframe.h"
#include "mdispgtkmarshal.h"

gint ChildFrame::SignalId = 0;

ChildFrame::ChildFrame(MainFrame* mf):m_mf(mf)
   {
   m_View                 = NULL;
   m_FrameStr[0]          ='\0';
   m_ScaleStr[0]          ='\0';
   m_MouseStr[0]          ='\0';

   GtkWidget* vbox        = NULL;

   SignalId++;
   m_frameRateChangedSignalName     =  g_strdup_printf("frame-rate-changed-%d", SignalId);
   m_zoomFactorChangedSignalName    =  g_strdup_printf("zoom-factor-changed-%d",SignalId);
   m_mousePositionChangedSignalName =  g_strdup_printf("mouse-position-changed-%d",SignalId);

   m_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   
   m_frameRateChangedSignal = g_signal_new(m_frameRateChangedSignalName,
                                           G_TYPE_OBJECT,
                                           G_SIGNAL_RUN_LAST,
                                           0,
                                           NULL,
                                           NULL,
                                           mdispgtk_marshal_VOID__DOUBLE,       
                                           G_TYPE_NONE,
                                           1,
                                           G_TYPE_DOUBLE);


   m_zoomFactorChangedSignal = g_signal_new(m_zoomFactorChangedSignalName,
                                            G_TYPE_OBJECT,
                                            G_SIGNAL_RUN_LAST,
                                            0,
                                            NULL,
                                            NULL,
                                            mdispgtk_marshal_VOID__DOUBLE_DOUBLE,       
                                            G_TYPE_NONE,
                                            2,
                                            G_TYPE_DOUBLE,
                                            G_TYPE_DOUBLE);


   m_mousePositionChangedSignal = g_signal_new(m_mousePositionChangedSignalName,
                                             G_TYPE_OBJECT,
                                             G_SIGNAL_RUN_LAST,
                                             0,
                                             NULL,
                                             NULL,
                                             mdispgtk_marshal_VOID__INT_INT_DOUBLE_DOUBLE, 
                                             G_TYPE_NONE,
                                             4,
                                             G_TYPE_INT,
                                             G_TYPE_INT,
                                             G_TYPE_DOUBLE,
                                             G_TYPE_DOUBLE);

   // if we want to make image child window in the center 
   // gtk_window_set_position(GTK_WINDOW(m_window), GTK_WIN_POS_CENTER);    

   vbox = gtk_vbox_new (false, 0);
   gtk_container_add (GTK_CONTAINER (m_window), vbox); 

   m_DrawingArea = gtk_drawing_area_new ();
   gtk_container_add (GTK_CONTAINER (vbox), m_DrawingArea);

   // for each child frame drawin area attach parent frame
   GtkWidget* mainWindow =  m_mf->MainWindow();
   MdispGtkApp* App = (MdispGtkApp *) g_object_get_data(G_OBJECT(mainWindow),"App");
   g_object_set_data(G_OBJECT(m_DrawingArea),"App",(void *) App);
   g_object_set_data(G_OBJECT(m_DrawingArea),"MainWindow",(void *) mainWindow);

   // create the view and set it's parent
   m_View = new MdispGtkView(this); 

   gtk_window_set_title(GTK_WINDOW(m_window), m_View->filename());

   m_StatusBar = gtk_statusbar_new ();
   gtk_box_pack_end (GTK_BOX (vbox), m_StatusBar, false, false, 0);

   gtk_widget_set_events (m_DrawingArea, GDK_EXPOSURE_MASK | GDK_SCROLL_MASK);

   /* !!! very important to get drawing area repaint correctly in Gtk !!! */
   gtk_widget_set_double_buffered(m_DrawingArea,FALSE);
   /* !!! disable mouse handling in Gtk for this widget */
   gtk_widget_set_events(m_DrawingArea,0);

   // attach callbacks to events 
   g_signal_connect (G_OBJECT (m_window), "focus-in-event", G_CALLBACK (ChildFrame::OnChildGetFocus),this);
   g_signal_connect (G_OBJECT (m_window), "delete-event",   G_CALLBACK (ChildFrame::OnChildDelete),this);
   g_signal_connect (G_OBJECT (m_window), "destroy",        G_CALLBACK (ChildFrame::OnChildDestroy),this);
   g_signal_connect (G_OBJECT (m_DrawingArea), "configure-event", G_CALLBACK (ChildFrame::OnChildConfigure),this);
   g_signal_connect (G_OBJECT (m_DrawingArea), "expose-event", G_CALLBACK (ChildFrame::OnChildExpose),this);
   g_signal_connect (G_OBJECT (m_window), m_frameRateChangedSignalName, G_CALLBACK (ChildFrame::OnFrameRateChanged),this);
   g_signal_connect (G_OBJECT (m_window), m_zoomFactorChangedSignalName, G_CALLBACK (ChildFrame::OnZoomFactorChanged),this);
   g_signal_connect (G_OBJECT (m_window), m_mousePositionChangedSignalName, G_CALLBACK (ChildFrame::OnMousePositionChanged),this);


   gtk_widget_show_all(m_window);
   gdk_display_flush(gdk_display_get_default());

   // set this child as current child frame
   m_mf->setcf(this);

   UpdateStatusBarWithFrameRate(0.0);
   UpdateStatusBarWithScale(1.0, 1.0);
   UpdateStatusBarWithMousePosition(0,0,0.0,0.0);

   m_layout = gtk_widget_create_pango_layout(m_DrawingArea,NULL);

   }

ChildFrame::~ChildFrame()
   {
   if(m_View)  delete m_View;
   g_free(m_frameRateChangedSignalName);
   g_free(m_zoomFactorChangedSignalName);
   g_free(m_mousePositionChangedSignalName);
   }

MdispGtkView* ChildFrame::View()
   {
   return m_View;
   }

void ChildFrame::close()
   {
   gtk_widget_destroy(m_window);
   }

void ChildFrame::setTitle(const gchar* title)
   {
   if(title)
      gtk_window_set_title(GTK_WINDOW(m_window),title);
   }

void ChildFrame::show()
   {
   gtk_widget_show_all(m_window);
   }

void ChildFrame::OnChildDestroy(GtkWidget *widget, gpointer user_data)
   {
   ChildFrame* cf = (ChildFrame *) user_data;
   g_return_if_fail(cf);
   cf->OnChildDelete(widget,NULL, user_data);
   }
gboolean ChildFrame::OnChildDelete(GtkWidget *widget, GdkEvent  *event, gpointer user_data)
   {
   ChildFrame* cf = (ChildFrame *) user_data;
   g_return_val_if_fail(cf, false);
   MainFrame* mf = cf->m_mf;
   gint result;

   if(cf->View() && cf->View()->IsModified()) 
      {
      GtkWidget *dialog = gtk_message_dialog_new (NULL,
                                                  GTK_DIALOG_DESTROY_WITH_PARENT,
                                                  GTK_MESSAGE_QUESTION,
                                                  GTK_BUTTONS_YES_NO,
                                                  " MdispGtk Save Image ?");
      gtk_window_set_title(GTK_WINDOW(dialog),"MdispGtk Message");
      result = gtk_dialog_run (GTK_DIALOG (dialog));
      gtk_widget_destroy (dialog);
      switch(result)
         {
         case GTK_RESPONSE_YES:
            mf->fileSaveAs(NULL,mf);            
            break;
         case GTK_RESPONSE_NO:
            break;
         }
      }
   if(mf)
      {
      mf->remove(cf);
      }
   // remove the view
   if(cf->m_View) delete cf->m_View;
   cf->m_View = NULL;               
   return false;
    }

gboolean ChildFrame::OnChildGetFocus(GtkWidget *widget, GdkEventFocus  *event, gpointer user_data)
   {
   ChildFrame* cf = (ChildFrame *) user_data;
   g_return_val_if_fail(cf, true);
   MainFrame* mf = cf->m_mf;
   g_return_val_if_fail(mf, true);
   mf->setcf(cf);
   return true;
   }

gboolean ChildFrame::OnChildConfigure(GtkWidget *widget, GdkEventConfigure  *event, gpointer user_data)
   {
   return true;
   }

gboolean ChildFrame::OnChildExpose(GtkWidget *widget, GdkEventExpose  *event, gpointer user_data)
   {
   ChildFrame* cf = (ChildFrame *) user_data;
   g_return_val_if_fail(cf, true);

   cf->m_View->Paint();
   return true;
   }

void ChildFrame::UpdateStatusBar()
   {
   if(GTK_WIDGET_VISIBLE(m_window))
      {
      gchar *text = g_strdup_printf("%s      | %s    %s",
                                    m_FrameStr,
                                    m_ScaleStr,
                                    m_MouseStr);
      gtk_statusbar_push (GTK_STATUSBAR(m_StatusBar), 0, text);
      g_free(text);
      }
   }

void ChildFrame::UpdateStatusBarWithFrameRate(MIL_DOUBLE CurrentRate)
   {
   if(CurrentRate == M_INVALID)
      {
      g_snprintf(m_FrameStr,STRING_SIZE,"%s","Display Updates Not Available");
      }
   else
      {
      g_snprintf(m_FrameStr,STRING_SIZE,"Display Updates :%.2f fps",CurrentRate);
      }
   UpdateStatusBar();
   }

void ChildFrame::UpdateStatusBarWithScale(MIL_DOUBLE CurrentScaleX, MIL_DOUBLE CurrentScaleY)
   {
   g_snprintf(m_ScaleStr,STRING_SIZE,"%.4f, %.4f",CurrentScaleX, CurrentScaleY );
   UpdateStatusBar();
   }

void ChildFrame::UpdateStatusBarWithMousePosition(long DispX, long DispY, double BufX, double BufY)
   {
   g_snprintf(m_MouseStr,STRING_SIZE,"M:(%d,%d)->(%.2f,%.2f)",(gint)DispX, (gint)DispY, BufX, BufY);
   UpdateStatusBar();
   }

void ChildFrame::UpdateContentSize(long SizeX, long SizeY)
   {
   long NewSizeX = SizeX; 
   long NewSizeY = SizeY;
   
   if(GTK_WIDGET_VISIBLE(m_window))
      {
      NewSizeY+= m_StatusBar->allocation.height;
      gdk_window_resize(m_window->window,NewSizeX,NewSizeY);
      }
   }

void ChildFrame::OnFrameRateChanged(GtkWidget *widget, gdouble Rate, gpointer user_data)
   {
   ChildFrame* cf = (ChildFrame *) user_data;
   g_return_if_fail(cf);
   cf->UpdateStatusBarWithFrameRate(Rate);
   }

void ChildFrame::OnZoomFactorChanged(GtkWidget *widget, gdouble ScaleX, gdouble ScaleY, gpointer user_data)
   {
   ChildFrame* cf = (ChildFrame *) user_data;
   g_return_if_fail(cf);
   cf->UpdateStatusBarWithScale(ScaleX, ScaleY);
   }

void ChildFrame::OnMousePositionChanged(GtkWidget *widget, gint DispX, gint DispY, gdouble BufX, gdouble BufY, gpointer user_data)
   {
   ChildFrame* cf = (ChildFrame *) user_data;
   g_return_if_fail(cf);
   cf->UpdateStatusBarWithMousePosition(DispX, DispY, BufX, BufY);
   }