/*
* File name: childframe.cpp
* Location: See Matrox Example Launcher in the MIL Control Center
* 
*/
//
// Copyright (C) Matrox Electronic Systems Ltd., 1992-2020.
// All Rights Reserved
#include <mil.h>
#include <gtk/gtk.h>
#include <X11/Xlib.h>
#include "mdispgtkapp.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_box_new (GTK_ORIENTATION_VERTICAL, 0);
   gtk_container_add (GTK_CONTAINER (m_window), vbox); 

   m_DrawingArea = gtk_drawing_area_new ();
   gtk_box_pack_start (GTK_BOX (vbox), m_DrawingArea, TRUE, TRUE, 0);

   // 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());
   gtk_window_set_default_size (GTK_WINDOW(m_window),100,100);
   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 !!! */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
   gtk_widget_set_double_buffered(m_DrawingArea,FALSE);
G_GNUC_END_IGNORE_DEPRECATIONS
   /* !!! 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);
   m_ExposeHandlerId = g_signal_connect (G_OBJECT (m_DrawingArea), "draw", 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()
   {
   g_signal_handler_disconnect (G_OBJECT (m_DrawingArea), m_ExposeHandlerId);
   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::Destroy()
   {
   if (m_View && m_View->IsModified()) 
      {
      GtkWidget *dialog = gtk_message_dialog_new (m_mf?GTK_WINDOW(m_mf->MainWindow()):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");
      gint result = gtk_dialog_run (GTK_DIALOG (dialog));
      gtk_widget_destroy (dialog);
      switch(result)
         {
         case GTK_RESPONSE_YES:
            m_mf->fileSaveAs(NULL,NULL, m_mf);
            break;
         case GTK_RESPONSE_NO:
            break;
            }
      }
   
   // remove the view
   if(m_View)
      delete m_View;
   m_View = NULL;               
   
   }
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;
   
   cf->Destroy();
   
   if(mf)
      {
      mf->remove(cf);
      }
   
   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);
   g_return_val_if_fail(!mf->Quit(), true);
   mf->setcf(cf);
   return true;
   }

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

gboolean ChildFrame::OnChildExpose(GtkWidget *widget, cairo_t *cr, gpointer user_data)
   {
   ChildFrame* cf = (ChildFrame *) user_data;
   g_return_val_if_fail(cf, true);
   MainFrame* mf = cf->m_mf;
   cf->m_View->Paint(cr);
   return true;
   }

void ChildFrame::UpdateStatusBar()
   {
   if(gtk_widget_is_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_is_visible(m_window))
      {
      GtkAllocation allocation;
      gtk_widget_get_allocation (m_StatusBar, &allocation);
      NewSizeY+= allocation.height;
      gdk_window_resize(gtk_widget_get_window(m_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);
   }

GtkWidget *ChildFrame::ParentWindow()
   {
   return m_mf->MainWindow();
   }