//---------------------------------------------------------------------------- // ObjectWindows - (C) Copyright 1991, 1993 by Borland International // Example program that shows Dibs, Bitmaps and Palettes in a scrolling // Window. Also uses diagnostics to trace thru some routines //---------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include #include "bmpview.h" DIAG_DEFINE_GROUP_INIT(OWL_INI, BmpView, 1, 0); #define USE_DDB // Use a DDB, else blts the DIB directly to the screen //#define PAINT_ICON // define to paint the icon from the bitmap #define MAXAPPNAME 20 static const char AppName[] = "BitmapView"; // // TBmpViewWindow, a Bitmap displaying window derived from TClipboardViewer to // facilitate receiving of clipboard change notifications. Could mix it in if // an additional base was desired. // class TBmpViewWindow : virtual public TWindow, public TClipboardViewer { public: char FileName[MAXPATH]; TDib* Dib; #if defined(USE_DDB) TBitmap* Bitmap; #endif TPalette* Palette; TBrush* BkgndBrush; long Rop; int PixelWidth; int PixelHeight; WORD Colors; BOOL Fit; BOOL AutoClipView; TBmpViewWindow(); ~TBmpViewWindow(); protected: void CmFileOpen(); void CmRead1(); void CmRead2(); void CmReadBad(); void CmCopy(); void CmPaste(); void CmFit(); void CmAutoClipView(); void CeCopy(TCommandEnabler& ce); void CePaste(TCommandEnabler& ce); void CeFit(TCommandEnabler& ce); void CeAutoClipView(TCommandEnabler& ce); void Paint(TDC&, BOOL erase, TRect&); void EvSize(UINT sizeType, TSize&); void EvPaletteChanged(HWND hWndPalChg); BOOL EvQueryNewPalette(); void EvSetFocus(HWND); // should use above when working void EvDrawClipboard(); void EvDestroy(); BOOL UpdatePalette(BOOL alwaysRepaint); void AdjustScroller(); void SetCaption(const char*); void SetupFromDib(TDib* dib); BOOL LoadBitmapFile(const char*); BOOL LoadBitmapResource(WORD ResId); DECLARE_RESPONSE_TABLE(TBmpViewWindow); }; DEFINE_RESPONSE_TABLE2(TBmpViewWindow, TClipboardViewer, TWindow) EV_COMMAND(CM_FILEOPEN, CmFileOpen), EV_COMMAND(CM_READ1, CmRead1), EV_COMMAND(CM_READ2, CmRead2), EV_COMMAND(CM_READBAD, CmReadBad), EV_COMMAND(CM_EDITCOPY, CmCopy), EV_COMMAND(CM_EDITPASTE, CmPaste), EV_COMMAND(CM_FIT, CmFit), EV_COMMAND(CM_AUTOCLIPVIEW, CmAutoClipView), EV_COMMAND_ENABLE(CM_EDITCOPY, CeCopy), EV_COMMAND_ENABLE(CM_EDITPASTE, CePaste), EV_COMMAND_ENABLE(CM_FIT, CeFit), EV_COMMAND_ENABLE(CM_AUTOCLIPVIEW, CeAutoClipView), EV_WM_SIZE, EV_WM_PALETTECHANGED, EV_WM_QUERYNEWPALETTE, EV_WM_SETFOCUS, EV_WM_DRAWCLIPBOARD, EV_WM_DESTROY, END_RESPONSE_TABLE; // // Constructor for a TBmpViewWindow, sets scroll styles and constructs // the Scroller object. Also sets the Rop based on whether the display // is monochrome (two-color) or polychrome. // TBmpViewWindow::TBmpViewWindow() : TWindow(0, 0, 0), TClipboardViewer() { // Init TWindow since TClipboardViewer is usually a mixin and doesn't do it // // Init(0, 0, 0); Attr.Style |= WS_VSCROLL | WS_HSCROLL; Dib = 0; #if defined(USE_DDB) Bitmap = 0; #endif Palette = 0; BkgndBrush = new TBrush(::GetSysColor(COLOR_WINDOW)); Scroller = new TScroller(this, 1, 1, 200, 200); Fit = FALSE; AutoClipView = FALSE; TScreenDC screenDC; if (screenDC.GetDeviceCaps(NUMCOLORS) < 3 ) Rop = NOTSRCCOPY; else Rop = SRCCOPY; SetCaption(0); } TBmpViewWindow::~TBmpViewWindow() { #if defined(USE_DDB) delete Bitmap; #endif delete Palette; delete Dib; delete BkgndBrush; } // // Build up a caption based on a filename, and set it into the title. // void TBmpViewWindow::SetCaption(const char* name) { char caption[MAXPATH + MAXAPPNAME + 2 + 1]; strcpy(FileName, name ? name : "(Untitled)"); strcpy(caption, GetApplication()->GetName()); strcat(caption, " - "); strcat(caption, FileName); if (Parent) Parent->SetCaption(caption); } // // Make a metafile & put it on the clipboard. // Make a copy of each of the objects & place the copies on the clipboard // void TBmpViewWindow::CmCopy() { TClipboard& clipboard = OpenClipboard(); if (clipboard.EmptyClipboard()) { TMetaFileDC mfDC; mfDC.SetWindowExt(Dib->Size()); mfDC.SetWindowOrg(0, 0); mfDC.SetDIBitsToDevice(TRect(0,0, PixelWidth, PixelHeight), TPoint(0,0), *Dib); TMetaFilePict mf(mfDC.Close(), AutoDelete); mf.ToClipboard(clipboard, MM_TEXT, TSize(PixelWidth, PixelHeight)); TPalette(*Palette).ToClipboard(clipboard); TDib(*Dib).ToClipboard(clipboard); #if defined(USE_DDB) TBitmap(*Bitmap).ToClipboard(clipboard); #endif clipboard.CloseClipboard(); } } void TBmpViewWindow::CeCopy(TCommandEnabler& ce) { ce.Enable(Dib != 0); } // // When a user selects edit.paste, get the data from the clipboard. This // routine prefers CF_META over CF_DIB over CF_BITMAP // void TBmpViewWindow::CmPaste() { TClipboard& clipboard = OpenClipboard(); if (!clipboard) return; TPalette* newPal = 0; TDib* newDib = 0; TBitmap* newBitmap; // If there is a palette on the clipboard, get it & realize it // if (clipboard.IsClipboardFormatAvailable(CF_PALETTE)) { newPal = new TPalette(TPalette(clipboard)); // make a copy UpdatePalette(TRUE); } // try DIB format 1st // if (clipboard.IsClipboardFormatAvailable(CF_DIB)) { newDib = new TDib(TDib(clipboard)); // make a copy newBitmap = new TBitmap(*newDib, newPal); // newPal==0 is OK // try metafile 2nd // } else if (clipboard.IsClipboardFormatAvailable(CF_METAFILEPICT)) { if (!newPal) newPal = new TPalette((HPALETTE)GetStockObject(DEFAULT_PALETTE)); newBitmap = new TBitmap(TMetaFilePict(clipboard), *newPal, GetClientRect().Size()); #if defined(USE_DDB) // try bitmap (DDB) format 3rd // } else if (clipboard.IsClipboardFormatAvailable(CF_BITMAP)) newBitmap = new TBitmap(TBitmap(clipboard)); // make a copy else return; // Should never happen--this command is enabled by above tests // Got a bitmap & maybe more. Now keep it & setup things. // delete Bitmap; Bitmap = newBitmap; if (!newDib) newDib = new TDib(*newBitmap, newPal); #else } #endif delete Dib; Dib = newDib; delete Palette; Palette = newPal ? newPal : new TPalette(*newDib); Palette->GetObject(Colors); PixelWidth = Dib->Width(); PixelHeight = Dib->Height(); AdjustScroller(); SetCaption("(Clipboard)"); clipboard.CloseClipboard(); // Parent->SetIcon(0, 0); // we'll paint the icon from the bitmap } void TBmpViewWindow::CePaste(TCommandEnabler& ce) { TClipboard& clipboard = OpenClipboard(); ce.Enable( clipboard && ( clipboard.IsClipboardFormatAvailable(CF_METAFILEPICT) || clipboard.IsClipboardFormatAvailable(CF_DIB) || clipboard.IsClipboardFormatAvailable(CF_BITMAP) ) ); clipboard.CloseClipboard(); } // // If either of the "Read bitmap" menu items is selected, then we read // the bitmap resource with the ID of the menu item... // void TBmpViewWindow::CmRead1() { if (LoadBitmapResource(CM_READ1)) SetCaption("(Bitmap resource 1)"); } void TBmpViewWindow::CmRead2() { if (LoadBitmapResource(CM_READ2)) SetCaption("(Bitmap resource 2)"); } void TBmpViewWindow::CmReadBad() { LoadBitmapFile(""); // force a failure for kicks } // // Toggle Fit member variable & adjust scroller as needed // void TBmpViewWindow::CmFit() { Fit = !Fit; AdjustScroller(); } // // The fit menu item is checked if the Fit member is true // void TBmpViewWindow::CeFit(TCommandEnabler& ce) { ce.SetCheck(Fit ? TCommandEnabler::Checked : TCommandEnabler::Unchecked); } // // Toggle AutoAutoClipView member variable // void TBmpViewWindow::CmAutoClipView() { AutoClipView = !AutoClipView; } // // Check AutoClipView according to flag // void TBmpViewWindow::CeAutoClipView(TCommandEnabler& ce) { ce.SetCheck(AutoClipView ? TCommandEnabler::Checked : TCommandEnabler::Unchecked); } // // If the the "Open..." menu item is selected, then we prompt the user // for a new bitmap file. If the user selects one and it is one that // we can read, we display it in the window and change the window's // caption to reflect the new bitmap file. // void TBmpViewWindow::CmFileOpen() { static TOpenSaveDialog::TData data ( OFN_HIDEREADONLY|OFN_FILEMUSTEXIST|OFN_NOREADONLYRETURN, "Bitmap Files (*.BMP)|*.bmp|", 0, "", "BMP" ); if (TFileOpenDialog(this, data).Execute() == IDOK) { char fileTitle[MAXPATH]; TOpenSaveDialog::GetFileTitle(data.FileName, fileTitle, MAXPATH); LoadBitmapFile(fileTitle); SetCaption(strlwr(fileTitle)); } } // // Adjust the Scroller range so that the the origin is the // upper-most scrollable point and the corner is the // bottom-most. // void TBmpViewWindow::AdjustScroller() { TRect clientRect = GetClientRect(); // only show scrollbars when image is larger than // the client area and we are not stretching to fit. // if (Fit) Scroller->SetRange(0, 0); else { TPoint Range(Max(PixelWidth-clientRect.Width(), 0), Max(PixelHeight-clientRect.Height(), 0)); Scroller->SetRange(Range.x, Range.y); } Scroller->ScrollTo(0, 0); if (!GetUpdateRect(clientRect, FALSE)) Invalidate(FALSE); } // // Reset scroller range. // void TBmpViewWindow::EvSize(UINT SizeType, TSize& Size) { TWindow::EvSize(SizeType, Size); if (SizeType != SIZEICONIC) { AdjustScroller(); Invalidate(FALSE); } } // // Somebody changed the palette. If its not us, then we need to update. // void TBmpViewWindow::EvPaletteChanged(HWND hWndPalChg) { if (hWndPalChg != HWindow) UpdatePalette(TRUE); // pass FALSE to UpdateColors() instead of repaint } // // We need to re-realize the logical palette each time // we regain the input focus // BOOL TBmpViewWindow::EvQueryNewPalette() { return UpdatePalette(TRUE); } // // Use this message temporarily until the palette msgs get routed to us // void TBmpViewWindow::EvSetFocus(HWND) { UpdatePalette(TRUE); } void TBmpViewWindow::EvDrawClipboard() { if (TClipboardViewer::DoDrawClipboard() == esComplete) return; if (AutoClipView) CmPaste(); } void TBmpViewWindow::EvDestroy() { if (TClipboardViewer::DoDestroy() == esComplete) return; TWindow::EvDestroy(); } BOOL TBmpViewWindow::UpdatePalette(BOOL alwaysRepaint) { TRACEX(BmpView, 2, "Enter UpdatePalette()"); if (Palette) { TClientDC clientDC(*this); #if !defined(__WIN32__) Palette->UnrealizeObject(); #endif TRACEX(BmpView, 2, "UpdatePalette::Palette: " << hex << (UINT)(HPALETTE)*Palette); clientDC.SelectObject(*Palette, FALSE); if (clientDC.RealizePalette() > 0) if (alwaysRepaint) Invalidate(FALSE); else clientDC.UpdateColors(); TRACEX(BmpView, 2, "Leave UpdatePalette(TRUE)"); return TRUE; } TRACEX(BmpView, 2, "Leave UpdatePalette(FALSE)"); return FALSE; } // // Responds to an incoming Paint message by redrawing the bitmap. // The Scroller's BeginView method, which sets the viewport origin // relative to the present scroll position, has been called by TWindow's // EvPaint // Note that we Invalidate() ourselves with false to avoid the background // paint flicker. Thats why we use // // The code can use either the Bitmap member with Stretch- and Bit- Blts, // or use the Dib member with Stretch- and Set- DIBits... // void TBmpViewWindow::Paint(TDC& dc, BOOL, TRect&) { TRACEX(BmpView, 2, "Enter Paint()"); TRect clientRect = GetClientRect(); TRACEX(BmpView, 2, "Paint::BkBrush: " << hex << (UINT)(HBRUSH)*BkgndBrush); dc.SelectObject(*BkgndBrush); #if defined(USE_DDB) if (Bitmap) { TMemoryDC memoryDC(dc); TRACEX(BmpView, 2, "Paint::Bitmap: " << hex << (UINT)(HBITMAP)*Bitmap); memoryDC.SelectObject(*Bitmap); dc.SetStretchBltMode(COLORONCOLOR); if (Palette) { TRACEX(BmpView, 2, "Paint::Palette: " << hex << (UINT)(HPALETTE)*Palette); dc.SelectObject(*Palette, FALSE); dc.RealizePalette(); memoryDC.SelectObject(*Palette, FALSE); } if (Rop == SRCCOPY) { if (Colors == 2) { if (Palette) { PALETTEENTRY pe; Palette->GetPaletteEntry(0, pe); dc.SetTextColor(TColor(pe)); Palette->GetPaletteEntry(1, pe); dc.SetBkColor(TColor(pe)); } else { dc.SetBkColor(TColor(0,0,0)); dc.SetTextColor(TColor(255,255,255)); } } } #else if (Dib) { #endif TRect imageRect(0,0, PixelWidth, PixelHeight); if (Parent->IsIconic()) { #if defined(USE_DDB) dc.StretchBlt(Parent->GetClientRect(), memoryDC, imageRect, Rop); #else dc.StretchDIBits(Parent->GetClientRect(), imageRect, *Dib, Rop); #endif } else { clientRect += TPoint((int)Scroller->XPos, (int)Scroller->YPos); if (Fit) { #if defined(USE_DDB) dc.StretchBlt(clientRect, memoryDC, imageRect, Rop); #else dc.StretchDIBits(clientRect, imageRect, *Dib); #endif } else { #if defined(USE_DDB) dc.BitBlt(imageRect, memoryDC, TPoint(0,0), Rop); #else dc.SetDIBitsToDevice(imageRect, TPoint(0,0), *Dib); #endif // Clear borders here for no flicker // dc.PatBlt(TRect(TPoint(PixelWidth,0), clientRect.BottomRight())); dc.PatBlt(TRect(TPoint(0,PixelHeight), clientRect.BottomRight())); } } } else dc.PatBlt(clientRect, PATCOPY); TRACEX(BmpView, 2, "Leave Paint()" << endl); } void TBmpViewWindow::SetupFromDib(TDib* dib) { TRACEX(BmpView, 1, "Enter SetupFromDib()"); TRACEX(BmpView, 1, "SetupFromDib::Dib: " << hex << (UINT)(HANDLE)*dib); delete Dib; Dib = dib; delete Palette; Palette = 0; try { Palette = new TPalette(*dib); } catch (...) { MessageBox("Dib has no color table, using default palette", GetApplication()->GetName(), MB_OK); Palette = new TPalette((HPALETTE)::GetStockObject(DEFAULT_PALETTE)); } TRACEX(BmpView, 1, "SetupFromDib::Palette: " << hex << (UINT)(HPALETTE)*Palette); #if defined(USE_DDB) delete Bitmap; Bitmap = new TBitmap(*Dib, Palette); TRACEX(BmpView, 1, "SetupFromDib::Bitmap: " << hex << (UINT)(HBITMAP)*Bitmap); #endif PixelWidth = Dib->Width(); PixelHeight = Dib->Height(); UpdatePalette(TRUE); AdjustScroller(); #if defined(PAINT_ICON) Parent->SetIcon(0, 0); // enable to paint the icon from the bitmap #endif TRACEX(BmpView, 1, "Leave SetupFromDib()"); } // // Test if the passed resource is a Windows 3.0 (or PM 1.x) DI bitmap // and if so read it. // Report errors if unable to do so. Adjust the Scroller to the new // bitmap dimensions. // BOOL TBmpViewWindow::LoadBitmapResource(WORD resId) { TDib* newDib; try { newDib = new TDib(*GetModule(), resId); } catch (TGdiBase::TXGdi) { MessageBox("Cannot access bitmap resource", GetApplication()->GetName(), MB_OK); return FALSE; } SetupFromDib(newDib); return TRUE; } // // Test if the passed file is a Windows 3.0 DI (or PM 1.x) bitmap // and if so read it. // Report errors if unable to do so. Adjust the Scroller to the new // bitmap dimensions. // BOOL TBmpViewWindow::LoadBitmapFile(const char* name) { TDib* newDib; try { newDib = new TDib(name); } catch (TGdiBase::TXGdi) { MessageBox("Cannot open bitmap file", GetApplication()->GetName(), MB_OK); return FALSE; } SetupFromDib(newDib); return TRUE; } //---------------------------------------------------------------------------- class TBmpViewApp : public TApplication { public: TBmpViewApp(const char far* name) : TApplication(name) {} void InitMainWindow() { MainWindow = new TFrameWindow(0, Name, new TBmpViewWindow); MainWindow->AssignMenu(Name); MainWindow->SetIcon(this, Name); } }; //---------------------------------------------------------------------------- int OwlMain(int /*argc*/, char* /*argv*/ []) { return TBmpViewApp(AppName).Run(); }