/* Autor: Leandro Bernsmuller
Cria uma janela tipica, com capacidade para exibir bitmaps com o DD. */



#include <windows.h>
#include <windowsx.h>
#include <ddraw.h>
#include "..\princip\defs.h"
#include "..\extra\ddutil.h"
#include "..\extra\ddmm.h"
#include "..\cenario\gr.h"
#include "janela.h"



long FAR PASCAL WindowProc ( HWND hWnd, UINT uMsg, 
                             WPARAM wParam, LPARAM lParam );


  
/* Cria janela.
dwMenu - menu a ser usado na janela
szTitulo - titulo da janela
return TRUE - certo / FALSE - erro
**********************************************************/
BOOL CJanela::mCria ( DWORD dwMenu, char* szTitulo, HINSTANCE hInstance )
{
   m_bMinimizou = FALSE;
   m_poBmps = NULL;

   // todos os bitmps da janela devem ser exibidos
   for ( int ncE = 0; ncE < MAX_BMPS; ncE ++ )
      m_bExibir [ ncE ] = TRUE;
   
   WNDCLASS
      stJ;        // classe da janela (tipo)
    
   // registra a janela
   stJ.style = CS_HREDRAW | CS_VREDRAW;
   stJ.lpfnWndProc = ::WindowProc;
   stJ.cbClsExtra = 0;
   stJ.cbWndExtra = 0;
   stJ.hInstance = hInstance;
   stJ.hIcon = LoadIcon ( hInstance, MAKEINTRESOURCE ( IDI_ICON1 ) ); //IDI_APPLICATION );
   stJ.hCursor = LoadCursor ( NULL, IDC_ARROW );
   stJ.hbrBackground = (HBRUSH) ( COLOR_SCROLLBAR + 1 );
   stJ.lpszMenuName = NULL;
   stJ.lpszClassName = STR_NOMEAPL;
   ::RegisterClass ( &stJ );
    
   // cria janela
   m_hWnd = ::CreateWindow (
      STR_NOMEAPL,
      STR_NOMEAPL,
      WS_POPUP | WS_CAPTION | WS_SYSMENU,
      //WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_THICKFRAME,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      128,
      128,
      NULL,
      NULL,
      hInstance,
      NULL );

   // testa se criou janela
   if ( ! m_hWnd )
      return FALSE;

   // configura menu
   HMENU
      hMenu = ::LoadMenu ( hInstance, MAKEINTRESOURCE ( dwMenu ) );
   ::SetMenu ( m_hWnd, hMenu );

   // configura titulo
   ::SetWindowText ( m_hWnd, szTitulo );

   return TRUE;
}



/* destroi janela
**********************************************************/
void CJanela::mDestroi ()
{
   m_poBmps = NULL;
   //::SendMessage ( m_hWnd, WM_CLOSE, 0, 0 );
   m_hWnd = NULL;
}



/* Exibe janela
**********************************************************/
void CJanela::mExibe ( int nCmdShow )
{
   ::ShowWindow ( m_hWnd, nCmdShow );
   ::UpdateWindow ( m_hWnd );
}


/* Define quais bitmaps a janela pode processar
**********************************************************/
void CJanela::mIncluiBmps ( CGr& oBmps )
{
   m_poBmps = &oBmps;
}



/* Altera o tamanho e posicao da janela.
nComo - define como posicionar a janela
        0 - conforme os demais parametros dados
            nXI, nYI - posicao do canto superior esquerdo da janela
            nX, nY - largura e altura
        1 - no centro da tela
            nX, nY - porcentagem de ocupacao da janela em cada eixo (xy)
        2 - centrado em X (horizontalmente)
            nYI - posicao em Y
            nX - porcentagem de ocupacao da janela no eixo X.
            nY - porcentagem de ocupacao da janela no eixo Y.
**********************************************************/
void CJanela::mAlteraTamanhoPosicaoJanela ( int nComo, int nXI, int nYI, int nX, int nY )
{
   switch ( nComo ) {

      case 0:
         break;
      
      case 1:
         {
            // define tamanho e posicao da janela
            // (se janela no meio da tela)
            int
               // resolucao de video
               nVidX = ::GetSystemMetrics ( SM_CXSCREEN ),
               nVidY = ::GetSystemMetrics ( SM_CYSCREEN );

            // redefine largura e altura da janela, proporcionalmente
            nX = (int) ( (float) nVidX * ( (float) nX / 100 ) ),
            nY = (int) ( (float) nVidY * ( (float) nY / 100 ) ),
            // redefine posicao
            nXI = ( nVidX - nX ) / 2,
            nYI = ( nVidY - nY ) / 2;
            nYI -= 25;   // extra pelos menus,...?
         }
         break;

      case 2:
         {
            // define tamanho e posicao em X
            // (se janela no meio da tela)
            int
               // resolucao de video
               nVidX = ::GetSystemMetrics ( SM_CXSCREEN ),
               nVidY = ::GetSystemMetrics ( SM_CYSCREEN );

            // redefine largura e altura da janela, proporcionalmente
            nX = (int) ( (float) nVidX * ( (float) nX / 100 ) );
            nY = (int) ( (float) nVidY * ( (float) nY / 100 ) );
            // redefine posicao
            nXI = ( nVidX - nX ) / 2;
         }
         break;
   }

   RECT
      stRect;

   ::SetRect ( &stRect, 0, 0, nX, nY );

   ::AdjustWindowRectEx ( &stRect, 
                          ::GetWindowLong ( m_hWnd, GWL_STYLE ),
                          ::GetMenu ( m_hWnd ) != NULL,
                          ::GetWindowLong ( m_hWnd, GWL_EXSTYLE ) );
   ::SetWindowPos ( m_hWnd, NULL, nXI, nYI,
                    stRect.right - stRect.left,
                    stRect.bottom - stRect.top,
                    SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME );
}



/* Redesenha bitmaps
**********************************************************/
void CJanela::mRedesenha ()
{
   if ( m_poBmps == NULL )
      return;

   if ( m_poBmps->m_nDisp != DirectDrawDeviceFromWindow ( m_hWnd, NULL, NULL ) )
      m_poBmps->mCria ( m_hWnd );

   // recarrega bitmaps
   m_poBmps->mRecarregaBmps ();

   // exibe os bitmaps
   for ( int ncE = 0; ncE < MAX_BMPS; ncE ++ )
      // se deve exibir
      if ( m_bExibir [ ncE ] )
         // faz
         m_poBmps->mExibe ( ncE );
}



/* Trata mensagens do windows
return TRUE - certo / FALSE - erro
**********************************************************/
BOOL CJanela::mTrataMensagensWindows ( HWND& hWnd, UINT& uMsg,
                                       WPARAM& wParam, LPARAM& lParam )
{
   // classifica mensagens
   switch ( uMsg ) {

      case WM_DISPLAYCHANGE:         // se alterou o video
         mWinAlteraVideo ( hWnd, uMsg, wParam, lParam );
         break;

      case WM_PALETTECHANGED:
         if ( (HWND) wParam == hWnd )
            break;
      
      case WM_QUERYNEWPALETTE:
         // reconfigura palette
         //if ( m_poBmps->m_lpDDPal )
            //m_poBmps->m_lpDDSOnde->SetPalette ( m_poBmps->m_lpDDPal );
         // recarrega bitmaps, porque palette mudou
         //m_poBmps->mRecarregaBmps ();
         break;

      case WM_ACTIVATE:
         mWinAtivo ( hWnd, uMsg, wParam, lParam );
         break;

      case WM_DESTROY:
         mDestroi ();
         break;

      case WM_GETMINMAXINFO:
         ( (MINMAXINFO*) lParam ) -> ptMinTrackSize.x = MINIMOJANX;
         ( (MINMAXINFO*) lParam ) -> ptMinTrackSize.y = MINIMOJANY;
         return 0;

      case WM_KEYDOWN:
         switch ( wParam ) {
         
            case VK_F12:
               PostMessage ( hWnd, WM_DESTROY, 0, 0 );
               break;
         }
         break;
   }

   return TRUE;
}



/* Executado se a mensagem de video foi alterado for
gerada pelo Windows
**********************************************************/
void CJanela::mWinAlteraVideo ( HWND& hWnd, UINT& uMsg,
                                       WPARAM& wParam, LPARAM& lParam )
{
   // se estah minimizado sai
   if ( m_bMinimizou )
      return;      

   // reconfigura, para isso requer DD
   LPDIRECTDRAW
      lpDD;
   if ( ::DirectDrawCreate ( NULL, &lpDD, NULL ) )
      return;
   if ( lpDD->SetCooperativeLevel ( hWnd, DDSCL_NORMAL ) ) {
      lpDD->Release();
      return;
   }
         
   // coleta dados sobre configuracao
   DDSURFACEDESC
      stDdsd;
   memset ( &stDdsd, 0, sizeof ( stDdsd ) );
   stDdsd.dwSize = sizeof ( stDdsd );
   stDdsd.dwFlags = DDSD_CAPS;
   stDdsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
   LPDIRECTDRAWSURFACE
      lpDDS;
   if ( lpDD->CreateSurface ( &stDdsd, &lpDDS, NULL ) ==
                                                  DDERR_NOEXCLUSIVEMODE) {
      lpDD->Release();
      return;
   }

   // se jah terminou com sucesso
   lpDDS->Release();
   lpDD->Release();
   
   mRedesenha ();
}



/* Executado se a mensagem tamanho de jabela alterada for
gerada pelo Windows
**********************************************************/
void CJanela::mWinAlteraTamanhoJanela ( HWND& hWnd, UINT& uMsg,
                                       WPARAM& wParam, LPARAM& lParam )
{
   int
      nResX = LOWORD ( lParam ),
      nResY = HIWORD ( lParam );

   // reconfigura D3D, se mensagem eh de alteracao do tamanho
   if ( nResX && nResY ) {

      m_bMinimizou = FALSE;
      mRedesenha ();
   }
   else     // se mensagem informa minimizacao
      m_bMinimizou = TRUE;
}



/* Executado se a mensagem de aplicativo ativo
for gerada pelo Windows
**********************************************************/
void CJanela::mWinAtivo ( HWND& hWnd, UINT& uMsg,
                                       WPARAM& wParam, LPARAM& lParam )
{
   mRedesenha ();
}
