/*
* File name: mdispqtview.cpp
* Location:  ...\Matrox Imaging\MILxxx\Examples\General\MdispQt\C++
*             
*/
//
// Copyright (C) Matrox Electronic Systems Ltd., 1992-2015.
// All Rights Reserved

#include "mdispqtview.h"
#include "mdispqtapp.h"
#include "childframe.h"

#include <QtGui>
#if M_MIL_USE_LINUX
#include <QX11Info>
#endif
#include <cmath>
#include <cstdlib>
#if M_MIL_USE_LINUX 
#include <X11/Xlib.h> // For XClearArea, XSendEvent...
#undef Bool
#else
#include <windows.h>
#endif
#include <QColorDialog>
#include <QScrollArea>
#include <QFileDialog>
#include <QMessageBox>

#define NON_MOUSE_MASK (~(ButtonPressMask|ButtonReleaseMask|PointerMotionMask))

#define IMAGE_FILE   M_IMAGE_PATH MIL_TEXT("BaboonRGB.mim")

MIL_INT MFTYPE MouseFct(MIL_INT /*HookType*/, MIL_ID EventID, void* UserDataPtr)
   {
   MdispQtView* pCurrentView = (MdispQtView *)UserDataPtr;

   if(pCurrentView)
      {
      MOUSEPOSITION MousePosition;
      MdispGetHookInfo(EventID, M_MOUSE_POSITION_X,         &MousePosition.m_DisplayPositionX);
      MdispGetHookInfo(EventID, M_MOUSE_POSITION_Y,         &MousePosition.m_DisplayPositionY);
      MdispGetHookInfo(EventID, M_MOUSE_POSITION_BUFFER_X,  &MousePosition.m_BufferPositionX);
      MdispGetHookInfo(EventID, M_MOUSE_POSITION_BUFFER_Y,  &MousePosition.m_BufferPositionY);

      pCurrentView->SetMousePosition(MousePosition);
      ((MdispQtApp*)qApp)->postEvent( pCurrentView, new MilMouseEvent(MousePosition));
      }
   return 0;
   }

MIL_INT MFTYPE GraphicListModifiedHookFct(MIL_INT /*HookType*/, MIL_ID EventID, void* UserDataPtr)
   {
   MdispQtView *pCurrentView = (MdispQtView *)UserDataPtr;

   if(pCurrentView)
      {
      MIL_INT State = M_NULL;
      MgraGetHookInfo(EventID, M_INTERACTIVE_GRAPHIC_STATE, &State);

      if((State != M_STATE_WAITING_FOR_CREATION) && (State != M_STATE_BEING_CREATED))
         {
         pCurrentView->ResetPrimitiveCreation();
         }
      }
   return 0;
   }

MdispQtView::MdispQtView( QWidget* parent )
   :QWidget(parent)
   , m_Modified(false)
   {
   m_InitDone = false;
   setAttribute(Qt::WA_OpaquePaintEvent, true);
   setAttribute(Qt::WA_PaintOnScreen, true);
   setAttribute(Qt::WA_NoSystemBackground, false);


   m_MilOverlayImage            = M_NULL;   // Overlay image buffer identifier
   m_MilDisplay                 = M_NULL;   // Display identifier.
   m_MilGraphContext            = M_NULL;
   m_MilGraphList               = M_NULL;

   static int viewNumber = 0;
   m_Filename = QString(tr("Image%1.mim")).arg(++viewNumber);
   m_FilenameValid = false;

   m_currentZoomFactorX         = 1.0;
   m_currentZoomFactorY         = 1.0;
   m_isWindowed                 = true;
   m_isExclusive                = false;
   m_isOverlayEnabled           = false;    // Overlay state
   m_isOverlayInitialized       = false;
   m_isScaleDisplayEnabled       = false;
   m_isGraphicsAnnotationsEnabled = false;
   m_isNativeAnnotationsEnabled   = false;
   m_currentViewMode            = M_TRANSPARENT;
   m_currentShiftValue          = M_NULL;
   m_isInAsynchronousMode          = false;
   m_currentCompressionType        = M_NULL;
   m_currentAsynchronousFrameRate  = M_INFINITE;
   m_currentQFactor                = M_DEFAULT;
   m_currentRestrictCursor         = M_ENABLE;
   m_PrimitiveInCreation           = M_NULL;

   m_FrameRateTimer = startTimer(500);
   
#if M_MIL_USE_LINUX
   m_GC                           = M_NULL;
#endif
   }

MdispQtView::~MdispQtView()
   {
   // Halt the grab, deselected the display, free the display and the image buffer
   // only if MbufAlloc was successful
   if (m_MilImage)
      {
      // Make sure display is deselected and grab is halt
      RemoveFromDisplay();

      // Free image buffer [CALL TO MIL]
      MbufFree(m_MilImage);
      }
   
#if M_MIL_USE_LINUX
   XFreeGC(QX11Info::display(),m_GC);
#endif
   }

void MdispQtView::GrabStart()
   {
    // TODO: Add your command handler code here
  
  /////////////////////////////////////////////////////////////////////////
  // MIL: Write code that will be executed on a grab start
  /////////////////////////////////////////////////////////////////////////

   // If there is a grab in a view, halt the grab before starting a new one
   if(((MdispQtApp*)qApp)->m_isGrabStarted)
      ((MdispQtApp*)qApp)->m_pGrabView->GrabStop();

   // Start a continuous grab in this view
   MdigGrabContinuous(((MdispQtApp*)qApp)->m_MilDigitizer, m_MilImage);

   // Update the variable GrabIsStarted
   ((MdispQtApp*)qApp)->m_isGrabStarted = true;

   // GrabInViewPtr is now a pointer to m_pGrabView view
   ((MdispQtApp*)qApp)->m_pGrabView = this;

   // Document has been modified
   m_Modified = true;

  /////////////////////////////////////////////////////////////////////////  
  // MIL: Write code that will be executed on a grab start
  /////////////////////////////////////////////////////////////////////////
   
   }

void MdispQtView::GrabStop()
   {
   // TODO: Add your command handler code here
 
   /////////////////////////////////////////////////////////////////////////
  // MIL: Write code that will be executed on a grab stop 
  /////////////////////////////////////////////////////////////////////////
   // Halt the grab
   MdigHalt(((MdispQtApp*)qApp)->m_MilDigitizer);
   ((MdispQtApp*)qApp)->m_isGrabStarted = false;

   /////////////////////////////////////////////////////////////////////////
  // MIL: Write code that will be executed on a grab stop 
  /////////////////////////////////////////////////////////////////////////
   }

void MdispQtView::Overlay( bool on )
   {
   // Enable overlay
   if (on && !m_isOverlayEnabled)
      {
      MdispControl(m_MilDisplay, M_OVERLAY, M_ENABLE);

      //If overlay buffer as not been initialized yet, do it now.
      if(!m_isOverlayInitialized)
         InitializeOverlay();

      m_isOverlayEnabled = true;
      }

   // Disable overlay
   else if (!on && m_isOverlayEnabled)
      {
      // Disable the overlay display. [CALL TO MIL]
      MdispControl(m_MilDisplay, M_OVERLAY, M_DISABLE);

      m_isOverlayInitialized = false;
      m_isOverlayEnabled     = false;
      }

   /////////////////////////////////////////////////////////////////////////
   // MIL: Write code that will be executed when 'add overlay' is selected
   /////////////////////////////////////////////////////////////////////////

   }


void MdispQtView::Initialize()
   {
   // Allocate a display [CALL TO MIL]
   MdispAlloc(((MdispQtApp*)qApp)->m_MilSystem, M_DEFAULT, MIL_TEXT("M_DEFAULT"), M_DEFAULT, &m_MilDisplay);

   if(m_MilDisplay)
      {
      MIL_INT DisplayType = MdispInquire(m_MilDisplay, M_DISPLAY_TYPE, M_NULL);
      
      // Check display type [CALL TO MIL]
      if((DisplayType&(M_WINDOWED|M_EXCLUSIVE)) !=M_WINDOWED)
         m_isWindowed = false;

      if(DisplayType&(M_EXCLUSIVE))
         m_isExclusive = true;
 
      ChangeViewMode(M_DEFAULT);
    
      if(IsNetworkedSystem())
         {
         // Check compression type [CALL TO MIL]
         MdispInquire(m_MilDisplay, M_COMPRESSION_TYPE, &m_currentCompressionType);
         
         // Check asynchronous mode [CALL TO MIL]
         m_isInAsynchronousMode = (MdispInquire(m_MilDisplay, M_ASYNC_UPDATE, M_NULL) == M_ENABLE);
         
         // Check asynchronous frame rate [CALL TO MIL]
         MdispInquire(m_MilDisplay, M_UPDATE_RATE_MAX, &m_currentAsynchronousFrameRate);
         
         // Check Q factor [CALL TO MIL]
         MdispInquire(m_MilDisplay, M_Q_FACTOR, &m_currentQFactor);
         }

      if(m_isExclusive)
         {
         setAttribute(Qt::WA_PaintOnScreen, false);
         MdispInquire(m_MilDisplay, M_RESTRICT_CURSOR,    &m_currentRestrictCursor);
         
         }

    // Allow paning and zooming with the mouse [CALL TO MIL]
    MdispControl(m_MilDisplay, M_MOUSE_USE, M_ENABLE);

      // Allow mouse cursor handling [CALL TO MIL]
      MdispControl(m_MilDisplay, M_MOUSE_CURSOR_CHANGE, M_ENABLE);

      // Hook a function to mouse-movement event, to update cursor position in status bar.
      MdispHookFunction(m_MilDisplay, M_MOUSE_MOVE, MouseFct, (void*)this);
      }
   m_InitDone = true;
   /////////////////////////////////////////////////////////////////////////
   // MIL: Code that will be executed when a view is first attached to the document
   /////////////////////////////////////////////////////////////////////////
   }



void MdispQtView::RemoveFromDisplay()

   {
   //Halt grab if in process in THIS view
   if ((((MdispQtApp*)qApp)->m_pGrabView == this) &&
        ((MdispQtApp*)qApp)->m_isGrabStarted)
      {
      //Ask the digitizer to halt the grab [CALL TO MIL]
      MdigHalt(((MdispQtApp*)qApp)->m_MilDigitizer);


      ((MdispQtApp*)qApp)->m_isGrabStarted = false;
      }

   if (m_MilImage && m_MilDisplay)
      {
      //Deselect the buffer from it's display object and given window [CALL TO MIL]
      MdispDeselect(m_MilDisplay,m_MilImage);

      // Hook from mouse-movement event.
      MdispHookFunction(m_MilDisplay, M_MOUSE_MOVE+M_UNHOOK, MouseFct, (void*)this);

      //Free GraphicList [CALL TO MIL]
      if(m_MilGraphList)
      {
         MgraFree(m_MilGraphList);
         m_MilGraphList = M_NULL;
      }
      if(m_MilGraphContext)
      {
         MgraFree(m_MilGraphContext);
         m_MilGraphContext = M_NULL;
      }

      //Free the display [CALL TO MIL]
      MdispFree(m_MilDisplay);
      m_MilDisplay = M_NULL;
      }
   }

#if M_MIL_USE_WINDOWS
void MdispQtView::resizeEvent(QResizeEvent*)
   {
    if(m_MilDisplay)
       {
       MdispControl(m_MilDisplay, M_UPDATE, M_NOW);
       }
   }
#endif

#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0)
QPaintEngine* MdispQtView::paintEngine()const 
   {
   if (!m_InitDone)
      return NULL;
   else if (m_MilDisplay && m_isWindowed)
      return NULL;
   else
      return QWidget::paintEngine();
   }
#endif


void MdispQtView::paintEvent( QPaintEvent* /*ev*/)
   {
   if(!m_MilDisplay)
      {
      QPainter p( this);
      QFont font;

      font.setStyleStrategy( QFont::NoAntialias );
      font.setBold(true);
      p.setFont(font);
      p.setPen( QColor(255,0,0) );
      p.drawText( 0, 0, width() , p.fontMetrics().height(), Qt::AlignCenter,
                  tr("Display Allocation Failed!") );
      }

   else if (m_isWindowed)
      {
       if (m_isNativeAnnotationsEnabled)
          {
#if M_MIL_USE_LINUX
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
          QPainter p( this);
          QFont font;
          p.setPen( QColor(255,0,255) );
          p.drawText( 0, 0, contentsRect().width(), p.fontMetrics().height(), Qt::AlignCenter,
                      tr("Window Annotations") );
#else
          // PaintEngine is disabled use Xlib functions
          Display *dpy = QX11Info::display();
          MIL_TEXT_CHAR chText[80];
          MosStrcpy(chText, 80, MIL_TEXT("Window Annotation"));
          XDrawString(dpy,winId(),m_GC, contentsRect().width()/3,50, chText,MosStrlen(chText));
          XFlush(dpy);
#endif
#elif M_MIL_USE_WINDOWS
          // PaintEngine is disabled use GDi functions
          RECT rectangle;
          rectangle.top =  0;
          rectangle.left =  0;
          rectangle.right =  rect().width();
          rectangle.bottom = rect().height();
          
          HDC hdc = GetDC((HWND)winId());
          SetTextColor(hdc,RGB(255,0,255));
          SetBkMode(hdc, TRANSPARENT);
          DrawText(hdc,L"Window Annotation", 17,&rectangle, DT_CENTER);
          ReleaseDC((HWND)winId(), hdc);          
#endif
          }
      }
   else
      {
      // In external mode, write message in window
      QPainter p( this);
      QFont font;

      font.setStyleStrategy( QFont::NoAntialias );
      font.setBold(true);
      p.setFont(font);
      p.setPen( QColor(0,0,0) );
      p.drawText( 0, 0, m_isScaleDisplayEnabled ? width() :
                  contentsRect().width(), p.fontMetrics().height(), Qt::AlignLeft,
                  tr("Image Displayed on external screen") );
      }
   }


void MdispQtView::timerEvent( QTimerEvent* e )
   {
   if ( e->timerId() == m_FrameRateTimer )
      {
      MIL_DOUBLE CurrentFrameRate = M_NULL;
      MdispInquire(m_MilDisplay, M_UPDATE_RATE, &CurrentFrameRate);
      emit frameRateChanged(CurrentFrameRate);

      MIL_DOUBLE ZoomX =1.0, ZoomY = 1.0;
      MdispInquire(m_MilDisplay, M_ZOOM_FACTOR_X, &ZoomX);
      MdispInquire(m_MilDisplay, M_ZOOM_FACTOR_Y, &ZoomY);
      emit zoomFactorChanged(ZoomX, ZoomY);
      }
   }

void MdispQtView::ZoomIn()
   {
   if(m_MilDisplay)
    {
       MIL_DOUBLE ZoomX =1.0, ZoomY =1.0;
       MdispInquire(m_MilDisplay,M_ZOOM_FACTOR_X, &ZoomX);
       MdispInquire(m_MilDisplay,M_ZOOM_FACTOR_Y, &ZoomY);

       if(ZoomX <=8.0 && ZoomY<=8.0)
         {
           ZoomX*=2.0;
           ZoomY*=2.0;
         }
       //Perform zooming with MIL (using MdispZoom)
       Zoom( ZoomX, ZoomY);
     }
 }

void MdispQtView::ZoomOut()
   {
  if(m_MilDisplay)
    {
      MIL_DOUBLE ZoomX =1.0, ZoomY =1.0;
      MdispInquire(m_MilDisplay,M_ZOOM_FACTOR_X, &ZoomX);
      MdispInquire(m_MilDisplay,M_ZOOM_FACTOR_Y, &ZoomY);
      if(ZoomX >=0.125 && ZoomY>=0.125)
        {
          ZoomX/=2.0;
          ZoomY/=2.0;
        }
      //Perform zooming with MIL (using MdispZoom)
      Zoom( ZoomX, ZoomY );
    }
  }

void MdispQtView::NoZoom()
   {
  if(m_MilDisplay)
    {
      //Perform zooming with MIL
      Zoom(1.0, 1.0);
         MdispPan(m_MilDisplay, M_NULL,M_NULL);
    }
   }

void MdispQtView::Zoom( MIL_DOUBLE ZoomFactorToApplyX, MIL_DOUBLE ZoomFactorToApplyY )
{
  if( m_MilDisplay)
   {
     //Apply zoom  [CALL TO MIL]
     MdispZoom(m_MilDisplay, ZoomFactorToApplyX, ZoomFactorToApplyY);
     m_currentZoomFactorX = ZoomFactorToApplyX;
     m_currentZoomFactorY = ZoomFactorToApplyY;
     emit zoomFactorChanged(m_currentZoomFactorX, m_currentZoomFactorY);
  }
}

void MdispQtView::ScaleDisplay( bool on )
   {
   if(m_MilDisplay)
      {
#if M_MIL_USE_LINUX      
      if(!on)
         {
         XClearWindow(QX11Info::display(), winId());
         XFlush(QX11Info::display());
         XSync(QX11Info::display(),False);
         }
#endif
      //Using MIL, enable/disable Scale Display Mode [CALL TO MIL]
    MdispControl(m_MilDisplay, M_SCALE_DISPLAY, on ? M_ENABLE : M_DISABLE);

    m_isScaleDisplayEnabled = on;


      // clear contents
      repaint();

      }
   }


void MdispQtView::OnGraRectangle()
   {
   if(m_MilDisplay)
      {
      if(m_isGraphicsAnnotationsEnabled)
         {
         MgraColor(m_MilGraphContext, M_COLOR_WHITE);
         MgraInteractive(m_MilGraphContext, m_MilGraphList, M_GRAPHIC_TYPE_RECT, M_DEFAULT, M_DEFAULT);
         m_PrimitiveInCreation = M_GRAPHIC_TYPE_RECT;
         }
      }
   }
void MdispQtView::OnGraCircle()
   {
   if(m_MilDisplay)
      {
      if(m_isGraphicsAnnotationsEnabled)
         {
         MgraColor(m_MilGraphContext, M_COLOR_YELLOW);
         MgraInteractive(m_MilGraphContext, m_MilGraphList, M_GRAPHIC_TYPE_ARC, M_DEFAULT, M_DEFAULT);
         m_PrimitiveInCreation = M_GRAPHIC_TYPE_ARC;
         }
      }
   }
void MdispQtView::OnGraPolygon()
   {
   if(m_MilDisplay)
      {
      if(m_isGraphicsAnnotationsEnabled)
         {
         MgraColor(m_MilGraphContext, M_COLOR_MAGENTA);
         MgraInteractive(m_MilGraphContext, m_MilGraphList, M_GRAPHIC_TYPE_POLYGON, M_DEFAULT, M_DEFAULT);
         m_PrimitiveInCreation = M_GRAPHIC_TYPE_POLYGON;
         }
      }
   }

void MdispQtView::OnGraChooseColor()
   {
   if(m_MilDisplay && m_MilGraphList)
      {
      QColor c = QColorDialog::getColor(Qt::white,this);
      if(c.isValid())
          {
          MIL_INT NewColor = M_RGB888(c.red(),c.green(), c.blue());
          MgraControlList(m_MilGraphList, M_ALL_SELECTED, M_DEFAULT, M_COLOR, (MIL_INT)NewColor);
          MgraControlList(m_MilGraphList, M_ALL, M_DEFAULT, M_GRAPHIC_SELECTED, M_FALSE);
          }
      }
   }

void MdispQtView::OnGraFill()
   {
   if(m_MilDisplay && m_MilGraphList)
      {
      MgraControlList(m_MilGraphList, M_ALL_SELECTED, M_DEFAULT, M_FILLED, M_TRUE);
      MgraControlList(m_MilGraphList, M_ALL, M_DEFAULT, M_GRAPHIC_SELECTED, M_FALSE);
      }
   }

void MdispQtView::X11Annotations( bool on ) 
   { 
   m_isNativeAnnotationsEnabled = on;
   
#if M_MIL_USE_LINUX
   
   if(on)
      {
      // The connection to the X display must be given to Mil so it
      // can update the window annotation.
      Display *dpy = QX11Info::display();
      MdispControl(m_MilDisplay, M_WINDOW_ANNOTATIONS, M_PTR_TO_DOUBLE(dpy));
      }
   else
      {
      MdispControl(m_MilDisplay,M_WINDOW_ANNOTATIONS,M_NULL);
      }

#else
  if(on)
      {
      MdispControl(m_MilDisplay, M_WINDOW_ANNOTATIONS, M_ENABLE);
      }
   else
      {
      MdispControl(m_MilDisplay,M_WINDOW_ANNOTATIONS,M_DISABLE);
      }
#endif
  repaint();
   }
 
void MdispQtView::GraphicsAnnotations( bool on )
{
if(m_MilDisplay)
   {
   m_isGraphicsAnnotationsEnabled = on;

    if(m_isGraphicsAnnotationsEnabled)
      {
      if(!m_MilGraphContext && !m_MilGraphList)
         {
         MIL_INT BufSizeX  = 0, BufSizeY = 0;
         MIL_INT Offset    = 15;

         MgraAlloc(((MdispQtApp*)qApp)->m_MilSystem, &m_MilGraphContext);
         MgraAllocList(((MdispQtApp*)qApp)->m_MilSystem, M_DEFAULT, &m_MilGraphList);
         MdispControl(m_MilDisplay, M_ASSOCIATED_GRAPHIC_LIST_ID, m_MilGraphList);



         MdispControl(m_MilDisplay, M_UPDATE_GRAPHIC_LIST, M_DISABLE);
         MbufInquire(m_MilImage, M_SIZE_X, &BufSizeX);
         MbufInquire(m_MilImage, M_SIZE_Y, &BufSizeY);

         MgraClear(m_MilGraphContext, m_MilGraphList);

         MgraColor(m_MilGraphContext, M_COLOR_LIGHT_BLUE);
         MgraRect(m_MilGraphContext, m_MilGraphList, Offset, Offset, BufSizeX - Offset, BufSizeY - Offset);

         MgraColor(m_MilGraphContext, M_COLOR_GREEN);
         MgraControl(m_MilGraphContext, M_BACKGROUND_MODE, M_TRANSPARENT);
         MgraControl(m_MilGraphContext, M_TEXT_ALIGN_HORIZONTAL, M_CENTER);
         MgraControl(m_MilGraphContext, M_TEXT_ALIGN_VERTICAL, M_CENTER);
         MgraControl(m_MilGraphContext, M_FONT_SIZE, 24);
         MgraFont(m_MilGraphContext, MIL_FONT_NAME(M_FONT_DEFAULT_TTF));
         MgraText(m_MilGraphContext, m_MilGraphList, BufSizeX/2, Offset, MIL_TEXT("Interactive Graphic Annotations"));
         MdispControl(m_MilDisplay, M_UPDATE_GRAPHIC_LIST, M_ENABLE);
         MdispControl(m_MilDisplay, M_GRAPHIC_LIST_INTERACTIVE, M_ENABLE);

         MgraHookFunction(m_MilGraphList, M_INTERACTIVE_GRAPHIC_STATE_MODIFIED, GraphicListModifiedHookFct, (void*)this);
         }
      }
   else
      {
      MgraHookFunction(m_MilGraphList, M_INTERACTIVE_GRAPHIC_STATE_MODIFIED+M_UNHOOK, GraphicListModifiedHookFct, (void*)this);
      MdispControl(m_MilDisplay, M_ASSOCIATED_GRAPHIC_LIST_ID, M_NULL);

      if(m_MilGraphList)
         {
         MgraFree(m_MilGraphList);
         m_MilGraphList = M_NULL;
         }
      if(m_MilGraphContext)
         {
         MgraFree(m_MilGraphContext);
         m_MilGraphContext = M_NULL;
         }
      }
   }
}


void MdispQtView::ChangeViewMode(long ViewMode,long ShiftValue)
   {
   if(m_MilDisplay)
      {
      //Apply view mode on display [CALL TO MIL]
      MdispControl(m_MilDisplay, M_VIEW_MODE, ViewMode);

      if(ViewMode == M_BIT_SHIFT)
         MdispControl(m_MilDisplay, M_VIEW_BIT_SHIFT, ShiftValue);

      //Check if control worked correctly before considering it as successful [CALL TO MIL]
      if(MdispInquire(m_MilDisplay, M_VIEW_MODE,M_NULL)==ViewMode)
         {
         //Make sure ViewMode Mode combo box shows current view mode
         m_currentViewMode   = ViewMode;
         m_currentShiftValue = ShiftValue;
         }
      }
   }

void MdispQtView::ChangeCompressionType(MIL_INT CompressionType)
   {
   if(m_MilDisplay)
      {
      // Apply compression type to display [CALL TO MIL]
      MdispControl(m_MilDisplay, M_COMPRESSION_TYPE, CompressionType);
   
      // Check if control worked correctly before considering it successful [CALL TO MIL]
      if(MdispInquire(m_MilDisplay, M_COMPRESSION_TYPE, M_NULL) == CompressionType)
         {
         m_currentCompressionType = CompressionType;
         }
      }
   }

void MdispQtView::ChangeAsynchronousMode(bool Enabled, MIL_INT FrameRate)
   {
   if(Enabled && (FrameRate != m_currentAsynchronousFrameRate))
      {
      if(m_MilDisplay)
         {
         // Apply asynchronous frame rate to display [CALL TO MIL]
         MdispControl(m_MilDisplay, M_UPDATE_RATE_MAX, FrameRate);
      
         // Check if control worked correctly before considering it successful [CALL TO MIL]
         if(MdispInquire(m_MilDisplay, M_UPDATE_RATE_MAX, M_NULL) == FrameRate)
            {
            m_currentAsynchronousFrameRate = FrameRate;
            }
         }
      }

   if((Enabled && !m_isInAsynchronousMode) ||
      (!Enabled && m_isInAsynchronousMode))
      {
      if(m_MilDisplay)
         {
         // Apply asynchronous update to display [CALL TO MIL]
         MdispControl(m_MilDisplay, M_ASYNC_UPDATE, (Enabled ? M_ENABLE : M_DISABLE));
      
         // Check if control worked correctly before considering it successful [CALL TO MIL]
         if(MdispInquire(m_MilDisplay, M_ASYNC_UPDATE, M_NULL) == (Enabled ? M_ENABLE : M_DISABLE))
            {
            m_isInAsynchronousMode = Enabled;
            }
         }
      }
   }

void MdispQtView::ChangeQFactor(MIL_INT QFactor)
   {
   if(m_MilDisplay)
      {
      // Apply Q factor to display [CALL TO MIL]
      MdispControl(m_MilDisplay, M_Q_FACTOR, QFactor);
   
      // Check if control worked correctly before considering it successful [CALL TO MIL]
      if(MdispInquire(m_MilDisplay, M_Q_FACTOR, M_NULL) == QFactor)
         {
         m_currentQFactor = QFactor;
         }
      }
   }

bool MdispQtView::IsNetworkedSystem()
   {
   bool NetworkedSystem = false;
   MIL_ID SystemId = ((MdispQtApp*)qApp)->m_MilSystem;

   // Check if system is networked (DistributedMIL) [CALL TO MIL]
   if(SystemId)
      NetworkedSystem = (MsysInquire(SystemId, M_LOCATION, M_NULL) == M_REMOTE);

   return NetworkedSystem;
   }


void MdispQtView::InitializeOverlay()
   {
   // Initialize overlay if not already done
   if ((!m_isOverlayInitialized) && (m_MilDisplay))
      {
      //Only do it on a valid windowed display [CALL TO MIL]
      if (m_MilImage && m_MilDisplay )
         {
         // Prepare overlay buffer //
         ////////////////////////////

         // Enable display overlay annotations.
         MdispControl(m_MilDisplay, M_OVERLAY, M_ENABLE);

         // Inquire the Overlay buffer associated with the displayed buffer [CALL TO MIL]
         MdispInquire(m_MilDisplay, M_OVERLAY_ID, &m_MilOverlayImage);

         // Clear the overlay to transparent.
         MdispControl(m_MilDisplay, M_OVERLAY_CLEAR, M_DEFAULT);
         
         // Disable the overlay display update to accelerate annotations.
         MdispControl(m_MilDisplay, M_OVERLAY_SHOW, M_DISABLE);


         // Draw MIL monochrome overlay annotation *
         //*****************************************

         // Inquire MilOverlayImage size x and y [CALL TO MIL]
         long imageWidth  = MbufInquire(m_MilOverlayImage,M_SIZE_X,M_NULL);
         long imageHeight = MbufInquire(m_MilOverlayImage,M_SIZE_Y,M_NULL);

         // Set graphic text to transparent background. [CALL TO MIL]
         MgraControl(M_DEFAULT, M_BACKGROUND_MODE, M_TRANSPARENT);

         // Set drawing color to white. [CALL TO MIL]
         MgraColor(M_DEFAULT, M_COLOR_WHITE);

         // Print a string in the overlay image buffer. [CALL TO MIL]
         MgraText(M_DEFAULT, m_MilOverlayImage, imageWidth/9, imageHeight/5,    MIL_TEXT(" -------------------- "));
         MgraText(M_DEFAULT, m_MilOverlayImage, imageWidth/9, imageHeight/5+25, MIL_TEXT(" - MIL Overlay Text - "));
         MgraText(M_DEFAULT, m_MilOverlayImage, imageWidth/9, imageHeight/5+50, MIL_TEXT(" -------------------- "));

         // Print a green string in the green component overlay image buffer. [CALL TO MIL]
         MgraColor(M_DEFAULT, M_COLOR_GREEN);
         MgraText(M_DEFAULT, m_MilOverlayImage, imageWidth*11/18, imageHeight/5,    MIL_TEXT(" -------------------- "));
         MgraText(M_DEFAULT, m_MilOverlayImage, imageWidth*11/18, imageHeight/5+25, MIL_TEXT(" - MIL Overlay Text - "));
         MgraText(M_DEFAULT, m_MilOverlayImage, imageWidth*11/18, imageHeight/5+50, MIL_TEXT(" -------------------- "));

         // Draw GDI color overlay annotation *
         //************************************

         // Disable hook to MIL error because control might not be supported
         MappControl(M_DEFAULT, M_ERROR_HOOKS, M_DISABLE);

#if M_MIL_USE_LINUX

         // Create a device context to draw in the overlay buffer with GDI.  [CALL TO MIL]
         MbufControl(m_MilOverlayImage, M_XPIXMAP_ALLOC, M_COMPENSATION_ENABLE);

         // Reenable hook to MIL error
         MappControl(M_DEFAULT, M_ERROR_HOOKS, M_ENABLE);

         // Retrieve the XPIXMAP of the overlay [CALL TO MIL]
         Pixmap XPixmap = (Pixmap)MbufInquire(m_MilOverlayImage, M_XPIXMAP_HANDLE, M_NULL);
         if(XPixmap != M_NULL)
            {
            /* init X */
            Display *dpy = XOpenDisplay("");
            int screen = DefaultScreen(dpy);
            GC gc = XCreateGC(dpy,XPixmap,0,0);
            XColor xcolors[3],exact;
            XPoint Hor[2];
            XPoint Ver[2];
            int i;
            const char *color_names[] = {"red","yellow","blue"};
            MIL_TEXT_CHAR chText[80];

            /* allocate colors */
            for(i=0;i<3;i++)
               {
               if(!XAllocNamedColor(dpy,DefaultColormap(dpy,screen),color_names[i], &xcolors[i],&exact))
                  {
                  fprintf(stderr, "cant't alloc color %s\n", color_names[i]);
                  exit (1);
                  }
               }

            /* Write a blue cross. */
            XSetForeground(dpy,gc, xcolors[2].pixel);
            Hor[0].x = 0;
            Hor[0].y = imageHeight/2;
            Hor[1].x = imageWidth;
            Hor[1].y = imageHeight/2;
            XDrawLines(dpy,XPixmap,gc,Hor, 2, CoordModeOrigin);
            
            Ver[0].x = imageWidth/2;
            Ver[0].y = 0;
            Ver[1].x = imageWidth/2;
            Ver[1].y = imageHeight;
            XDrawLines(dpy,XPixmap,gc,Ver, 2, CoordModeOrigin);
            
            /* Write Red text. */
            XSetForeground(dpy,gc, xcolors[0].pixel);
            MosStrcpy(chText, 80, MIL_TEXT("X Overlay Text"));
            XDrawString(dpy,XPixmap,gc,
                        imageWidth*3/18, imageHeight*17/24,
                        chText,MosStrlen(chText));
            
            /* Write yellow text. */
            XSetForeground(dpy,gc, xcolors[1].pixel);
            XDrawString(dpy,XPixmap,gc,
                        imageWidth*12/18, imageHeight*17/24,
                        chText,MosStrlen(chText));
            
            XSetForeground(dpy,gc, BlackPixel(dpy,screen));
            XFlush(dpy);
            XFreeGC(dpy,gc);
            XCloseDisplay(dpy);

            // Delete created Pixmap.  [CALL TO MIL]
            MbufControl(m_MilOverlayImage, M_XPIXMAP_FREE, M_DEFAULT);
            
            // Signal MIL that the overlay buffer was modified. [CALL TO MIL]
            MbufControl(m_MilOverlayImage, M_MODIFIED, M_DEFAULT);


            }

#else
         // Create a device context to draw in the overlay buffer with GDI.  [CALL TO MIL]
         MbufControl(m_MilOverlayImage, M_DC_ALLOC, M_DEFAULT);

         // Reenable hook to MIL error
         MappControl(M_DEFAULT, M_ERROR_HOOKS, M_ENABLE);

         // Retrieve the HDC of the overlay [CALL TO MIL]
         HDC OverlayDC = (HDC)MbufInquire(m_MilOverlayImage, M_DC_HANDLE, M_NULL);

         if(OverlayDC != M_NULL)
         {
             HGDIOBJ        hpen, hpenOld;
             POINT Hor[2];
             POINT Ver[2];
             SIZE  TxtSz;
             RECT  Txt;
             MIL_TEXT_CHAR  chText[80];
             int            Count;

             /* Draw a blue cross. */
             hpen=CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
             hpenOld = SelectObject(OverlayDC, hpen);

             Hor[0].x = (MIL_INT32)0;
             Hor[0].y = (MIL_INT32)(imageHeight/2);
             Hor[1].x = (MIL_INT32)imageWidth;
             Hor[1].y = (MIL_INT32)(imageHeight/2);
             Polyline(OverlayDC, Hor,2);

             Ver[0].x = (MIL_INT32)(imageWidth/2);
             Ver[0].y = (MIL_INT32)0;
             Ver[1].x = (MIL_INT32)(imageWidth/2);
             Ver[1].y = (MIL_INT32)imageHeight;
             Polyline(OverlayDC, Ver,2);

             SelectObject(OverlayDC, hpenOld);
             DeleteObject(hpen);

             /* Prepare transparent text annotations. */
             SetBkMode(OverlayDC, TRANSPARENT);
             MosStrcpy(chText, 80, MIL_TEXT("GDI Overlay Text"));
             Count = (int) MosStrlen(chText);
             GetTextExtentPoint(OverlayDC, chText, Count, &TxtSz);


             /* Write red text. */
             Txt.left = (MIL_INT32)(imageWidth*3/18);
             Txt.top  = (MIL_INT32)(imageHeight*17/24);
             Txt.right  = (MIL_INT32)(Txt.left + TxtSz.cx);
             Txt.bottom = (MIL_INT32)(Txt.top  + TxtSz.cy);
             SetTextColor(OverlayDC,RGB(255, 0, 0));
             DrawText(OverlayDC, chText, Count, &Txt, DT_RIGHT);

             /* Write yellow text. */
             Txt.left = (MIL_INT32)imageWidth*12/18;
             Txt.top  = (MIL_INT32)imageHeight*17/24;
             Txt.right  = (MIL_INT32)(Txt.left + TxtSz.cx);
             Txt.bottom = (MIL_INT32)(Txt.top  + TxtSz.cy);
             SetTextColor(OverlayDC, RGB(255, 255, 0));
             DrawText(OverlayDC, chText, Count, &Txt, DT_RIGHT);

             // Delete created device context.  [CALL TO MIL]
             MbufControl(m_MilOverlayImage, M_DC_FREE, M_DEFAULT);

             // Signal to MIL that the overlay buffer was modified. [CALL TO MIL]
             MbufControl(m_MilOverlayImage, M_MODIFIED, M_DEFAULT);
         }
#endif
         // Now that overlay buffer is correctly prepared, we can show it [CALL TO MIL]
         MdispControl(m_MilDisplay, M_OVERLAY_SHOW, M_ENABLE);

         // Overlay is now initialized
         m_isOverlayInitialized = true;
         }
      }
   }


void MdispQtView::RestrictCursor(bool on)
   {
   /////////////////////////////////////////////////////////////////////////
   // MIL: Write code that will be executed when 'Restrict Cursor' menu item is clicked
   /////////////////////////////////////////////////////////////////////////

   if(m_MilDisplay)
      {
      MdispControl(m_MilDisplay, M_RESTRICT_CURSOR,on?M_ENABLE:M_DISABLE);

      // Check if control worked correctly before considering it successful [CALL TO MIL]
      MdispInquire(m_MilDisplay, M_RESTRICT_CURSOR, &m_currentRestrictCursor);

      }
   }

bool MdispQtView::newDoc()
   {
   // Set buffer attributes
   if(((MdispQtApp*)qApp)->m_numberOfDigitizer)
   {
      m_bufferAttributes=M_IMAGE+M_DISP+M_GRAB+M_PROC;

      m_bufferAttributes=M_IMAGE+M_DISP+M_GRAB+M_PROC;
      m_imageSizeX = ((MdispQtApp*)qApp)->m_digitizerSizeX;
      m_imageSizeY = ((MdispQtApp*)qApp)->m_digitizerSizeY;
      m_NbBands    = ((MdispQtApp*)qApp)->m_digitizerNbBands;

      // Allocate a buffer [CALL TO MIL]
      MbufAllocColor(((MdispQtApp*)qApp)->m_MilSystem,
                     m_NbBands,
                     m_imageSizeX,
                     m_imageSizeY,
                     8+M_UNSIGNED,
                     m_bufferAttributes,
                     &m_MilImage);

      // Clear the buffer [CALL TO MIL]
      MbufClear(m_MilImage,M_COLOR_BLACK);
   }
   else
   {
      MbufImport(IMAGE_FILE,M_DEFAULT,M_RESTORE,((MdispQtApp*)qApp)->m_MilSystem,&m_MilImage);

      // Set SizeX and SizeY variable to the size of the buffer [CALL TO MIL]
      if (m_MilImage)
      {
         m_imageSizeX   = MbufInquire(m_MilImage, M_SIZE_X, M_NULL);
         m_imageSizeY   = MbufInquire(m_MilImage, M_SIZE_Y, M_NULL);
         m_NbBands      = MbufInquire(m_MilImage, M_SIZE_BAND, M_NULL);
      }
   }


   UpdateContentSize();

   // If not able to allocate a buffer, do not create a new document
   if(!m_MilImage)
      return false;

   Initialize();

   return true;
}

bool MdispQtView::load( const QString& fn )
   {
   //Import image in buffer [CALL TO MIL]

   MIL_TEXT_CHAR *txt = new MIL_TEXT_CHAR[ fn.length() + 1 ];
#if M_MIL_USE_LINUX
   QByteArray ba = fn.toLocal8Bit();
   const char *tmp = ba.data();
   strncpy( txt, tmp, fn.length() );
#else
   fn.toWCharArray(txt);
#endif
   txt[ fn.length() ] = 0;

   MbufImport(txt,M_DEFAULT,M_RESTORE,((MdispQtApp*)qApp)->m_MilSystem,&m_MilImage);
   delete[] txt;

   // Set SizeX and SizeY variable to the size of the buffer [CALL TO MIL]
   if (m_MilImage)
      {
      Initialize();
      m_imageSizeX = MbufInquire(m_MilImage,M_SIZE_X,M_NULL);
      m_imageSizeY = MbufInquire(m_MilImage,M_SIZE_Y,M_NULL);
      UpdateContentSize();

      m_Filename = QFileInfo(fn).fileName();
      m_FilenameValid = true;
      emit filenameChanged(m_Filename);
      return true;
      }
   else
      {
      return false;
      }
   }


bool MdispQtView::save()
   {
   if ( !m_FilenameValid )
      {
      return saveAs();
      }

   bool SaveStatus;
   QString TempPath;
   long FileFormat = M_MIL;

   // Get extension for file format determination
   TempPath = m_Filename.toUpper();
   //Set the file format to M_MIL when the filepath extension is ".MIM"
   if (TempPath.endsWith(".MIM"))
      FileFormat = M_MIL;
   //Set the file format to M_TIFF when the filepath extension is ".TIF"
   else if (TempPath.endsWith(".TIF"))
      FileFormat = M_TIFF;
   //Set the file format to M_BMP when the filepath extension is ".BMP"
   else if (TempPath.endsWith(".BMP"))
      FileFormat = M_BMP;
   //Set the file format to M_JPEG_LOSSY when the filepath extension is ".JPG"
   else if (TempPath.endsWith(".JPG"))
      FileFormat = M_JPEG_LOSSY;
   //Set the file format to M_JPEG2000_LOSSLESS when the filepath extension is ".JP2"
   else if (TempPath.endsWith(".JP2"))
      FileFormat = M_JPEG2000_LOSSLESS;
   //Set the file format to M_RAW when the filepath extension is ".RAW"
   else if (TempPath.endsWith(".RAW"))
      FileFormat = M_RAW;
   //Set the file format to M_PNG when the filepath extension is ".PNG"
   else if (TempPath.endsWith(".PNG"))
      FileFormat = M_PNG;

   // Halt the grab if the current view has it [CALL TO MIL]
   if((((MdispQtApp*)qApp)->m_pGrabView == this) &&
      (((MdispQtApp*)qApp)->m_isGrabStarted == true))
      MdigHalt(((MdispQtApp*)qApp)->m_MilDigitizer);

   // Save the current buffer [CALL TO MIL]
#if !UNICODE
   QByteArray ba = m_Filename.toLocal8Bit();
   const char *tmp = ba.data();
#else
   const wchar_t *tmp = (const wchar_t *) m_Filename.utf16();
#endif
   MbufExport(tmp, FileFormat, m_MilImage);

   // Verify if save operation was successful [CALL TO MIL]
   SaveStatus = (MappGetError(M_DEFAULT, M_CURRENT,M_NULL) == M_NULL_ERROR);

   // Document has been saved
   if (!((((MdispQtApp*)qApp)->m_pGrabView == this) &&
         (((MdispQtApp*)qApp)->m_isGrabStarted == true)))
      m_Modified = false;

   // Restart the grab if the current view had it [CALL TO MIL]
   if((((MdispQtApp*)qApp)->m_pGrabView == this) &&
     (((MdispQtApp*)qApp)->m_isGrabStarted == true))
     MdigGrabContinuous(((MdispQtApp*)qApp)->m_MilDigitizer, m_MilImage);

   return SaveStatus;
   }

bool MdispQtView::saveAs()
   {
   QString showName = strippedName(m_Filename);
   QString fn = QFileDialog::getSaveFileName(this, tr("Save File"),
                                             tr("%1").arg(showName));

   if ( !fn.isEmpty() )
      {
      m_Filename = fn;
      m_FilenameValid = true;
      emit filenameChanged(strippedName(m_Filename));
      return save();
      }
   else
      {
      return false;
     }
   }

const QString& MdispQtView::filename() const
   {
   return m_Filename;
   }


void MdispQtView::closeEvent( QCloseEvent* e )
   {
   if ( IsModified() )
      {
      switch ( QMessageBox::warning( this, tr("MdispQt Message"),
               tr("Save changes to %1?").arg(m_Filename),
               QMessageBox::Yes | QMessageBox::Default,
               QMessageBox::No,
               QMessageBox::Cancel | QMessageBox::Escape ) )
         {
         case QMessageBox::Yes:
            if ( save() )
               e->accept();
            else
               e->ignore();
            break;
         case QMessageBox::No:
            e->accept();
            break;
         default:
            e->ignore();
            break;
         }
      }
   else
      {
      e->accept();
      }
   }

QSize MdispQtView::sizeHint() const
   {
   return QSize(width(), height());
   }

void MdispQtView::UpdateContentSize()
   {
   int sizeX, sizeY;
  if(m_MilDisplay)
    {
      MIL_DOUBLE ZoomX =1.0, ZoomY =1.0;
      MdispInquire(m_MilDisplay, M_ZOOM_FACTOR_X, &ZoomX);
      MdispInquire(m_MilDisplay, M_ZOOM_FACTOR_Y, &ZoomY);
      if(ZoomX || ZoomY)
         {
         m_currentZoomFactorX = ZoomX;
         m_currentZoomFactorY = ZoomY;
         }
      }
   
   sizeX = int( m_imageSizeX * m_currentZoomFactorX );
   sizeY = int( m_imageSizeY * m_currentZoomFactorY );


   resize( sizeX, sizeY );
   emit sizeChanged((long)(sizeX) , (long)(sizeY));
   }


void MdispQtView::UpdateMousePosition()
   {
   emit mousePositionChanged(m_LastMousePosition.m_DisplayPositionX,
                             m_LastMousePosition.m_DisplayPositionY,
                             m_LastMousePosition.m_BufferPositionX,
                             m_LastMousePosition.m_BufferPositionY);
   // Reset mouse position
   m_LastMousePosition.Set(M_INVALID, M_INVALID, M_INVALID, M_INVALID);
   }

void MdispQtView::customEvent(QEvent* e)
   {
  if (e->type() == QEvent::User +8)
   {

      MilMouseEvent* re = (MilMouseEvent*)e;
      MOUSEPOSITION Pos = re->MousePostion();
      emit mousePositionChanged(Pos.m_DisplayPositionX,
                                Pos.m_DisplayPositionY,
                                Pos.m_BufferPositionX,
                                Pos.m_BufferPositionY);
      // Reset mouse position
      m_LastMousePosition.Set(M_INVALID, M_INVALID, M_INVALID, M_INVALID);
   }
}

void MdispQtView::SelectWindow()
   {
   //Select the buffer from its display object and given window [CALL TO MIL]
   if(m_MilDisplay && m_MilImage)
      {
#if M_MIL_USE_LINUX
      XWindowAttributes attr;
      XColor xcolor,exact;
      XGetWindowAttributes(QX11Info::display(),winId(),&attr);
      // Do not select mouse event, it will be done by the MIL Display
      XSelectInput(QX11Info::display(),winId(), attr.your_event_mask & NON_MOUSE_MASK);
      XSetWindowBackground(QX11Info::display(), winId(), WhitePixel(QX11Info::display(),0));
      m_GC = XCreateGC(QX11Info::display(), winId(), 0, 0);
      XAllocNamedColor(QX11Info::display(),DefaultColormap(QX11Info::display(),0),"magenta", &xcolor,&exact);
      XSetForeground(QX11Info::display(),m_GC, xcolor.pixel);
      XFlush(QX11Info::display());
      XSync(QX11Info::display(),False);
#endif  

      MdispSelectWindow(m_MilDisplay, m_MilImage, (MIL_WINDOW_HANDLE)(m_isWindowed?winId():0));   
      }
   }


#include "moc_mdispqtview.cpp"