// Listing 9.11. Przykład pliku nagłówkowego naszej własnej klasy widoku
//
class COpenCVTestView : public CWindowImpl<COpenCVTestView> {
public:
  DECLARE_WND_CLASS(NULL)
  bool OpenFile(std::string file);
  void _copyImage();
  BOOL PreTranslateMessage(MSG* pMsg);
  BEGIN_MSG_MAP(COpenCVTestView)
    MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
    MESSAGE_HANDLER(WM_PAINT, OnPaint)
    MESSAGE_HANDLER(WM_TIMER, OnTimer)
  END_MSG_MAP()
// prototypy procedu obsługi (w razie potrzeby usunąć odpowiednie komentarze):
//  LRESULT MessageHandler(
//    UINT    /*uMsg*/,
//    WPARAM  /*wParam*/,
//    LPARAM  /*lParam*/,
//    BOOL&   /*bHandled*/
//  );
//  LRESULT CommandHandler(
//    WORD    /*wNotifyCode*/,
//    WORD    /*wID*/,
//    HWND    /*hWndCtl*/,
//    BOOL&   /*bHandled*/
//  );
//  LRESULT NotifyHandler(
//    int     /*idCtrl*/,
//    LPNMHDR /*pnmh*/,
//    BOOL&   /*bHandled*/
//  );
  LRESULT OnPaint(
    UINT    /*uMsg*/,
    WPARAM  /*wParam*/,
    LPARAM  /*lParam*/,
    BOOL&   /*bHandled*/
  );
  LRESULT OnTimer(
    UINT    /*uMsg*/,
    WPARAM  /*wParam*/,
   LPARAM  /*lParam*/,
    BOOL&   /*bHandled*/
  );
  LRESULT OnEraseBkgnd(
    UINT    /*uMsg*/,
    WPARAM  /*wParam*/,
    LPARAM  /*lParam*/,
    BOOL&   /*bHandled*/
  );
private:
  cv::VideoCapture m_cap;
  cv::Mat          m_cv_img;
  RGBTRIPLE*       m_bitmapBits;
};

LRESULT CMainFrame::OnFileOpen(
      WORD /*wNotifyCode*/,
      WORD /*wID*/,
      HWND /*hWndCtl*/,
      BOOL& /*bHandled*/
  ) {
  WTL::CFileDialog dlg(TRUE);
  if (IDOK == dlg.DoModal(m_hWnd)) {
    m_view.OpenFile(dlg.m_szFileName);
  }
  return 0;
}

bool COpenCVTestView::OpenFile(std::string file) {
  if( !m_cap.open( file ) ) return false;
  //  jeśli otworzyliśmy plik, przygotowujemy wszystko, co potrzeba:
  //
  m_cap.read( m_cv_img );
  //  można tu utworzyć DIBSection, ale alokujemy pamięć tylko dla surowych bitów
  //
  m_bitmapBits = new RGBTRIPLE[m_cv_img.cols * m_cv_img.rows];
  _copyImage();
  SetTimer(0, 1000.0f / m_cap.get( cv::CAP_PROP_FPS ) );
  return true;
}

void COpenCVTestView::_copyImage() {
  // kopiuje dane obrazu do mapy bitowej
  //
  cv::Mat cv_header_to_qt_image(
  cv::Size(
  m_cv_img.cols,
  m_cv_img.rows
  ),
  CV_8UC3,
  m_bitmapBits
  );
  cv::cvtColor( m_cv_img, cv_header_to_qt_image, cv::BGR2RGB );
}

LRESULT COpenCVTestView::OnPaint(
  UINT
  /* uMsg
  */,
  WPARAM /* wParam
  */,
  LPARAM /* lParam
  */,
  BOOL& /* bHandled */
  ) {
  CPaintDC dc(m_hWnd);
  WTL::CRect rect;
  GetClientRect(&rect);
  if( m_cap.isOpened() ) {
  BITMAPINFO bmi = {0};
  bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
  bmi.bmiHeader.biCompression = BI_RGB;
  bmi.bmiHeader.biWidth
  = m_cv_img.cols;
  //  domyślnie mapy bitowe są ustawiane do góry nogami, więc należy ustawić ujemną wysokość
  //
  bmi.bmiHeader.biHeight = m_cv_img.rows * -1;
  bmi.bmiHeader.biPlanes = 1;
  bmi.bmiHeader.biBitCount = 24;
  dc.StretchDIBits(
  0,
  rect.Width(),
  0,
  bmi.bmiHeader.biWidth,
  m_bitmapBits,
  &bmi,
  DIB_RGB_COLORS,
  SRCCOPY
  // 32, jeśli używana jest struktura RGBQUAD
  0,
  rect.Height(),
  0,
  abs(bmi.bmiHeader.biHeight),
  Working with Windows
  |
  245);
  } else {
  dc.FillRect(rect, COLOR_WINDOW);
  }
  return 0;
}

RESULT COpenCVTestView::OnTimer(
  UINT
  /* uMsg
  */,
  WPARAM /* wParam
  */,
  LPARAM /* lParam
  */,
  BOOL& /* bHandled */
  ) {
  // nie ma nic do zrobienia, jeśli obiekt przechwytywania nie jest otwarty
  //
  if( !m_cap.isOpened() ) return 0;
  m_cap.read( m_cv_img );
  _copyImage();
  Invalidate();
  return 0;
 }

LRESULT COpenCVTestView::OnEraseBkgnd(
  UINT
  /* uMsg
  */,
  WPARAM /* wParam
  */,
  LPARAM /* lParam
  */,
  BOOL& /* bHandled */
  ) {
  // ponieważ okno w całości rysujemy w procedurze obsługi OnPaint, pozostawiamy pustą procedurę obsługi tła
  return 0;
}
