// vcsam2p.cpp : Defines the entry point for the application. // #include "config2.h" #include "image.hpp" #include "error.hpp" #include "main.hpp" /* init_loader(), init_applier() */ #include "StdAfx.h" #include "resource.h" #define MAX_LOADSTRING 100 extern "C" int main(int argc, char**argv); #if 0 extern "C" int getpid(void); //#include /* OSVERSIONINFO etc. */ //#include /* _getpid() */ static unsigned long win32_os_id(void) { static OSVERSIONINFO osver; static DWORD w32_platform = (DWORD)-1; if (w32_platform==-1 || osver.dwPlatformId != w32_platform) { memset(&osver, 0, sizeof(OSVERSIONINFO)); osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osver); w32_platform = osver.dwPlatformId; } return (unsigned long)w32_platform; } static inline bool IsWin95(void) { return (win32_os_id() == VER_PLATFORM_WIN32_WINDOWS); } // static int win32_getpid(void) { int getpid(void) { int pid; pid = _getpid(); /* Windows 9x appears to always reports a pid for threads and processes * that has the high bit set. So we treat the lower 31 bits as the * "real" PID for Perl's purposes. */ if (IsWin95() && pid < 0) pid = -pid; return pid; } #endif // Global Variables: HINSTANCE hInst; // current instance // TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text // Foward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK dialogRun(HWND, UINT, WPARAM, LPARAM); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, // !! int nCmdShow) { // TODO: Place code here. MSG msg; HACCEL hAccelTable; // Initialize global strings // LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_VCSAM2P, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_VCSAM2P); // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; } // // FUNCTION: MyRegisterClass() // // PURPOSE: Registers the window class. // // COMMENTS: // // This function and its usage is only necessary if you want this code // to be compatible with Win32 systems prior to the 'RegisterClassEx' // function that was added to Windows 95. It is important to call this function // so that the application will get 'well formed' small icons associated // with it. // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = 0; /*CS_HREDRAW | CS_VREDRAW;*/ wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SAM2P32); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = (LPCSTR)IDC_VCSAM2P; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SAM2P16); return RegisterClassEx(&wcex); } /* --- */ /** An image that can be rendered onto a window really quickly */ class WinFastImage { HDC hmemdc; HBITMAP hbitmap; slen_t wd, ht; public: // WinFastImage::WinFastImage(slen_t wd_, slen_t ht_); WinFastImage(); ~WinFastImage(); /** Constructs a WinFastImage that can be drawn fast onto hdc. */ WinFastImage(HDC hdc, HBITMAP hsrc); /** Constructs a WinFastImage that can be drawn fast onto hwnd and all compatible HDCs. */ WinFastImage(HWND hwnd, HBITMAP hsrc); slen_t getWd() const { return wd; } slen_t getHt() const { return ht; } /* @param hdc dc on which fast rendering is desired * @param hsrc source bitmap containing the data */ void set(HDC hdc, HBITMAP hsrc); inline void drawTo(HDC hdc, slen_t dstX, slen_t dstY) const { drawTo(hdc, dstX, dstY, wd, ht, 0, 0); } inline void drawTo(HDC hdc, slen_t dstX, slen_t dstY, slen_t dstWd, slen_t dstHt, slen_t srcX, slen_t srcY) const { BitBlt(hdc,dstX,dstY,dstWd,dstHt,hmemdc,srcX,srcY,SRCCOPY); } // void drawTo(HDC hdc, slen_t dstX, slen_t dstY); // void drawTo(HDC hdc, slen_t dstX, slen_t dstY, slen_t dstWd, slen_t dstHt, slen_t srcX, slen_t srcY); /** MSDN says hbitmap must be a DDB, but it worked fine for me with a DIB */ static void getSize(HBITMAP hbitmap, slen_t &wd, slen_t &ht); }; void WinFastImage::getSize(HBITMAP hbitmap, slen_t &wd, slen_t &ht) { /* It took me 1 hour to figure this out. Not documented anywhere! */ BITMAPINFOHEADER h2; h2.biSize=sizeof(h2); h2.biBitCount=0; // h2.biWidth=11; h2.biHeight=22; h2.biPlanes=1; HDC hxdc=CreateDC("DISPLAY",NULL,NULL,NULL); GetDIBits(hxdc, hbitmap, 0, 0, NULL, (BITMAPINFO*)&h2, DIB_RGB_COLORS); wd=h2.biWidth; ht=h2.biHeight; DeleteDC(hxdc); } WinFastImage::WinFastImage(): hmemdc(NULL), hbitmap(NULL), wd(0), ht(0) {} WinFastImage::WinFastImage(HDC hdc, HBITMAP hsrc): hmemdc(NULL), hbitmap(NULL) { set(hdc, hsrc); } WinFastImage::WinFastImage(HWND hwnd, HBITMAP hsrc): hmemdc(NULL), hbitmap(NULL) { HDC hdc=GetDC(hwnd); set(hdc, hsrc); ReleaseDC(hwnd, hdc); } WinFastImage::~WinFastImage() { if (hmemdc!=NULL) DeleteDC(hmemdc); if (hbitmap!=NULL) DeleteObject(hbitmap); } void WinFastImage::set(HDC hdc, HBITMAP hsrc) { if (hmemdc!=NULL) DeleteDC(hmemdc); if (hbitmap!=NULL) DeleteObject(hbitmap); /* Imp: error handling */ getSize(hsrc, wd, ht); hmemdc=CreateCompatibleDC(hdc); hbitmap=CreateCompatibleBitmap(hdc, wd, ht); /* BUGFIX at 22:07 */ DeleteObject(SelectObject(hmemdc, hbitmap)); HDC hsrcdc=CreateCompatibleDC(hmemdc); SelectObject(hsrcdc, hsrc); BitBlt(hmemdc,0,0,wd,ht,hsrcdc,0,0,SRCCOPY); DeleteDC(hsrcdc); } /* --- */ class CopyableImage { public: virtual slen_t vi_getWd() const =0; virtual slen_t vi_getHt() const =0; /** Copies an row in RGB PPM8 format from (this) to `to' */ virtual void copyRGBRow(char *to, slen_t whichRow) const =0; }; /** A rectangular RGB image, suitable for displaying in Win32 API */ class WinImageRGB { /** Number of bytes per scanline */ slen_t rlen; HBITMAP hbitmap; /** data[0] is blue of upper left pixel, data[1] is green, data[2] is red. Rows * are aligned to 4-byte boundary */ char *data; BITMAPINFOHEADER header; void init(slen_t wd_, slen_t ht_); public: inline WinImageRGB(slen_t wd_, slen_t ht_) { init(wd_, ht_); } WinImageRGB(CopyableImage const&); ~WinImageRGB(); inline slen_t getWd() const { return header.biWidth; } inline slen_t getHt() const { return -header.biHeight; } virtual inline slen_t vi_getWd() const { return header.biWidth; } virtual inline slen_t vi_getHt() const { return -header.biHeight; } virtual void copyRGBRow(char *to, slen_t whichRow) const; inline slen_t getRlen() const { return rlen; } inline char* getData() const { return data; } inline HBITMAP getHbitmap() const { return hbitmap; } void drawTo(HDC hdc, slen_t dstX, slen_t dstY) const; void drawTo(HDC hdc, slen_t dstX, slen_t dstY, slen_t dstWd, slen_t dstHt, slen_t srcX, slen_t srcY) const; /** Copies image data from an other image in the PPM8 format: ppm8_data[0] * is red, ppm8_data[1] is green, pp8_data[2] is blue. Rows are aligned to * byte boundary. */ void fromPPM8(char const*ppm8_data); void fill(char r, char g, char b); void putPixel(slen_t x, slen_t y, char r, char g, char b); }; void WinImageRGB::init(slen_t wd_, slen_t ht_) { rlen=(wd_*3+3)&~3; header.biSize=sizeof(header); header.biWidth=wd_; header.biHeight=0-ht_; header.biPlanes=1; header.biBitCount=24; header.biCompression=BI_RGB; header.biSizeImage=0; header.biXPelsPerMeter=1000; /* returned by GetBitmapDimensionEx */ header.biXPelsPerMeter=1000; header.biClrUsed=0; header.biClrImportant=0; hbitmap=CreateDIBSection(NULL, (CONST BITMAPINFO*)&header, DIB_RGB_COLORS, (void**)&data, NULL, 0); // slen_t xx=GetDeviceCaps(hbitmap, HORZRES); } WinImageRGB::WinImageRGB(CopyableImage const& other) { init(other.vi_getWd(), other.vi_getHt()); char *buf=new char[rlen]; slen_t pad=(header.biWidth)&3, x, y=0, ym=header.biHeight; char *p=data; char const *ppm8_data; while (ym++!=0) { other.copyRGBRow(buf, y++); ppm8_data=buf; x=header.biWidth; while (x--!=0) { p[2]=*ppm8_data++; p[1]=*ppm8_data++; p[0]=*ppm8_data++; p+=3; } p+=pad; } delete [] buf; } WinImageRGB::~WinImageRGB() { DeleteObject(hbitmap); } void WinImageRGB::copyRGBRow(char *to, slen_t whichRow) const { if (whichRow<0U-header.biHeight) { char *p=data+rlen*whichRow, *pend=p+rlen; while (p!=pend) { to[0]=p[2]; to[1]=p[1]; to[2]=p[0]; p+=3; to+=3; } } } void WinImageRGB::drawTo(HDC hdc, slen_t dstX, slen_t dstY) const { drawTo(hdc, dstX, dstY, header.biWidth, -header.biHeight, 0, 0); } void WinImageRGB::drawTo(HDC hdc, slen_t dstX, slen_t dstY, slen_t dstWd, slen_t dstHt, slen_t srcX, slen_t srcY) const { HDC hmemdc=CreateCompatibleDC(hdc); DeleteObject(SelectObject(hmemdc, hbitmap)); /* ^^^ set the bitmap for hmemdc that Rectangle (hmemdc etc.) will draw to, to (this) */ // slen_t xx=GetDeviceCaps(hdc, HORZRES); // HPEN hpen=CreatePen(PS_SOLID, 0, RGB(255,0,0)); // HANDLE hold=SelectObject(hmemdc, hpen); // Rectangle(hmemdc,10,10,200,100); // SelectObject(hmemdc, hold); // DeleteObject(hpen); BitBlt(hdc,dstX,dstY,dstWd,dstHt,hmemdc,srcX,srcY,SRCCOPY); DeleteDC(hmemdc); } void WinImageRGB::fromPPM8(char const* ppm8_data) { /* Dat: biWidth*3 is considered when calculating pad */ slen_t pad=(header.biWidth)&3, x, y=header.biHeight; char *p=data; while (y++!=0) { x=header.biWidth; while (x--!=0) { p[2]=*ppm8_data++; p[1]=*ppm8_data++; p[0]=*ppm8_data++; p+=3; } p+=pad; } } void WinImageRGB::fill(char r, char g, char b) { /* Dat: biWidth*3 is considered when calculating pad */ slen_t pad=(header.biWidth)&3, x, y=header.biHeight; char *p=data; while (y++!=0) { x=header.biWidth; while (x--!=0) { *p++=b; *p++=g; *p++=r; } p+=pad; } } void WinImageRGB::putPixel(slen_t x, slen_t y, char r, char g, char b) { if (x<(slen_t)header.biWidth && y<(slen_t)-header.biHeight) { char *p=data+rlen*y+x; p[0]=b; p[1]=g; p[2]=r; } } /* --- */ /** Implements the CopyableImage interface for the sam2p Image::Sampled class. */ class CopyableAdapter: public CopyableImage { Image::Sampled const& img; public: inline CopyableAdapter(Image::Sampled const& img_): img(img_) {} inline virtual slen_t vi_getHt() const { return img.getHt(); } inline virtual slen_t vi_getWd() const { return img.getWd(); } inline virtual void copyRGBRow(char *to, slen_t whichRow) const { img.copyRGBRow(to, whichRow); } }; /* --- */ /** Size of previous open image */ static slen_t wd_last=0, ht_last=0; /** Size of window including decorations !! exclude decorations */ static const unsigned wd_def=150, ht_def=90; static WinImageRGB *imgr=NULL; static WinFastImage *imgf=NULL; static HWND hwnd_main; /** Changed since last save? */ static bool dirty=false; /** File loaded. NULL if no/new; begins with "* " for a dirty file, ": " for a normal file. * TODO(pts): Do `delete [] filename2;' on exit, also for other global variables. */ static char *filename2=NULL; static bool first_paint_p=true; // static char szHello[MAX_LOADSTRING]; /* OK: not resizable: WM_... */ /* Imp: clipboard copy-paste image */ /* !! about editbox non-grey disabled */ /* !! open rxvt_bug.bmp wrong window size */ /* !! test larger image than screen */ /* !! SetWindowText() LineScroll() */ /* !! bongeszo ne irjon felul ablakot */ /* !! transparent images */ /* void CHistoryEdit::AppendString(CString str) { SendMessage(EM_SETSEL,0xFFFFFFFF,-1); SendMessage(EM_REPLACESEL,FALSE,(LPARAM)(LPCTSTR)str); } */ // PURPOSE: Saves instance handle and creates main window // In this function, we save the instance handle in a global variable and // create and display the main program window. // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { init_sam2p_engine("vcsam2p"); hInst = hInstance; // Store instance handle in our global variable hwnd_main = CreateWindow(szWindowClass, Error::banner0, WS_OVERLAPPED| WS_CAPTION| WS_SYSMENU| WS_MINIMIZEBOX| WS_BORDER| WS_THICKFRAME, // WS_THICKFRAME: resizable (has sizing border) // WS_MAXIMIZEBOX, WS_OVERLAPPEDWINDOW CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hwnd_main) return FALSE; SetWindowPos(hwnd_main, NULL, 0, 0, wd_def, ht_def, SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); #if 0 imgr=new WinImageRGB(226, 33); if (imgr==NULL) return FALSE; imgr->fill(0,0,(char)255); HDC hdc_main=GetDC(hwnd_main); imgf=new WinFastImage(hdc_main, imgr->getHbitmap()); #endif ShowWindow(hwnd_main, nCmdShow); // ReleaseDC(hwnd_main, hdc_main); UpdateWindow(hwnd_main); // imgr->fill((char)255,0,0); return TRUE; } static void do_ask_save_as() { // !! implement this } /** @return true iff save successful */ static bool do_save(bool ask_save_as) { /* !! implement this */ if (!dirty) return true; if (filename2==NULL && ask_save_as) do_ask_save_as(); if (filename2==NULL) return false; if (IDYES==MessageBox(hwnd_main, "Saving... Success?", NULL, MB_YESNO)) { dirty=false; return true; } return false; } static void do_save_as(void) { char *old_filename2=filename2; filename2=NULL; do_ask_save_as(); if (filename2!=NULL) { if (do_save(false)) { delete [] old_filename2; return; } delete [] filename2; } filename2=old_filename2; } /** no@@return true iff should exit */ static void do_exit(void) { if (dirty) { int i=MessageBox(hwnd_main, "Save changes before exit?", "Confirm exit", MB_YESNOCANCEL|MB_ICONEXCLAMATION|MB_DEFBUTTON1); if (i==IDCANCEL || (i==IDYES && !do_save(true))) return; } DestroyWindow(hwnd_main); } static void getFrameSize(HWND hwnd, LONG &wd_ret, LONG &ht_ret) { RECT wr; GetWindowRect(hwnd, &wr); RECT cr; GetClientRect(hwnd, &cr); wd_ret=(wr.right-wr.left)-(cr.right-cr.left); ht_ret=(wr.bottom-wr.top)-(cr.bottom-cr.top); } extern Image::Loader in_bmp_loader; struct SamArgs { typedef void* (WINAPI*samfun_t)(SamArgs const*); }; struct SamImageLoad: public SamArgs { char const *filename; SimBuffer::Flat *loadHints; }; void* WINAPI do_image_load(SamImageLoad const* args) { // Error::sev((Error::level_t) 2) << "a lma" << (Error*)0; return Image::load(args->filename, *(args->loadHints)); } void* do_samfun(SamArgs::samfun_t samfun, SamArgs const* args) { SimBuffer::B log; GenBuffer::Writable *old_serr=Error::serr; Error::pushPolicy((Error::level_t)0, (Error::level_t)-99, (Error::level_t)-199, &log); // Error::serr=&log; HANDLE hthread; DWORD res=0, tid; /* printf("Creating thread.\n"); */ if (NULL==(hthread=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)samfun, (void*)args, CREATE_SUSPENDED, &tid))) { log << "CreateThread() failed\n"; on_error: Error::serr=old_serr; log.term0(); MessageBox(hwnd_main, log(), Error::banner0, 0); return NULL; } /* printf("Resuming thread (h=0x%x tid=0x%x).\n", hthread, tid); */ if (0==1+ResumeThread(hthread)) { log << "ResumeThread() failed\n"; on_thread_error: TerminateThread(hthread, 0); CloseHandle(hthread); goto on_error; } /* printf("Waiting for thread.\n"); */ if (WAIT_FAILED==WaitForSingleObject(hthread, INFINITE)) { log << "WaitForSingleObject() failed\n"; goto on_thread_error; } if (0==GetExitCodeThread(hthread, &res)) { log << "GetExitCodeThread() failed\n"; goto on_thread_error; } Error::popPolicy(); CloseHandle(hthread); Error::serr=old_serr; // !! vvv 0 == NULL, exit(1), exit(2) is if (res+0U<10U) { /* log << "return(NULL);\n1\n"; */ goto on_error; } /* printf("Done, thread has returned=%u\n", res); */ return (void*)res; } /** Load image from disk, update imgr and imgf * @return true on success */ static bool do_open_image(char const* filename) { // MessageBox(NULL, filename, "opening image", 0); if (imgf!=NULL) { if (imgr!=NULL) { delete imgr; imgr=NULL; } delete imgf; imgf=NULL; if (filename2!=NULL) filename2[0]='-'; /* mark file closed */ } // !! free // !! check for errors // !! generalize SimBuffer::B loadHints; #if 0 Image::Loader::reader_t reader=in_bmp_loader.checker( "BM\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0", "", opt); FILE *f=fopen(filename, "rb"); if (f==NULL) return false; Image::Sampled *img=reader((Image::filep_t)f, loadHints); fclose(f); #endif init_loader(); SamImageLoad args; args.filename=filename; args.loadHints=&loadHints; Image::Sampled *img=(Image::Sampled*)do_samfun((SamArgs::samfun_t)do_image_load, &args); if (img==NULL) return false; // Image::load(filename, loadHints); imgr=new WinImageRGB(CopyableAdapter(*img)); // Image::Sampled *imgrgb=img->toRGB(8); // imgr=new WinImageRGB(img->getWd(), img->getHt()); // imgr->fill(0,0,(char)255); // imgr->fromPPM8(imgrgb->getRowbeg()); assert(imgr!=NULL); /* `operator new' never returns NULL */ // HDC hdc_main=GetDC(hwnd_main); imgf=new WinFastImage(hwnd_main, imgr->getHbitmap()); wd_last=imgf->getWd(); ht_last=imgf->getHt(); // ReleaseDC(hwnd_main, hdc_main); slen_t len=strlen(filename); if (filename2!=NULL) delete [] filename2; strcpy(filename2=new char[len+3], ": "); strcpy(filename2+2, filename); SetWindowText(hwnd_main, filename2); SetWindowLong(hwnd_main, GWL_STYLE, GetWindowLong(hwnd_main, GWL_STYLE)&~WS_THICKFRAME); /* ^^^ The Win32 API way to say hwnd_main.setResizable(false); :-) */ InvalidateRect(hwnd_main, NULL, TRUE); #if 0 LONG fr_wd, fr_ht; getFrameSize(hwnd_main, fr_wd, fr_ht); // !! handle minimum window size SetWindowPos(hwnd_main, NULL, 0, 0, fr_wd+imgf->getWd(), fr_ht+imgf->getHt(), SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); GdiFlush(); { /* Dat: strange, two iterations of getFrameSize + SetWindowPos is needed !! still bad */ getFrameSize(hwnd_main, fr_wd, fr_ht); SetWindowPos(hwnd_main, NULL, 0, 0, fr_wd+imgf->getWd(), fr_ht+imgf->getHt(), SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); } BOOL CYourWndOrDialog::ResizeClient (int nWidth, int nHeight, BOOL bRedraw) { RECT rcWnd; GetClientRect (&rcWnd); if(nWidth != -1) rcWnd.right = nWidth; if(nHeight != -1) rcWnd.bottom = nHeight; if(!::AdjustWindowRectEx(&rcWnd, GetStyle(), (!(GetStyle() & WS_CHILD) && GetMenu() != NULL)), GetExStyle())) return FALSE; UINT uFlags = SWP_NOZORDER | SWP_NOMOVE; if(!bRedraw) uFlags |= SWP_NOREDRAW; return SetWindowPos(NULL, 0, 0, rcWnd.right - rcWnd.left, rcWnd.bottom - rcWnd.top, uFlags); } // CYourWndOrDialog::ResizeClient #endif RECT rt; rt.left=0; rt.right=imgf->getWd(); rt.top=0; rt.bottom=imgf->getHt(); AdjustWindowRect(&rt, GetWindowLong(hwnd_main, GWL_STYLE), TRUE); // !! true SetWindowPos(hwnd_main, NULL, 0,0, rt.right-rt.left, rt.bottom-rt.top, SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); return true; } static char const* loadImageFilter= "all loadable images\0*.tiff;*.tif;*.jpeg;*.jpg;*.gif;*.png;*.pnm;*.pgm;*.ppm;*.xpm;*.lbm;*.tga;*.pcx;*.bmp\0" "TIFF images\0*.tiff;*.tif\0" "JPEG images\0*.jpeg;*.jpg\0" "GIF images\0*.gif\0" "PNG images\0*.png\0" "PNM images\0*.pnm;*.pbm;*.pgm;*.ppm\0" "PBM images\0*.pbm\0" "PGM images\0*.pgm\0" "PPM images\0*.ppm\0" "XPM images\0*.xpm\0" "IFF ILBM images\0*.lbm\0" // "EPS figures\0*.eps\0" // "PostScript documents\0*.ps\0" // "PDF figures\0*.pdf\0" // "XWD screen shots\0*.xwd\0" // "PAM images\0*.pam\0" // "Image meta information\0*.meta\0" "Targa TGA images\0*.tga\0" "PCX images\0*.pcx\0" "Windows BMP bitmaps\0*.bmp\0" "All files (*)\0*\0"; static char const* saveImageFilter= "all saveable images\0*.tiff;*.tif;*.jpeg;*.jpg;*.gif;*.png" ";*.pnm;*.pgm;*.ppm;*.xpm;*.lbm;*.tga;*.pcx;*.bmp;*.eps;*.ps;*.pdf;*.xwd;*.pam;*.meta\0" "TIFF images\0*.tiff;*.tif\0" "JPEG images\0*.jpeg;*.jpg\0" "GIF images\0*.gif\0" "PNG images\0*.png\0" "PNM images\0*.pnm;*.pbm;*.pgm;*.ppm\0" "PBM images\0*.pbm\0" "PGM images\0*.pgm\0" "PPM images\0*.ppm\0" "XPM images\0*.xpm\0" "IFF ILBM images\0*.lbm\0" "EPS figures\0*.eps\0" "PostScript documents\0*.ps\0" "PDF figures\0*.pdf\0" "XWD screen shots\0*.xwd\0" // "PAM images\0*.pam\0" "Image meta information\0*.meta\0" "Targa TGA images\0*.tga\0" "PCX images\0*.pcx\0" "Windows BMP bitmaps\0*.bmp\0" "All files (*)\0*\0"; static void do_open(void) { OPENFILENAME ofn; // ZeroMemory(&ofn, sizeof(ofn)); char szFileName[MAX_PATH]; szFileName[0]='\0'; ofn.lpstrTitle="Open image with sam2p"; ofn.lStructSize = sizeof(ofn); // SEE NOTE BELOW ofn.hwndOwner = NULL; // hwnd; ofn.lpstrFilter=loadImageFilter; ofn.lpstrDefExt=NULL; ofn.lpstrFile = szFileName; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST /*|OFN_HIDEREADONLY*/ |OFN_EXTENSIONDIFFERENT /*|OFN_NODEREFERENCELINKS*/ |OFN_READONLY; ofn.lpstrDefExt = "txt"; ofn.hInstance=NULL; ofn.lpstrCustomFilter=NULL; // !! ofn.nMaxCustFilter=0; // !! ofn.nFilterIndex=0; // use Custom Filter ofn.lpstrFileTitle=NULL; ofn.nMaxFileTitle=0; ofn.lpstrInitialDir=NULL; // use current directory ofn.nFileOffset=0; ofn.nFileExtension=0; ofn.lCustData=NULL; ofn.lpfnHook=NULL; ofn.lpTemplateName=NULL; // MessageBox(NULL, "hello", "world", 0); if (GetOpenFileName(&ofn)) { do_open_image(szFileName); } } static void do_new(void) { if (imgf!=NULL) { if (filename2!=NULL) filename2[0]='-'; if (imgr!=NULL) { delete imgr; imgr=NULL; } delete imgf; imgf=NULL; #if 0 if (filename2!=NULL) { delete [] filename2; filename2=NULL; } SetWindowText(hwnd_main, Error::banner0); #endif SetWindowLong(hwnd_main, GWL_STYLE, GetWindowLong(hwnd_main, GWL_STYLE)|WS_THICKFRAME); /* ^^^ The Win32 API way to say hwnd_main.setResizable(true); :-) */ InvalidateRect(hwnd_main, NULL, TRUE); // SetWindowPos(hwnd_main, NULL, 0, 0, wd_def, ht_def, SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); /* ^^^ Do _not_ revert to default window size */ SendMessage(hwnd_main, WM_SIZE, 0, 0); /* calls updateBgText() */ } else if (wd_last!=0 || ht_last!=0) { if (filename2!=NULL) { delete [] filename2; filename2=NULL; } SetWindowText(hwnd_main, Error::banner0); wd_last=0; ht_last=0; SendMessage(hwnd_main, WM_SIZE, 0, 0); /* calls updateBgText() */ } } /** Rectangle to draw the background text into */ static RECT bgRect={0,0,0,0}; static char bgText[128]; /** @param hwnd hwnd_main */ static void updateBgText(HWND hwnd, slen_t x, slen_t y) { RECT rt; HDC hdc=GetDC(hwnd); GetClientRect(hwnd, &rt); bgRect=rt; sprintf(bgText, "%s\n%lu\327%lu", Error::banner0, x+0UL, y+0UL); // DrawText(hdc, msg, strlen(msg), &rt, DT_CENTER|DT_VCENTER|DT_SINGLELINE); int textht=DrawText(hdc, bgText, -1, &rt, DT_CENTER|DT_CALCRECT); bgRect.top+=(bgRect.bottom-bgRect.top-textht)/2; ReleaseDC(hwnd, hdc); } //void CDECL AfxTrace(LPCTSTR lpszFormat, ...); /** Processes messages for the main window. */ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; RECT *rp, rt; int i; switch (message) { case WM_PAINT: if (first_paint_p) { first_paint_p=false; // LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING); } hdc = BeginPaint(hwnd, &ps); if (imgf==NULL) { /* no image is loaded yet */ DrawText(hdc, bgText, -1, &bgRect, DT_CENTER); } else { GetClientRect(hwnd, &rt); bool xbad=0U+rt.right-rt.left>imgf->getWd(), ybad=0U+rt.bottom-rt.top>imgf->getHt(); if (ps.fErase && (xbad || ybad)) { /* Erase only region not part of the image; to avoid flicker */ // HDC hdc=GetDC(hwnd); // HBRUSH hbrush=(HBRUSH)GetClassLong(hwnd, GCL_HBRBACKGROUND); HBRUSH hbrush=(HBRUSH)GetStockObject(WHITE_BRUSH); HGDIOBJ holdbrush=SelectObject(hdc, hbrush); HPEN hpen=(HPEN)GetStockObject(WHITE_PEN); /* always used */ HGDIOBJ holdpen=SelectObject(hdc, hpen); Rectangle(hdc, imgf->getWd(), rt.top, rt.right, rt.bottom); Rectangle(hdc, rt.left, imgf->getHt(), imgf->getWd(), rt.bottom); SelectObject(hdc, holdpen); SelectObject(hdc, holdbrush); // ReleaseDC(hwnd, hdc); } // if (imgf==NULL) imgf=new WinFastImage(hdc, imgr->getHbitmap()); // rt.right-=rt.left; rt.bottom-=rt.top; imgf->drawTo(hdc, rt.left, rt.top); if (xbad) { /* show the borders of the image inside the window */ MoveToEx(hdc, rt.left+imgf->getWd(), rt.top, NULL); LineTo(hdc, rt.left+imgf->getWd(), rt.bottom-1); LineTo(hdc, rt.right-1, rt.top); } if (ybad) { /* show the borders of the image inside the window */ MoveToEx(hdc, rt.left, imgf->getHt()+rt.top, NULL); LineTo(hdc, rt.left+imgf->getWd(), rt.bottom-1); LineTo(hdc, rt.left, imgf->getHt()+rt.top); } } EndPaint(hwnd, &ps); return 0; case WM_COMMAND: /* int wmId=LOWORD(wParam), wmEvent=HIWORD(wParam); */ switch (LOWORD(wParam)) { case IDM_SAVE: do_save(true); return 0; case IDM_SAVE_AS: { char *argv[]={"(progname)","pts.ppm","pts.ps",NULL}; int argc=3; char result[30]; int ret=main(argc, argv); // int ret=getpid(); sprintf(result, "main run: %d", ret); MessageBox(hwnd, result, NULL, 0); /* unreached !! */ } do_save_as(); return 0; case IDM_WEBSITE: /* Dat: it seems to be impossible to force the browser to open the URL * in a new window (instead of overwriting the current window). There * are OLE/DDE solutions for Netscape4 and Internet Explorer, but no * generic solution. */ ShellExecute(hwnd, "open", "http://www.inf.bme.hu/~pts/sam2p/", 0, 0, SW_SHOWDEFAULT); return 0; case IDM_ABOUT: DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hwnd, (DLGPROC)About); return 0; case IDM_OPEN: do_open(); return 0; case IDM_NEW: do_new(); return 0; case IDM_PARAMETERS: DialogBox(hInst, (LPCTSTR)IDD_RUN, hwnd, (DLGPROC)dialogRun); return 0; case IDM_EXIT: do_exit(); return 0; default: MessageBox(hwnd,"Unimplemented.", Error::banner0, 0); return 0; } case WM_SIZING: /* possibly override resize requests */ if (imgf!=NULL) { /* resize the window to perfectly fit the image */ rp=(RECT*)lParam; // RECT wr; GetWindowRect(hwnd, &wr); // RECT cr; GetClientRect(hwnd, &cr); // rp->right=rp->left+imgf->getWd()+(wr.right-wr.left)-(cr.right-cr.left); // rp->bottom=rp->top+imgf->getHt()+(wr.bottom-wr.top)-(cr.bottom-cr.top); getFrameSize(hwnd, rp->right, rp->bottom); rp->right+=rp->left+imgf->getWd(); rp->bottom+=rp->top+imgf->getHt(); return TRUE; } else return FALSE; case WM_ERASEBKGND: if (imgf!=NULL) return FALSE; break; /* Dat: upon window resize, WM_SIZING, WM_SIZE, WM_ERASEBKGND and WM_PAINT is sent in this order */ case WM_SIZE: /* we have been resized; let's invalidate the window contents */ GetClientRect(hwnd, &rt); if (wd_last==0 && ht_last==0) updateBgText(hwnd, rt.right-rt.left, rt.bottom-rt.top); else updateBgText(hwnd, wd_last, ht_last); InvalidateRect(hwnd, NULL, TRUE); return 0; case WM_CLOSE: /* user has clicked button X on the title bar; confirm exit first */ do_exit(); return 0; case WM_DESTROY: /* exit already confirmed */ PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); } #if 0 char *s="1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"; #endif // Mesage handler for about box. LRESULT CALLBACK About(HWND hdlg, UINT message, WPARAM wParam, LPARAM /*lParam*/) { switch (message) { case WM_INITDIALOG: { HFONT hfont=CreateFont(10, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 0, /*"System"*/ "MS Sans Serif"); SendMessage(GetDlgItem(hdlg, IDC_PRODUCT), WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); // !! DeleteObject SetDlgItemText(hdlg, IDC_PRODUCT, Error::banner0); SetDlgItemText(hdlg, IDC_INFO, "This is the Win32 GUI of sam2p.\r\n" " sam2p is a UNIX command line utility written in ANSI C++ that converts many " "raster (bitmap) image formats into Adobe PostScript or PDF files and several " "other formats. The images " "are not vectorized. sam2p gives full control to the user to specify " "standards-compliance, compression, and bit depths. In some cases sam2p can " "compress an image 100 times smaller than the PostScript output of many other " "common image converters. sam2p provides ZIP, RLE and LZW (de)compression " "filters even on Level1 devices.\r\n"); } return TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { { CHOOSEFONT cf; ZeroMemory(&cf, sizeof(cf)); cf.lStructSize=sizeof(cf); cf.rgbColors=0; /* black */ cf.Flags=CF_EFFECTS|CF_FORCEFONTEXIST|CF_NOSIMULATIONS|CF_NOVERTFONTS|CF_SCREENFONTS; cf.hwndOwner=NULL; cf.hDC=NULL; ChooseFont(&cf); } EndDialog(hdlg, LOWORD(wParam)); return TRUE; } break; } return FALSE; } LRESULT CALLBACK dialogRun(HWND hdlg, UINT message, WPARAM wParam, LPARAM /*lParam*/) { switch (message) { case WM_INITDIALOG: { HWND hwnd=GetDlgItem(hdlg, IDC_ELOG); HFONT hfont=CreateFont(10, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0,"Fixedsys"); SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); // DeleteObject(hfont); /* Imp: where to do DeleteObject()? */ /* PostMessage doesn't work, either */ unsigned i; char buf[222]; for (i=0;i<100;i++) { SendMessage(hwnd,EM_SETSEL,0U-1,0U-1); sprintf(buf, "%d Hello, World! 0123456789 1111111111 222222222 333333333\r\n", i); SendMessage(hwnd,EM_REPLACESEL,FALSE,(LPARAM)(LPCTSTR)buf); } SendMessage(hwnd,EM_SCROLLCARET,0,0); InvalidateRect(hwnd,NULL,FALSE); /* no effect */ // !! EM_REPLACESEL doesn't make the end of the edit box text } return TRUE; #if 0 case WM_ACTIVATE: { // HWND hwnd=GetDlgItem(hdlg, IDC_ELOG); // MessageBox(NULL,"Hello","",0); //SendMessage(hwnd,EM_SETSEL,-1,2000); //SendMessage(hwnd,EM_SCROLLCARET,0,0); //InvalidateRect(hwnd,NULL,FALSE); /* no effect */ } return TRUE; #endif case WM_COMMAND: if (LOWORD(wParam) == IDOK) { HWND hwnd=GetDlgItem(hdlg, IDC_ELOG); SendMessage(hwnd,EM_SETSEL,0xFFFFFFFF,-1); SendMessage(hwnd,EM_REPLACESEL,FALSE,(LPARAM)(LPCTSTR)"Append."); break; } if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hdlg, LOWORD(wParam)); return TRUE; } break; } return FALSE; }