On 11/3/05, James Liggett <[EMAIL PROTECTED]> wrote:
> On Tue, 2005-11-01 at 23:34 -0200, Matheus Izvekov wrote:
> > yes, i develop it in a windows xp environment.
> > what kind of stack problem do you think might be related?
> > i think its unlikely that its because of stack overflow, it uses very
> > little stack, but ill investigate.
>
> If it works on Windows, then the stack problems I'm referring to aren't
> in your code but in wine. I'll have some free time for the next few
> days, so send your code and I'll try and see if I can help. By the way,
> does this program do?
>
> James
>

Its used for generating a 2 dimension float array dumped on a file.
You start with a bitmap and assign a float value for each color. its
still WIP and a bit messed up, but i believe it will be enough for the
purpose of testing.

Beware that this program does not use the C runtime. The entry point
is "WinMainStartup" in gui.c.
/*
	Copyright 2005 Matheus Izvekov
*/

#define UNICODE

#include <windows.h>
#include <commctrl.h>
#include "imageviewer.h"

const WCHAR g_szClassName[] = L"myWindowClass";

enum
{
  IDT_TIMER1 = 10001,
  ID_FILE_NEW,
  ID_FILE_OPEN,
  ID_FILE_SAVE,
  ID_FILE_CLOSE,
  ID_FILE_EXIT,
  ID_FILE_EXPORT,
  ID_FILE_SAVE_AS,
  ID_VIEW_ORIG,
  ID_VIEW_FIT,
  ID_VIEW_STRETCH,
  ID_HELP_ABOUT,
};

#define CVR_FILE_HEADER_MAGIC 'FRVC'

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);

typedef struct 
{
	BYTE b;
	BYTE g;
	BYTE r;
	BYTE pad;
} sBGR;
typedef sBGR *pBGR;

typedef struct
{
  DWORD magic;
  DWORD nx;
  DWORD ny;
  DWORD tsize;
} CVRfileHeader;

typedef struct
{
  sBGR c;
  float v;
} TTableItem;
typedef struct
{
  TTableItem *t;
  DWORD size;
} TTable;

typedef struct
{
  DWORD nx, ny;
  TTable table;
  pBGR image;
} CVR;

typedef struct
{
  HWND hwndToolTip, hwndList, hwndStatic, hwndToolbar, hwndStatusbar;
  HANDLE hImage, hImageInv;
  HMENU hMenu, hMenuArq, hMenuView, hMenuHelp;
  WCHAR szFileName[MAX_PATH];
  WCHAR szTitle[MAX_PATH];
  WCHAR szExportFileName[MAX_PATH];
  BOOLEAN bModified;
  CVR *cvr;
} MainWD;

TTable* GetColorTable(pBGR img, DWORD nx, DWORD ny);

/*
  Gera um campo de velocidades
*/
float* GenerateField(CVR *cvr, int *size);

HANDLE hConsole = NULL;
void UpdateTableList(HWND hwnd, TTable *t);
HBITMAP GetBitmapFromColorArray(pBGR buf, int nx, int ny);
pBGR GetColorArray(HBITMAP hBmp, DWORD *nx, DWORD *ny);
pBGR InvertColor(pBGR img, DWORD nx, DWORD ny, sBGR color);
INT GetColorIndexFromTable(TTable table, sBGR color);

void gui_update(HWND hwnd, MainWD *wd);
void gui_update_title(HWND hwnd, MainWD *wd);
BOOLEAN gui_export(LPWSTR file, CVR *cvr);

BOOLEAN cvr_save(LPWSTR file, CVR *cvr);
CVR* cvr_new(HBITMAP hBMP);
CVR* cvr_open(LPWSTR file);
void cvr_free(CVR **cvr);

/*
void PRINT(char *FMT, ...)
{
        DWORD TEMP; va_list ARG; char BUF[512];

        va_start(ARG, FMT); vsprintf(BUF, FMT, ARG); va_end(ARG);

        WriteConsole(hConsole, BUF, (DWORD)strlen(BUF), &TEMP, 0);
}
*/

HANDLE ProcHeap;

int _fltused = 1;

void ErrorMsg(HWND hwnd, WCHAR *error)
{
  WCHAR szBuf[80];
  LPVOID lpMsgBuf;
  DWORD dw = GetLastError(); 

  if (dw != 0)
  {
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );

    wsprintfW(szBuf, L"%s\nErro %d: %s", error, dw, lpMsgBuf);
    MessageBox(hwnd, szBuf, L"Erro!", MB_ICONEXCLAMATION | MB_OK);
    LocalFree(lpMsgBuf);
  } else
    MessageBox(hwnd, error, L"Erro!", MB_ICONEXCLAMATION | MB_OK);
}

BOOL simple_mode = FALSE;
WCHAR bmpName[MAX_PATH], binName[MAX_PATH];

WINAPI WinMainStartup(void)
{
    WNDCLASSEX wc;
    MSG Msg;
    INITCOMMONCONTROLSEX InitCtrls;
    HWND hwndWin;
    int nArgs, i;
    HINSTANCE hInstance;
    LPWSTR lpCmdLine;
    STARTUPINFOW si;

    GetStartupInfoW(&si);
    ProcHeap = GetProcessHeap();
    hInstance = GetModuleHandle(NULL);
    lpCmdLine = GetCommandLineW();
    hConsole = GetStdHandle((DWORD)-11);

    simple_mode = FALSE; bmpName[0] = binName[0] = '\0';

    if (lpCmdLine == NULL) ErrorMsg(NULL, L"lpCmdLine == NULL");
    else
    {
      LPWSTR *szArglist;

      szArglist = CommandLineToArgvW(lpCmdLine, &nArgs);
      if (szArglist == NULL) ErrorMsg(NULL, L"szArglist == NULL");
      else
      {
        for(i=0;i<nArgs;i++)
        {
          if (szArglist[i] == NULL) ErrorMsg(NULL, L"szArglist[i] == NULL");
          else
          {
            if (szArglist[i][0] == '-' && szArglist[i][1] == '-')
            {
              if (lstrcmpW(szArglist[i]+2, L"simple") == 0) simple_mode = TRUE;
              else if (lstrcmpW(szArglist[i]+2, L"console") == 0) AllocConsole();
            } else
            {
              LPWSTR ext = NULL, tmp;
              lstrcpyn(bmpName, szArglist[i], MAX_PATH);
              lstrcpyn(binName, bmpName, MAX_PATH);
              for(tmp=binName;*tmp!='\0';tmp++) if (*tmp=='.') ext = tmp;
              if (ext == NULL) ext = tmp;
              lstrcpy(ext, L".bin");
            }
          }
        }
        LocalFree(szArglist);
      }
    }

    InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
    InitCtrls.dwICC = ICC_LISTVIEW_CLASSES | ICC_BAR_CLASSES;
    if (InitCommonControlsEx(&InitCtrls) == FALSE)
      ErrorMsg(NULL, L"Não foi possivel inicializar as classes dos controles TOOLBAR e LISTVIEW");

    if (InitImView(hInstance) == FALSE)
      ErrorMsg(NULL, L"Não foi possivel inicializar a classe do controle IMVIEW");

    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = sizeof(MainWD*);
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&wc))
    {
        ErrorMsg(NULL, L"Não foi possivel registrar a classe da janela principal");
        return 0;
    }

    if ((hwndWin = CreateWindowEx(
        0,
        g_szClassName,
        L"",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 1000, 600,
        NULL, NULL, hInstance, NULL)) == NULL)
    {
        ErrorMsg(NULL, L"Não foi possível criar a janela principal");
        return 0;
    }

    ShowWindow(hwndWin, si.wShowWindow);
    UpdateWindow(hwndWin);

    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return (DWORD)Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    MainWD *wd;
    HINSTANCE hInstance;

    wd = (MainWD*)GetWindowLong(hwnd, 0);
    hInstance = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);

    switch(msg)
    {
        case WM_CREATE:
          {
            wd = GlobalAlloc(GMEM_FIXED, sizeof(MainWD));
            SetWindowLong(hwnd, 0, (LONG)wd);

            if ((wd->hwndToolTip = CreateWindowEx(0, TOOLTIPS_CLASSW, NULL,
                                  WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
                                  CW_USEDEFAULT, CW_USEDEFAULT,
                                  CW_USEDEFAULT, CW_USEDEFAULT,
                                  hwnd, NULL, NULL,
                                  NULL)) != NULL)
            {
              SetWindowPos(wd->hwndToolTip, HWND_TOPMOST,0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
            } else
              ErrorMsg(hwnd, L"ToolTip Creation Failed!");

            if ((wd->hMenu = CreateMenu()) != NULL)
            {
              if (simple_mode == FALSE) if ((wd->hMenuArq = CreatePopupMenu()) != NULL)
              {
                AppendMenu(wd->hMenuArq, MF_STRING, ID_FILE_NEW, L"&Novo");
                AppendMenu(wd->hMenuArq, MF_STRING, ID_FILE_OPEN, L"A&brir");
                AppendMenu(wd->hMenuArq, MF_STRING, ID_FILE_CLOSE, L"&Fechar");
                AppendMenu(wd->hMenuArq, MF_SEPARATOR, 0, NULL);
                AppendMenu(wd->hMenuArq, MF_STRING, ID_FILE_SAVE, L"&Salvar");
                AppendMenu(wd->hMenuArq, MF_STRING, ID_FILE_SAVE_AS, L"Salvar &como...");
                AppendMenu(wd->hMenuArq, MF_STRING, ID_FILE_EXPORT, L"&Exportar");
                AppendMenu(wd->hMenuArq, MF_SEPARATOR, 0, NULL);
                AppendMenu(wd->hMenuArq, MF_STRING, ID_FILE_EXIT, L"Sai&r");

                AppendMenu(wd->hMenu, MF_STRING | MF_POPUP, (UINT_PTR)wd->hMenuArq, L"&Arquivo");
              } else 
                ErrorMsg(hwnd, L"MenuArq Creation Failed!");

              if ((wd->hMenuView = CreatePopupMenu()) != NULL)
              {
                AppendMenu(wd->hMenuView, MF_STRING, ID_VIEW_ORIG, L"&Tamanho Original");
                AppendMenu(wd->hMenuView, MF_STRING, ID_VIEW_FIT, L"F&it");
                AppendMenu(wd->hMenuView, MF_STRING, ID_VIEW_STRETCH, L"Stretc&h Total");

                AppendMenu(wd->hMenu, MF_STRING | MF_POPUP, (UINT_PTR)wd->hMenuView, L"&Visualização");
              } else 
                ErrorMsg(hwnd, L"MenuView Creation Failed!");

              if ((wd->hMenuHelp = CreatePopupMenu()) != NULL)
              {
                AppendMenu(wd->hMenuHelp, MF_STRING, ID_HELP_ABOUT, L"&About");

                AppendMenu(wd->hMenu, MF_STRING | MF_POPUP, (UINT_PTR)wd->hMenuHelp, L"A&juda");
              } else 
                ErrorMsg(hwnd, L"MenuHelp Creation Failed!");
              
              SetMenu(hwnd, wd->hMenu);
            } else 
              ErrorMsg(hwnd, L"Menu Creation Failed!");

            if ((wd->hwndStatic = CreateWindowEx(0, IMVIEWCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, 
                                                 0, 0, 0, 0, hwnd, NULL, hInstance, NULL)) != NULL)
            {
              SendMessage(hwnd, WM_COMMAND, ID_VIEW_FIT, 0);
            } else 
              ErrorMsg(hwnd, L"Static Creation Failed!");
             
            if (simple_mode == FALSE) if ((wd->hwndToolbar = CreateWindowEx(0, 
                    TOOLBARCLASSNAMEW, NULL, 
                    WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS | TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | CCS_NODIVIDER, 
                    0, 0, 0, 0, hwnd, NULL, hInstance, NULL)) != NULL)
            {
              TBADDBITMAP tbab;
              BYTE bstyle = BTNS_BUTTON | BTNS_SHOWTEXT;
              TBBUTTON tbb[] =
              {
                  {STD_FILENEW,   ID_FILE_NEW,    TBSTATE_ENABLED, bstyle, 0, 0, 0, (INT_PTR)L"Novo"},
                  {STD_FILEOPEN,  ID_FILE_OPEN,   TBSTATE_ENABLED, bstyle, 0, 0, 0, (INT_PTR)L"Abrir"},
                  {STD_FILESAVE,  ID_FILE_SAVE,   TBSTATE_ENABLED, bstyle, 0, 0, 0, (INT_PTR)L"Salvar"},
                  {0,             ID_FILE_EXPORT, TBSTATE_ENABLED, bstyle, 0, 0, 0, (INT_PTR)L"Exportar"},
              };

              SendMessage(wd->hwndToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_MIXEDBUTTONS);
              SendMessage(wd->hwndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
              tbab.hInst = HINST_COMMCTRL;
              tbab.nID = IDB_STD_SMALL_COLOR;
              SendMessage(wd->hwndToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
              SendMessage(wd->hwndToolbar, TB_ADDBUTTONSW, sizeof(tbb)/sizeof(TBBUTTON), (LPARAM)&tbb);
              SendMessage(wd->hwndToolbar, TB_AUTOSIZE, 0, 0);
            } else 
              ErrorMsg(hwnd, L"Toolbar Creation Failed!");

            if ((wd->hwndStatusbar = CreateWindowEx(0, 
                    STATUSCLASSNAMEW, NULL, 
                    WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 
                    0, 0, 0, 0, hwnd, NULL, hInstance, NULL)) != NULL)
            {
              int statwidths[] = {150, 250, -1};

              SendMessage(wd->hwndStatusbar, SB_SETPARTS, sizeof(statwidths)/sizeof(int), (LPARAM)statwidths);
              SendMessage(wd->hwndStatusbar, SB_SETTEXTW, 2, (LPARAM)L"Selecione um item na lista, clique novamente e altere o valor");
            } else 
              ErrorMsg(hwnd, L"Statusbar Creation Failed!");

            if ((wd->hwndList = CreateWindowEx(
                0,
                WC_LISTVIEWW,
                L"ListView",
                WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | LVS_OWNERDATA | LVS_EDITLABELS 
                        | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER,
                0, 0, 0, 0,
                hwnd, NULL, hInstance, NULL)) != NULL)
            {
              LVCOLUMN col;

              ListView_SetExtendedListViewStyle(wd->hwndList, LVS_EX_SUBITEMIMAGES | LVS_EX_FLATSB);
              FlatSB_EnableScrollBar(wd->hwndList, SB_BOTH, ESB_ENABLE_BOTH);

              col.mask = LVCF_WIDTH | LVCF_SUBITEM;
              col.cx = 100;
              col.iSubItem = 0;
              SendMessage(wd->hwndList, (UINT)LVM_INSERTCOLUMNW, (WPARAM)(int)0, (LPARAM)(LPLVCOLUMN)&col);
            } else 
              ErrorMsg(hwnd, L"List Creation Failed!");

            wd->cvr = NULL;
            wd->bModified = FALSE;
            wd->szFileName[0] = '\0';
            wd->szTitle[0] = '\0';
            wd->szExportFileName[0] = '\0';

            gui_update_title(hwnd, wd);

            if (simple_mode == TRUE)
            {
              HANDLE hImage = LoadImage(NULL, bmpName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

              if (hImage == NULL)
              {
                ErrorMsg(hwnd, L"Arquivo de Imagem inválido");
                DestroyWindow(hwnd);
              } else
              {
                wd->cvr = cvr_new(hImage);
                wd->hImage = hImage;
                wd->bModified = TRUE;
                lstrcpyn(wd->szTitle, bmpName, MAX_PATH);
                gui_update(hwnd, wd);
              }
            }
          }
          break;

        case WM_CLOSE:
            if (simple_mode == TRUE)
            {
              if (gui_export(binName, wd->cvr) == FALSE)
                ErrorMsg(hwnd, L"Arquivo não pode ser exportado");
              DestroyWindow(hwnd);
            } else
              if (SendMessage(hwnd, WM_COMMAND, ID_FILE_CLOSE, 0) == TRUE)
              {
                DestroyWindow(hwnd);
              }
        break;

        case WM_DESTROY:
            GlobalFree(wd);
            PostQuitMessage(0);
        break;

        case WM_SIZE:
          {
            int sbheight;
            RECT tbrect, sbrect, ssrect, lvrect, mwrect;
            SendMessage(wd->hwndStatusbar, WM_SIZE, 0, 0);
            SendMessage(wd->hwndToolbar, WM_SIZE, 0, 0);

            GetClientRect(hwnd, &mwrect);
            GetClientRect(wd->hwndToolbar, &tbrect);
            if (simple_mode) memset(&tbrect, 0, sizeof(RECT));
            GetClientRect(wd->hwndStatusbar, &sbrect);

            tbrect.right = mwrect.right;

            sbheight = sbrect.bottom - sbrect.top;
            sbrect.bottom = mwrect.bottom;
            sbrect.top = mwrect.bottom - sbheight;

            lvrect.left = mwrect.left + GetSystemMetrics(SM_CXBORDER);
            lvrect.top = tbrect.bottom;// + GetSystemMetrics(SM_CYBORDER);
            lvrect.right = lvrect.left + 116 - GetSystemMetrics(SM_CXBORDER);
            lvrect.bottom = sbrect.top - GetSystemMetrics(SM_CYBORDER);

            ssrect.left = lvrect.right + GetSystemMetrics(SM_CXBORDER);
            ssrect.top = tbrect.bottom;// + GetSystemMetrics(SM_CYBORDER);
            ssrect.right = mwrect.right - GetSystemMetrics(SM_CXBORDER);
            ssrect.bottom = sbrect.top - GetSystemMetrics(SM_CYBORDER);

            MoveWindow(wd->hwndList, lvrect.left, lvrect.top, lvrect.right - lvrect.left, lvrect.bottom - lvrect.top, TRUE);
            MoveWindow(wd->hwndStatic, ssrect.left, ssrect.top, ssrect.right - ssrect.left, ssrect.bottom - ssrect.top, TRUE);
            //MoveWindow(wd->hwndRebar, tbrect.left, tbrect.top, tbrect.right - tbrect.left, tbrect.bottom - tbrect.top, TRUE);
          } break;
        case WM_TIMER:
          {
            if (wParam == IDT_TIMER1)
            {
              int layer = SendMessage(wd->hwndStatic, IVM_GETLAYER, 0, 0);
              if (layer == 0)
                SendMessage(wd->hwndStatic, IVM_SETLAYER, 1, 0);
              else
                SendMessage(wd->hwndStatic, IVM_SETLAYER, 0, 0);
            }
          } break;
        case WM_NOTIFY:
          {
              NMHDR *pnmh = (NMHDR *)lParam;

              if (pnmh->hwndFrom == wd->hwndStatic)
              {
                switch(pnmh->code)
                {
                  case NM_RCLICK:
                    {
                      LPNMMOUSE lpnmmouse;
                      POINT pt;

                      lpnmmouse = (LPNMMOUSE)lParam;

                      pt = lpnmmouse->pt;
                      MapWindowPoints(lpnmmouse->hdr.hwndFrom, HWND_DESKTOP, (LPPOINT)&pt, 1);
                      TrackPopupMenuEx(wd->hMenuView, TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL, pt.x, pt.y, hwnd, NULL); 
                    } break;
                  case WM_MOUSEMOVE:
                  case WM_LBUTTONDOWN:
                    {
                      INT i;
                      LPNMIVPOS ivp = (LPNMIVPOS)lParam;
                      sBGR color;

                      if (wd->cvr != NULL)
                      {
                        if ((ivp->x < wd->cvr->nx)&&(ivp->y < wd->cvr->ny))
                        {
                          color = wd->cvr->image[ivp->x + (ivp->y)*(wd->cvr->nx)];
                          i = GetColorIndexFromTable(wd->cvr->table, color);
                        } else i = -1;

                        if (i != -1)
                        {
                          switch(pnmh->code)
                          {
                            case WM_LBUTTONDOWN:
                              {
                                SetFocus(wd->hwndList);
                                ListView_EditLabel( wd->hwndList, i );
                              } break;
                            case WM_MOUSEMOVE:
                              {
                                WCHAR tmp[65];
                                wsprintfW(tmp, L"\tR:%d G:%d B:%d", color.r, color.g, color.b);
                                SendMessage(wd->hwndStatusbar, SB_SETTEXTW, 0, (LPARAM)tmp);
                              } break;
                          }
                        }
                      }
                    } break;
                }
              } else
              if (pnmh->hwndFrom == wd->hwndList)
              {
                NMLVDISPINFO *pnmv = (NMLVDISPINFO*)lParam;
                int i = pnmv->item.iItem;
                
                if (wd->cvr == NULL) break;

                switch(pnmh->code)
                {
                  case NM_CLICK:
                    {
                      LPNMITEMACTIVATE lpnmitem = (LPNMITEMACTIVATE)lParam;
                      ListView_EditLabel( wd->hwndList, lpnmitem->iItem );
                    } break;
                  case LVN_ITEMCHANGED:
                    {
                      LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
                      if (pnmv->uNewState & LVIS_SELECTED)
                      { /* Bota pra piscar e Atualiza a status bar com a cor selecionada na lista */
                          pBGR buf;
                          sBGR color;
                          WCHAR tmp[65];
                          if (wd->hImageInv != NULL) DeleteObject(wd->hImageInv);
                          color = wd->cvr->table.t[pnmv->iItem].c;
                          wsprintfW(tmp, L"\tR:%d G:%d B:%d", color.r, color.g, color.b);
                          SendMessage(wd->hwndStatusbar, SB_SETTEXTW, 0, (LPARAM)tmp);
                          buf = InvertColor(wd->cvr->image, wd->cvr->nx, wd->cvr->ny, color);
                          wd->hImageInv = GetBitmapFromColorArray(buf, wd->cvr->nx, wd->cvr->ny);
                          HeapFree(ProcHeap, 0 , buf);
                          SendMessage(wd->hwndStatic, IVM_SETPICTURE, (WPARAM)wd->hImageInv, 1);
                          KillTimer(hwnd, IDT_TIMER1);
                          SetTimer(hwnd, IDT_TIMER1, 500, (TIMERPROC) NULL);
                          SendMessage(wd->hwndStatic, IVM_SETLAYER, 1, 0);
                      }
                      return FALSE;
                    } break;

                  case LVN_GETDISPINFO:
                    {
                      if (pnmv->item.mask & LVIF_STATE) pnmv->item.state = 0;
                      if (pnmv->item.mask & LVIF_IMAGE) pnmv->item.iImage = i;
                      if (pnmv->item.mask & LVIF_TEXT) lstrcpyW(pnmv->item.pszText, L"todo");
                        //swprintf(pnmv->item.pszText, L"%5.4f", wd->cvr->table.t[i].v);
                    } break;
                 /* case LVN_BEGINLABELEDIT:
                    {
                      HWND hEdit;
                      DWORD id;

                      hEdit = ListView_GetEditControl(wd->hwndList);
                      id = GetWindowLong(hEdit, GWL_ID);
                      //PRINT("%d\n", id);
                      SendMessage(wd->hwndList, WM_NOTIFY, (WPARAM)(LOWORD(id) | HIWORD(EN_CHANGE)), (LPARAM)hEdit);
                      SendMessage(hEdit, EM_SETMODIFY, (WPARAM)TRUE, (LPARAM)0);

                      return FALSE;
                    } break; */
                  case LVN_ENDLABELEDIT:
                    {
                      if (pnmv->item.pszText == NULL) return FALSE;
                      if (/*swscanf(pnmv->item.pszText, L"%f", &(wd->cvr->table.t[i].v)) == 1*/0)
                      {
                        if (wd->bModified != TRUE)
                        {
                          wd->bModified = TRUE;
                          gui_update_title(hwnd, wd);
                        }
                        PostMessage(wd->hwndList, LVM_EDITLABELW, (WPARAM)i+1, (LPARAM)0);
                        return TRUE;
                      } else
                      {
                        //PostMessage(wd->hwndList, LVM_EDITLABELW, (WPARAM)i, (LPARAM)0);
                        return FALSE;
                      }
                    } break;
                }
              } else
              if (pnmh->hwndFrom == wd->hwndToolbar)
              {
                switch(pnmh->code)
                {
                  case TBN_GETINFOTIPW:
                    {
                      LPNMTBGETINFOTIP lptbgit; 

                      lptbgit = (LPNMTBGETINFOTIP)lParam; 

                      switch (lptbgit->iItem)
			                {
                        case ID_FILE_NEW: lstrcpyn(lptbgit->pszText, L"Criar novo arquivo de projeto", lptbgit->cchTextMax); break;
                        case ID_FILE_OPEN: lstrcpyn(lptbgit->pszText, L"Abrir novo arquivo de projeto", lptbgit->cchTextMax); break;
                        case ID_FILE_SAVE: lstrcpyn(lptbgit->pszText, L"Salvar arquivo de projeto", lptbgit->cchTextMax); break;
                        case ID_FILE_EXPORT: lstrcpyn(lptbgit->pszText, L"Exportar para formato binário", lptbgit->cchTextMax); break;
                      }
                    } break;
                }
              }
          } break;
        case WM_COMMAND:
          switch(LOWORD(wParam))
         { 
            case ID_FILE_NEW:
              {
                OPENFILENAME ofn;
                WCHAR szFileName[MAX_PATH];

                ZeroMemory(&ofn, sizeof(ofn));
                ZeroMemory(szFileName, sizeof(szFileName));

                ofn.lStructSize = sizeof(ofn);
                ofn.lpstrTitle = L"Escolha um Bitmap";
                ofn.hwndOwner = hwnd;
                ofn.lpstrFilter = L"Bitmap Files (*.bmp)\0*.bmp\0";
                ofn.lpstrFile = szFileName;
                ofn.nMaxFile = MAX_PATH;
                ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
                ofn.lpstrDefExt = L"bmp";

                if(GetOpenFileName(&ofn))
                {
                    HANDLE hImage = LoadImage(NULL, szFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
                    if (hImage != 0)
                    {
                      CVR *cvr;

                      cvr = cvr_new(hImage);

                      if (SendMessage(hwnd, WM_COMMAND, ID_FILE_CLOSE, 0) == FALSE)
                        cvr_free(&cvr);
                      else
                      {
                        wd->cvr = cvr;
                        wd->hImage = hImage;
                        wd->bModified = TRUE;
                        wd->szExportFileName[0] = '\0';
                        wd->szFileName[0] = '\0';
                        lstrcpyn(wd->szTitle, L"novo", MAX_PATH);

                        gui_update(hwnd, wd);
                      }
                    } else
                      ErrorMsg(hwnd, L"Arquivo de Imagem inválido");
                }
              } break;
            case ID_FILE_SAVE_AS:
              {
                OPENFILENAME ofn;
                WCHAR szFileName[MAX_PATH];

                if (wd->cvr == NULL) return FALSE;

                ZeroMemory(szFileName, sizeof(szFileName));
                ZeroMemory(&ofn, sizeof(ofn));

                ofn.lStructSize = sizeof(ofn);
                ofn.hwndOwner = hwnd;
                ofn.lpstrTitle = L"Salvar como...";
                ofn.lpstrFilter = L"Conversion Files (*.cvr)\0*.cvr\0";
                ofn.lpstrFile = szFileName;
                ofn.nMaxFile = MAX_PATH;
                ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
                ofn.lpstrDefExt = L"cvr";

                if(GetSaveFileName(&ofn))
                  if (cvr_save(szFileName, wd->cvr) == FALSE) 
                  {
                    ErrorMsg(hwnd, L"Arquivo não pode ser salvo");
                    return FALSE;
                  } else
                  {
                    WCHAR tmp[65 + MAX_PATH];

                    lstrcpyn(wd->szFileName, szFileName, MAX_PATH);
                    wsprintfW(tmp, L"Conversor - %s", wd->szFileName);
                    SetWindowText(hwnd, tmp);

                    if (wd->bModified != FALSE)
                    {
                      wd->bModified = FALSE;
                      gui_update_title(hwnd, wd);
                    }
                    return TRUE;
                  }
              } break;

            case ID_FILE_SAVE:
              if (wd->cvr == NULL) return FALSE;
              if (wd->bModified == TRUE)
                if (wd->szFileName[0] == '\0') return SendMessage(hwnd, WM_COMMAND, ID_FILE_SAVE_AS, 0);
                else 
                  if (cvr_save(wd->szFileName, wd->cvr) == FALSE)
                  {
                    ErrorMsg(hwnd, L"Arquivo não pode ser salvo");
                    ErrorMsg(hwnd, wd->szFileName);
                    return FALSE;
                  } else 
                  {
                    wd->bModified = FALSE;
                    gui_update_title(hwnd, wd);
                    return TRUE;
                  }
            break;

            case ID_FILE_EXPORT:
            {
              OPENFILENAME ofn;

              if (wd->cvr == NULL) return FALSE;

              ZeroMemory(&ofn, sizeof(ofn));

              ofn.lStructSize = sizeof(ofn);
              ofn.hwndOwner = hwnd;
              ofn.lpstrTitle = L"Exportar";
              ofn.lpstrFilter = L"Bitmap Files (*.bin)\0*.bin\0";
              ofn.lpstrFile = wd->szExportFileName;
              ofn.nMaxFile = MAX_PATH;
              ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
              ofn.lpstrDefExt = L"bmp";

              if(GetSaveFileName(&ofn))
                if (gui_export(wd->szExportFileName, wd->cvr) == FALSE)
                  ErrorMsg(hwnd, L"Arquivo não pode ser exportado");
            } break;

            case ID_FILE_OPEN:
              {
                OPENFILENAME ofn;
                WCHAR szFileName[MAX_PATH];

                ZeroMemory(&ofn, sizeof(ofn));
                ZeroMemory(szFileName, sizeof(szFileName));

                ofn.lStructSize = sizeof(ofn);
                ofn.hwndOwner = hwnd;
                ofn.lpstrFilter = L"Convert Files (*.cvr)\0*.cvr\0";
                ofn.lpstrFile = szFileName;
                ofn.nMaxFile = MAX_PATH;
                ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
                ofn.lpstrDefExt = L"cvr";

                if(GetOpenFileName(&ofn))
                {
                  CVR *cvr;

                  cvr = cvr_open(szFileName);
                  if (cvr == NULL) ErrorMsg(hwnd, L"Arquivo de conversão não pode ser aberto");
                  else
                  {
                    if (SendMessage(hwnd, WM_COMMAND, ID_FILE_CLOSE, 0) == TRUE)
                    {
                      wd->cvr = cvr;
                      wd->bModified = FALSE;
                      wd->hImage = GetBitmapFromColorArray(wd->cvr->image, wd->cvr->nx, wd->cvr->ny);
                      lstrcpyn(wd->szFileName, szFileName, MAX_PATH);
                      wd->szExportFileName[0] = '\0';
                      lstrcpyn(wd->szTitle, wd->szFileName, MAX_PATH);
                      gui_update(hwnd, wd);
                    } else
                    {
                      cvr_free(&cvr);
                    }
                  }
                }
              } break;

            case ID_FILE_CLOSE:
              {
                if (wd->bModified == TRUE)
                {
                  //perguntar se deseja salvar
                  switch(MessageBox(hwnd, L"Deseja salvar o arquivo agora?", L"Arquivo não foi salvo", MB_YESNOCANCEL | MB_ICONQUESTION))
                  {
                  case IDYES: if (SendMessage(hwnd, WM_COMMAND, ID_FILE_SAVE, 0) == FALSE) return FALSE; break;
                  case IDNO: break;
                  case IDCANCEL: return FALSE;
                  }
                }

                cvr_free(&wd->cvr);

                if (wd->hImage != NULL) {DeleteObject(wd->hImage); wd->hImage = NULL;}
                if (wd->hImageInv != NULL) {DeleteObject(wd->hImageInv); wd->hImageInv = NULL;}

                wd->szFileName[0] = '\0';
                wd->szTitle[0] = '\0';
                gui_update_title(hwnd, wd);
                KillTimer(hwnd, IDT_TIMER1);
                SendMessage(wd->hwndStatic, IVM_SETPICTURE, 0, 0);
                SendMessage(wd->hwndStatic, IVM_SETPICTURE, 0, 1);
                UpdateTableList(wd->hwndList, NULL);

                return TRUE;
              } break;
            case ID_FILE_EXIT:
                SendMessage(hwnd, WM_CLOSE, 0, 0); break;

            case ID_VIEW_ORIG:
              {
                SendMessage(wd->hwndStatic, IVM_SETSTRETCH, (WPARAM)FALSE, 0);
                CheckMenuRadioItem(wd->hMenuView, ID_VIEW_ORIG, ID_VIEW_STRETCH, ID_VIEW_ORIG, MF_BYCOMMAND);
              } break;

            case ID_VIEW_FIT:
              {
                SendMessage(wd->hwndStatic, IVM_SETSTRETCH, (WPARAM)TRUE, 0);
                SendMessage(wd->hwndStatic, IVM_SETKEEPASPECT, (WPARAM)TRUE, 0);
                CheckMenuRadioItem(wd->hMenuView, ID_VIEW_ORIG, ID_VIEW_STRETCH, ID_VIEW_FIT, MF_BYCOMMAND);
              } break;

            case ID_VIEW_STRETCH:
              {
                SendMessage(wd->hwndStatic, IVM_SETSTRETCH, (WPARAM)TRUE, 0);
                SendMessage(wd->hwndStatic, IVM_SETKEEPASPECT, (WPARAM)FALSE, 0);
                CheckMenuRadioItem(wd->hMenuView, ID_VIEW_ORIG, ID_VIEW_STRETCH, ID_VIEW_STRETCH, MF_BYCOMMAND);
              } break;
          }
        break;
        default: return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

void gui_update(HWND hwnd, MainWD *wd)
{
  WCHAR tmp[33];

  wsprintfW(tmp, L"\t%dx%d", wd->cvr->ny, wd->cvr->nx);
  SendMessage(wd->hwndStatusbar, SB_SETTEXTW, 1, (LPARAM)tmp);
  gui_update_title(hwnd, wd);
  SendMessage(wd->hwndStatic, IVM_SETPICTURE, (WPARAM)wd->hImage, 0);
  SendMessage(wd->hwndStatic, IVM_SETLAYER, 0, 0);
  UpdateTableList(wd->hwndList, &wd->cvr->table);
  SendMessage(hwnd, WM_SIZE, 0, 0);
}

void gui_update_title(HWND hwnd, MainWD *wd)
{
  WCHAR tmp[65 + MAX_PATH];

  if (wd->szTitle[0] != '\0')
  {
    wsprintf(tmp, L"Conversor - %s%c", wd->szTitle, wd->bModified ? '*' : '\0');
    SetWindowText(hwnd, tmp);
  } else
    SetWindowText(hwnd, L"Conversor");
}

BOOLEAN gui_export(LPWSTR file, CVR *cvr)
{
  HANDLE hFile;
  BOOLEAN ret;

  hFile = CreateFile(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hFile == INVALID_HANDLE_VALUE) ret = FALSE;
  else
  {
    float *field;
    DWORD size;

    field = GenerateField(cvr, &size);
    if (field == NULL) ret = FALSE;
    else
    {
      DWORD rsize;

      WriteFile(hFile, (LPCVOID)field, size*sizeof(float), &rsize, NULL);
      HeapFree(ProcHeap, 0 , field);
      ret = TRUE;
    }
    CloseHandle(hFile);
  }

  return ret;
}

BOOLEAN cvr_save(LPWSTR file, CVR *cvr)
{
  HANDLE hFile;

  hFile = CreateFileW(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

  if (hFile == INVALID_HANDLE_VALUE) return FALSE;
  else
  {
    DWORD rsize;
    CVRfileHeader header;

    header.magic = CVR_FILE_HEADER_MAGIC;
    header.nx = cvr->nx;
    header.ny = cvr->ny;
    header.tsize = cvr->table.size;

    WriteFile(hFile, (LPCVOID)&header, sizeof(CVRfileHeader), &rsize, NULL);
    WriteFile(hFile, (LPCVOID)cvr->table.t, cvr->table.size * sizeof(TTableItem), &rsize, NULL);
    WriteFile(hFile, (LPCVOID)cvr->image, cvr->nx * cvr->ny * sizeof(sBGR), &rsize, NULL);
    CloseHandle(hFile);
    return TRUE;
  }
}

CVR* cvr_new(HBITMAP hBMP)
{
  CVR *cvr;

  cvr = HeapAlloc(ProcHeap, 0, sizeof(CVR));
  cvr->image = GetColorArray(hBMP, &cvr->nx, &cvr->ny);
  cvr->table = *GetColorTable(cvr->image, cvr->nx, cvr->ny);
  return cvr;
}

CVR* cvr_open(LPWSTR file)
{
  HANDLE hFile;
  CVR* ret;

  hFile = CreateFile(file, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hFile == INVALID_HANDLE_VALUE) ret = NULL;
  else
  {
    CVRfileHeader header;
    DWORD rsize;

    if ((ReadFile(hFile, (LPVOID)&header, sizeof(CVRfileHeader), &rsize, NULL) == FALSE) || (rsize != sizeof(CVRfileHeader))) ret = NULL;
    else
    {
      if (header.magic != CVR_FILE_HEADER_MAGIC) ret = NULL;
      else
      {
        CVR *cvr;

        cvr = HeapAlloc(ProcHeap, 0, sizeof(CVR));
        if (cvr == NULL) ret = NULL;
        else
        {
          cvr->table.size = header.tsize;
          cvr->nx = header.nx;
          cvr->ny = header.ny;

          cvr->table.t = HeapAlloc(ProcHeap, 0, header.tsize*sizeof(TTableItem));
          cvr->image = HeapAlloc(ProcHeap, 0, header.nx*header.ny*sizeof(sBGR));

          if ((cvr->table.t == NULL) || (cvr->image == NULL))
          {
            if (cvr->table.t != NULL) HeapFree(ProcHeap, 0 , cvr->table.t);
            if (cvr->image != NULL) HeapFree(ProcHeap, 0 , cvr->image);
            HeapFree(ProcHeap, 0 , cvr);
            ret = NULL;
          } else
            if ((ReadFile(hFile, (LPVOID)cvr->table.t, header.tsize*sizeof(TTableItem), &rsize, NULL) == FALSE) || (rsize != header.tsize*sizeof(TTableItem)) ||
                (ReadFile(hFile, (LPVOID)cvr->image, header.nx*header.ny*sizeof(sBGR), &rsize, NULL) == FALSE) || (rsize != header.nx*header.ny*sizeof(sBGR)))
            {
              HeapFree(ProcHeap, 0 , cvr->table.t);
              HeapFree(ProcHeap, 0 , cvr->image);
              HeapFree(ProcHeap, 0 , cvr);
              ret = NULL;
            } else
              ret = cvr;
        }
      }
    }
    CloseHandle(hFile);
  }
  return ret;
}

void cvr_free(CVR **cvr)
{
  if (*cvr == NULL) return;

  if ((*cvr)->image != NULL) HeapFree(ProcHeap, 0 , (*cvr)->image);
  if ((*cvr)->table.t != NULL) HeapFree(ProcHeap, 0 , (*cvr)->table.t);
  HeapFree(ProcHeap, 0 , *cvr);
  *cvr = NULL;
}

void UpdateTableList(HWND hwnd, TTable *t)
{
  DWORD sizex, sizey, i;
  HDC hDCimg = GetDC(hwnd);
  HDC hDC = CreateCompatibleDC(hDCimg);
  HIMAGELIST hImageList;
  HBITMAP hBMP;
  RECT rect;
  HGDIOBJ hOld;

  if (t == NULL)
  {
    ListView_SetItemCount(hwnd, 0);
    ListView_SetImageList(hwnd, NULL, LVSIL_SMALL);
    return;
  }

  ListView_SetItemCount(hwnd, t->size);

  if (t->size == 0)
  {
    ListView_SetImageList(hwnd, NULL, LVSIL_SMALL);
  }
  else
  {
    sizex = GetSystemMetrics (SM_CXSMICON)*2;
    sizey = GetSystemMetrics (SM_CYSMICON);

    hImageList = ImageList_Create(sizex, sizey, ILC_COLORDDB, t->size, 0);
    hBMP = CreateCompatibleBitmap(hDCimg, sizex, sizey);
    hOld = SelectObject(hDC, hBMP);
    rect.top = rect.left = 0;
    rect.bottom = sizey;
    rect.right = sizex;
    FillRect(hDC, &rect, (HBRUSH)(COLOR_WINDOW));
    rect.top += 2;
    rect.left += 2;
    rect.bottom -= 2;
    rect.right -= 2;
    SelectObject(hDC, hOld);

    for(i=0;i<t->size;i++)
    {
      sBGR color = t->t[i].c;
      HBRUSH hbr = CreateSolidBrush(RGB(color.r,color.g,color.b));
      SelectObject(hDC, hBMP);
      FillRect(hDC, &rect, hbr);
      SelectObject(hDC, hOld);
      ImageList_Add(hImageList, hBMP, NULL);
      DeleteObject(hbr);
    }

    DeleteDC(hDC);
    ReleaseDC(hwnd, hDCimg);
    DeleteObject(hBMP);
    ListView_SetImageList(hwnd, hImageList, LVSIL_SMALL);
  }
}

TTable* GetColorTable(pBGR img, DWORD nx, DWORD ny)
{
  DWORD x,y;
  TTable *table;
  int tsize;
  int count = 0;
  unsigned char rgb[4];
  unsigned char * tb;
  int index1, index2;

  tsize = 256;
  table = HeapAlloc(ProcHeap, 0, sizeof(TTable));
  table->t = HeapAlloc(ProcHeap, 0, tsize*sizeof(TTableItem));

  tb = HeapAlloc(ProcHeap, HEAP_ZERO_MEMORY, ((256*256*256)/8)*sizeof(BYTE));

  for (y=0;y<ny;y++) for (x=0;x<nx;x++)
  {
    *(pBGR)rgb = img[x+y*nx];
    index1 = (rgb[0]>>3) | (rgb[1]<<5) | (rgb[2]<<13);
    index2 = rgb[0]&0x07;
    if (!(tb[index1] & 1<<index2))
    {
      tb[index1] |= 1<<index2;
      if (count > tsize) table->t = HeapReAlloc(ProcHeap, HEAP_ZERO_MEMORY, table->t, (tsize *= 2)*sizeof(TTableItem));
      table->t[count].v = 0.0f;
      table->t[count++].c = *(pBGR)rgb;
    }
  }

  HeapFree(ProcHeap, 0 ,tb);
  table->t = HeapReAlloc(ProcHeap, HEAP_ZERO_MEMORY, table->t, count*sizeof(TTableItem));
  table->size = count;
  return table;
}

pBGR InvertColor(pBGR img, DWORD nx, DWORD ny, sBGR color)
{
  DWORD x, y;
  sBGR white = {255,255,255,0};
  sBGR black = {0,0,0,0};
  pBGR res;

  res = HeapAlloc(ProcHeap, 0, nx*ny*sizeof(sBGR));

  for (y=0;y<ny;y++) for (x=0;x<nx;x++)
  {
    sBGR cur = img[x+y*nx];
    if (cur.r == color.r && 
        cur.g == color.g &&
        cur.b == color.b) cur = (cur.r+cur.g+cur.b < 384) ? white : black;
    res[x+y*nx] = cur;
  }

  return res;
}

INT GetColorIndexFromTable(TTable table, sBGR color)
{
  INT i;
  for(i=0;i<(INT)table.size;i++)
  {
    sBGR cur = table.t[i].c;
    if (cur.r == color.r && 
        cur.g == color.g &&
        cur.b == color.b) break;
  }
  if (i >= (INT)table.size) i = -1;
  return i;
}

float* GenerateField(CVR *cvr, int *size)
{
  DWORD x,y;
  INT i;
  sBGR color;
  float *field;

  *size = cvr->nx*cvr->ny;
  field = HeapAlloc(ProcHeap, 0, *size*sizeof(float));

  for (y=0;y<cvr->ny;y++) for (x=0;x<cvr->nx;x++)
  {
    color = cvr->image[x+y*cvr->nx];
    i = GetColorIndexFromTable(cvr->table, color);
    if (i != -1) field[x*cvr->ny+y] = cvr->table.t[i].v;
  }

  return field;
}

pBGR GetColorArray(HBITMAP hBMP, DWORD *nx, DWORD *ny)
{
  DWORD snx, sny;
	BITMAPINFO bi;
	BOOL bRes;
	pBGR res;
  HDC hDC;
  HGDIOBJ hOld;
  BITMAP bm;

  GetObject(hBMP, sizeof(BITMAP), &bm);
  hDC = CreateCompatibleDC(NULL);
  hOld = SelectObject(hDC, hBMP);
  if (nx == NULL) nx = &snx;
  if (ny == NULL) ny = &sny;
  *nx = bm.bmWidth;
  *ny = bm.bmHeight;

	bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
	bi.bmiHeader.biWidth = *nx;
	bi.bmiHeader.biHeight = - (LONG)*ny;
	bi.bmiHeader.biPlanes = 1;
	bi.bmiHeader.biBitCount = 32;
	bi.bmiHeader.biCompression = BI_RGB;
	bi.bmiHeader.biSizeImage = *nx * 4 * *ny;
	bi.bmiHeader.biClrUsed = 0;
	bi.bmiHeader.biClrImportant = 0;
	
  res = HeapAlloc(ProcHeap, 0, (*nx)*(*ny)*sizeof(sBGR));
	bRes = GetDIBits(hDC, hBMP, 0, *ny, res, &bi, DIB_RGB_COLORS);

  SelectObject(hDC, hOld);
  DeleteDC(hDC);

	if (!bRes) 
  {
		HeapFree(ProcHeap, 0 , res);
		res = NULL;
	}
	return res;
}

HBITMAP GetBitmapFromColorArray(pBGR buf, int nx, int ny)
{
  BITMAPINFO bi;
  HBITMAP res;
  HDC hDC, hDCd;
  HGDIOBJ hOld;

  hDCd = GetDC(NULL);
  hDC = CreateCompatibleDC(hDCd);
  res = CreateCompatibleBitmap(hDCd, nx, ny);
  ReleaseDC(NULL, hDCd);
  hOld = SelectObject(hDC, res);

	bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
	bi.bmiHeader.biWidth = nx;
	bi.bmiHeader.biHeight = -ny;
	bi.bmiHeader.biPlanes = 1;
	bi.bmiHeader.biBitCount = 32;
	bi.bmiHeader.biCompression = BI_RGB;
	bi.bmiHeader.biSizeImage = nx*ny*sizeof(sBGR);
	bi.bmiHeader.biClrUsed = 0;
	bi.bmiHeader.biClrImportant = 0;
	
  SetDIBits(hDC, res, 0, ny, buf, &bi, DIB_RGB_COLORS);

  SelectObject(hDC, hOld);
  DeleteDC(hDC);

  return res;
}



/* Copyright 2005 Matheus Izvekov */

#define UNICODE

#include <windows.h>
#include <commctrl.h>
#include "imageviewer.h"

static LRESULT CALLBACK ImViewProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

typedef struct
{
  HBITMAP hBMP[2];
  BITMAP BM[2];
  HDC hDC;
  ULONG curlayer;
  BOOL stretch, keepaspect;
  double scalex, scaley;
  LONG dx, dy, width, height;
} ImViewWD;
/*
static void CalcScale(ImViewWD* wd, LONG t_height, LONG t_width)
{
  if (wd->stretch == TRUE)
  {
    wd->dx = 0;
    wd->dy = 0;
    wd->height = t_height;
    wd->width = t_width;
    if (wd->keepaspect == TRUE)
    {
        double scalex = (double)t_height / (double)wd->BMimg.bmHeight;
        double scaley = (double)t_width / (double)wd->BMimg.bmWidth;

        if (scalex < scaley)
        {
          wd->width = wd->BMimg.bmWidth * scalex;
          wd->dx = (t_width - wd->width)/2;
        } else
        {
          wd->height = wd->BMimg.bmHeight * scaley;
          wd->dy = (t_height - wd->height)/2;
        }
    }
  } else
  {
    wd->height = wd->BMimg.bmHeight;
    wd->width = wd->BMimg.bmWidth;
    wd->dx = (t_width - wd->width)/2;
    wd->dy = (t_height - wd->height)/2;
  }
}
*/
BOOL InitImView(HINSTANCE hinstance)
{
  WNDCLASSEX wc;

  wc.cbSize        = sizeof(WNDCLASSEX);
  wc.style         = 0;
  wc.lpfnWndProc   = ImViewProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = sizeof(ImViewWD*);
  wc.hInstance     = hinstance;
  wc.hIcon         = NULL;
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
  wc.lpszMenuName  = NULL;
  wc.lpszClassName = IMVIEWCLASSNAME;
  wc.hIconSm       = NULL;

  if(!RegisterClassEx(&wc)) return FALSE;
  else return TRUE;
}

static LRESULT CALLBACK ImViewProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  ImViewWD *wd;
  HWND hwndParent = GetParent(hwnd);

  wd = (ImViewWD *)GetWindowLong(hwnd, 0);

  switch(msg)
  {
    case WM_CREATE:
      {
        HDC hDC;

        wd = GlobalAlloc(GMEM_FIXED, sizeof(ImViewWD));
        wd->hBMP[0] = NULL;
        wd->hBMP[1] = NULL;
        wd->keepaspect = FALSE;
        wd->stretch = FALSE;
        wd->curlayer = 0;

        hDC = GetDC(hwnd);
        wd->hDC = CreateCompatibleDC(hDC);
        ReleaseDC(hwnd, hDC);

        SetWindowLong(hwnd, 0, (LONG)wd);
      } break;
    case WM_DESTROY:
      {
        DeleteDC(wd->hDC);
        GlobalFree(wd);
      } break;
    case WM_SIZE:
      {
        RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
      } break;
    case WM_PAINT:
      {
        HDC hDC;
        PAINTSTRUCT paint;
        BITMAP bm;
        HBRUSH hbBG;

        hbBG = (HBRUSH)GetClassLong(hwnd, GCL_HBRBACKGROUND);

        hDC = BeginPaint(hwnd, &paint);

        if (GetObject(GetCurrentObject(wd->hDC, OBJ_BITMAP), sizeof(BITMAP), &bm) != 0)
        {
          RECT wrect, trect1, trect2, trect3, trect4;
          LONG t_height, t_width;

          GetWindowRect(hwnd, &wrect);
          t_height = wrect.bottom - wrect.top;
          t_width = wrect.right - wrect.left;
          
          if (wd->stretch == TRUE)
          {
            wd->dx = 0;
            wd->dy = 0;
            wd->height = t_height;
            wd->width = t_width;
            wd->scaley = (double)t_height / (double)bm.bmHeight;
            wd->scalex = (double)t_width / (double)bm.bmWidth;

            if (wd->keepaspect == TRUE)
            {
                if (wd->scalex > wd->scaley)
                {
                  wd->width = (LONG)(bm.bmWidth * wd->scaley);
                  wd->scalex = (double)wd->width / (double)bm.bmWidth;
                  wd->dx = (t_width - wd->width)/2;
                  trect1.top = trect2.top = 0;
                  trect1.bottom = trect2.bottom = t_height;
                  trect1.left = 0;
                  trect1.right = wd->dx;
                  trect2.left = wd->dx + wd->width;
                  trect2.right = t_width;
                  FillRect(hDC, &trect1, hbBG);
                  FillRect(hDC, &trect2, hbBG);
                } else
                {
                  wd->height = (LONG)(bm.bmHeight * wd->scaley);
                  wd->scaley = (double)wd->height / (double)bm.bmHeight;
                  wd->dy = (t_height - wd->height)/2;
                  trect1.left = trect2.left = 0;
                  trect1.right = trect2.right = t_width;
                  trect1.top = 0;
                  trect1.bottom = wd->dy;
                  trect2.top = wd->dy + wd->height;
                  trect2.bottom = t_width;
                  FillRect(hDC, &trect1, hbBG);
                  FillRect(hDC, &trect2, hbBG);
                }
            }

            StretchBlt(hDC, wd->dx, wd->dy, wd->width, wd->height, 
                      wd->hDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
          } else
          {
            wd->scalex = wd->scaley = 1.0f;
            wd->height = min(bm.bmHeight, t_height);
            wd->width = min(bm.bmWidth, t_width);
            wd->dx = (t_width - wd->width)/2;
            wd->dy = (t_height - wd->height)/2;

            trect1.top = trect2.top = trect3.top = 0;
            trect1.bottom = trect3.bottom = trect4.bottom = t_height;
            trect2.bottom = wd->dy;
            trect4.top = wd->dy + wd->height;

            trect1.left = 0;
            trect3.right = t_width;
            trect1.right = trect2.left = trect4.left = wd->dx;
            trect2.right = trect4.right = trect3.left = wd->dx + wd->width;
            
            FillRect(hDC, &trect1, hbBG);
            FillRect(hDC, &trect2, hbBG);
            FillRect(hDC, &trect3, hbBG);
            FillRect(hDC, &trect4, hbBG);
            StretchBlt(hDC, wd->dx, wd->dy, wd->width, wd->height, 
                      wd->hDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
            //BitBlt(hDC, wd->dx, wd->dy, wd->width, wd->height, wd->hDC, 0, 0, SRCCOPY);
          }
        }
        EndPaint(hwnd, &paint);
      } break;

    case WM_RBUTTONUP:
      if (hwndParent != NULL)
      {
        NMMOUSE tmp;

        tmp.hdr.code = NM_RCLICK;
        tmp.hdr.hwndFrom = hwnd;
        tmp.hdr.idFrom = 0/*INCOMPLETE*/;

        tmp.pt.x = LOWORD(lParam);
        tmp.pt.y = HIWORD(lParam);

        SendMessage(hwndParent, WM_NOTIFY, (WPARAM)NULL, (LPARAM)&tmp);
      } break;
    case WM_LBUTTONDOWN:
    case WM_MOUSEMOVE:
      if (hwndParent != NULL)
      {
        NMIVPOS tmp;
        
        tmp.hdr.code = msg;
        tmp.hdr.hwndFrom = hwnd;
        tmp.hdr.idFrom = 0/*INCOMPLETE*/;

        //SetPixel(GetDC(hwnd), LOWORD(lParam), HIWORD(lParam), RGB(0,0,0));
        tmp.x = (WORD)((LOWORD(lParam) - wd->dx)/wd->scalex);
        tmp.y = (WORD)((HIWORD(lParam) - wd->dy)/wd->scaley);
        if ((tmp.x >= 0) && (tmp.y >= 0) /*&& (tmp.x < wd->width) && (tmp.y < wd->height)*/)
          SendMessage(hwndParent, WM_NOTIFY, (WPARAM)NULL, (LPARAM)&tmp);
      } break;
    
    case IVM_SETPICTURE:
      {
        LRESULT ret;
        RECT wrect;
        LONG t_height, t_width;
        LONG layer;

        GetWindowRect(hwnd, &wrect);
        t_height = wrect.bottom - wrect.top;
        t_width = wrect.right - wrect.left;

        layer = (LONG)lParam;
        ret = (LRESULT)wd->hBMP[layer];
        wd->hBMP[layer] = (HBITMAP)wParam;

        if (wd->curlayer == layer) 
        {
          SelectObject(wd->hDC, (HGDIOBJ)wParam);
          RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
        }
        return ret;
      } break;
    case IVM_GETPICTURE:
      {
        return (WPARAM)wd->hBMP[wd->curlayer];
      } break;
    case IVM_SETKEEPASPECT:
      {
        RECT wrect;
        LONG t_height, t_width;

        GetWindowRect(hwnd, &wrect);
        t_height = wrect.bottom - wrect.top;
        t_width = wrect.right - wrect.left;

        wd->keepaspect = (BOOL)wParam;

        RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
      } break;
    case IVM_GETKEEPASPECT:
      {
        return (WPARAM)wd->keepaspect;
      } break;
    case IVM_SETSTRETCH:
      {
        RECT wrect;
        LONG t_height, t_width;

        GetWindowRect(hwnd, &wrect);
        t_height = wrect.bottom - wrect.top;
        t_width = wrect.right - wrect.left;

        wd->stretch = (BOOL)wParam;

        RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
      } break;
    case IVM_GETSTRETCH:
      {
        return (WPARAM)wd->stretch;
      } break;
    case IVM_SETLAYER:
      {
        wd->curlayer = (ULONG)wParam;
        SelectObject(wd->hDC, wd->hBMP[wParam]);
        RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
      } break;
    case IVM_GETLAYER:
      {
        return wd->curlayer;
      } break;
    default: return DefWindowProc(hwnd, msg, wParam, lParam); break;
  }

  return FALSE;
}

/* Copyright 2005 Matheus Izvekov */

#ifndef _IMVIEWER_
#define _IMVIEWER_

#include <windows.h>

typedef struct
{
  NMHDR hdr;
  WORD x, y;  
} NMIVPOS, *LPNMIVPOS;

#define IMVIEWCLASSNAME L"IMVIEW"

#define IVM_SETPICTURE 0x0170
#define IVM_GETPICTURE 0x0171
#define IVM_SETKEEPASPECT 0x0173
#define IVM_GETKEEPASPECT 0x0174
#define IVM_SETSTRETCH 0x0175
#define IVM_GETSTRETCH 0x0176
#define IVM_SETLAYER 0x0177
#define IVM_GETLAYER 0x0178

BOOL InitImView(HINSTANCE hinstance);

#endif



Reply via email to