home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1998 May
/
Pcwk5b98.iso
/
Borland
/
Cplus45
/
BC45
/
PAINT.PAK
/
PAINT.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-29
|
33KB
|
1,273 lines
//----------------------------------------------------------------------------
// ObjectWindows - (C) Copyright 1991, 1993 by Borland International
// Example paint program
//----------------------------------------------------------------------------
#include <owl\owlpch.h>
#include <owl\applicat.h>
#include <owl\dc.h>
#include <owl\gdiobjec.h>
#include <owl\decframe.h>
#include <owl\chooseco.h>
#include <owl\choosefo.h>
#include <owl\opensave.h>
#include <owl\printdia.h>
#include <owl\scroller.h>
#include <owl\controlb.h>
#include <owl\floatfra.h>
#include <owl\toolbox.h>
#include <owl\buttonga.h>
#include <owl\editfile.rh>
#include <stdio.h>
#include <dir.h>
#include "paint.rh"
#include "dibattr.h"
DIAG_DEFINE_GROUP(PaintDrw,1,0); // drawing tracing (set level to 1 for mouse)
DIAG_DEFINE_GROUP(PaintCmd,1,0); // command tracing
//#define USE_TOOLBAR // comment out for floating palette
#define PARALLEL_PEN // to enable parallel line drawing with pen tool
const int DefWidth = 640;
const int DefHeight = 480;
int DefNColors= 0; // fill in with screen device info
const int DefPenSize= 3;
const TColor DefPalette[] = {
0x000000L, 0xFFFFFFL, 0x7F7F7FL, 0xC0C0C0L,
0x00007FL, 0x007F00L, 0x007F7FL, 0x7F0000L, 0x7F007FL, 0x7F7F00L,
0x0000FFL, 0x00FF00L, 0x00FFFFL, 0xFF0000L, 0xFF00FFL, 0xFFFF00L,
};
const int CM_TOOL = 300;
const int CM_LINE = 400;
const int ToolCount = 6;
const int ID_CANVAS = 101;
const int ID_PALETTE= 102;
#if defined(USE_LINEBAR)
const int LineCount = 8;
const int LineBarWidth = LineCount * 4 + 6 + (1 + 2 + 3 + 4 + 5 + 7 + 9 + 12);
const int LineWidth[LineCount] = { 1, 2, 3, 4, 5, 7, 9, 12 };
#endif
//----------------------------------------------------------------------------
class TDrawTool;
struct TState {
TDrawTool* DrawTool;
TDC* DC;
TPalette* Palette;
TDib* Dib;
TBitmap* Bitmap;
int PenSize;
int FgColor;
int BgColor;
string Name;
string Title;
BOOL Modified;
};
class TDrawTool {
public:
TDrawTool(const char* name);
void MouseDown(TWindow& window, const TPoint& point, TState* state);
void MouseMove(const TPoint& Point);
void MouseUp();
virtual void DrawBegin(const TPoint& point) {}
virtual void DrawTo(const TPoint& point) {}
virtual void DrawEnd() {}
const char* GetName() {return Name;}
protected:
TCursor* Cursor;
TIcon* Icon;
TState* State;
TWindow* Window;
TPen* Pen;
TBrush* Brush;
TDC* DC;
TPoint LastPoint;
TRect Bounds;
private:
const char* Name;
};
class TPenTool : public TDrawTool {
public:
TPenTool(const char* name) : TDrawTool(name) {}
virtual void DrawBegin(const TPoint& point);
virtual void DrawTo(const TPoint& point);
virtual void DrawEnd();
protected:
#if defined(PARALLEL_PEN)
TPalette* TmpPalette;
#endif
};
class TFillTool : public TDrawTool {
public:
TFillTool(const char* name) : TDrawTool(name) {}
virtual void DrawBegin(const TPoint& point);
};
class TBoxTool : public TDrawTool {
public:
TBoxTool(const char* name, BOOL filled)
: TDrawTool(name), Filled(filled) {}
virtual void DrawBegin(const TPoint& point);
virtual void DrawTo(const TPoint& point);
virtual void DrawEnd();
virtual void DrawObject(TDC& dc) {}
protected:
BOOL Filled;
int X1;
int Y1;
int X2;
int Y2;
};
class TRectTool : public TBoxTool {
public:
TRectTool(const char* name, BOOL filled) : TBoxTool(name, filled) {}
virtual void DrawObject(TDC& dc);
};
class TEllipseTool : public TBoxTool {
public:
TEllipseTool(const char* name, BOOL filled) : TBoxTool(name, filled) {}
virtual void DrawObject(TDC& dc);
};
//----------------------------------------------------------------------------
class TPaletteWindow : public TWindow {
public:
TPaletteWindow(TWindow* parent, TState* state);
void SelectColor(TPoint& point, int& color);
protected:
void Paint(TDC&, BOOL, TRect&);
void EvSize(UINT, TSize&);
void EvLButtonDown(UINT modKeys, TPoint& point);
void EvLButtonDblClk(UINT modKeys, TPoint&);
void EvRButtonDown(UINT modKeys, TPoint& point);
void EvRButtonDblClk(UINT modKeys, TPoint& point);
LRESULT EvSetRGB(WPARAM, LPARAM);
private:
TState* State;
BOOL Horz;
int Cx; // Count of panes in the X direction
int Cy; // Count of panes in the Y direction
int Dx; // Size of a pane in the X direction
int Dy; // Size of a pane in the Y direction
DECLARE_RESPONSE_TABLE(TPaletteWindow);
};
DEFINE_RESPONSE_TABLE1(TPaletteWindow, TWindow)
EV_WM_SIZE,
EV_WM_LBUTTONDOWN,
EV_WM_LBUTTONDBLCLK,
EV_WM_RBUTTONDOWN,
EV_WM_RBUTTONDBLCLK,
EV_REGISTERED(SETRGBSTRING, EvSetRGB),
END_RESPONSE_TABLE;
//----------------------------------------------------------------------------
//
// A slightly customized floating frame for use as our tool & style button
// palettes.
//
class TButtonPalette : public TFloatingFrame {
public:
TButtonPalette(TWindow* parent,
char* title = 0,
TWindow* clientWnd = 0,
TModule* module = 0);
private:
void SetupWindow();
void CleanupWindow();
void EvClose();
DECLARE_RESPONSE_TABLE(TButtonPalette);
};
DEFINE_RESPONSE_TABLE1(TButtonPalette, TFloatingFrame)
EV_WM_CLOSE,
END_RESPONSE_TABLE;
TButtonPalette::TButtonPalette(TWindow* parent, char* title, TWindow* clientWnd,
TModule* module)
: TFloatingFrame(parent, title, clientWnd, TRUE, DefaultCaptionHeight, TRUE, module)
{
}
//
// Supply a reasonable startup position relative to our Parent (owner actually)
//
void
TButtonPalette::SetupWindow()
{
TFloatingFrame::SetupWindow();
if (Attr.X < 0 || Attr.Y < 0) {
TRect parentRect;
Parent->GetWindowRect(parentRect);
SetWindowPos(0, parentRect.left+10, parentRect.top+10, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}
}
//
// Remember latest position when we are destroyed
//
void
TButtonPalette::CleanupWindow()
{
TRect rect;
GetWindowRect(rect);
Attr.X = rect.left;
Attr.Y = rect.top;
TFloatingFrame::CleanupWindow();
}
//
// Override EvClose to keep TWindow from having us deleted
//
void
TButtonPalette::EvClose()
{
CloseWindow();
}
//----------------------------------------------------------------------------
#if defined(USE_LINEBAR)
class TLineBar : public TWindow {
public:
TLineBar(TWindow* parent, TState* state);
void Paint(TDC&, BOOL, TRect&);
void EvLButtonDown(UINT modKeys, TPoint& point);
private:
TState* State;
void Notch(TDC& dc, int x, int w, int y, int dy);
DECLARE_RESPONSE_TABLE(TLineBar);
};
DEFINE_RESPONSE_TABLE1(TLineBar, TWindow)
EV_WM_LBUTTONDOWN,
END_RESPONSE_TABLE;
#endif
//----------------------------------------------------------------------------
class TCanvas : public TWindow {
public:
TCanvas();
~TCanvas();
TState State;
protected:
// Override TWindow virtuals
//
void SetupWindow();
BOOL CanClose();
BOOL AbandonOk();
void SetupDib(TDib* dib, const char* fileName, const char* fileTitle);
void NewDib(int width, int height, int nColors);
void OpenDib(const char* fileName, const char* fileTitle);
BOOL SaveDib(const char* fileName);
void UpdateCaption();
void AdjustScroller();
void Paint(TDC&, BOOL, TRect&);
void EvSize(UINT, TSize&);
BOOL EvEraseBkgnd(HDC hDC);
void EvLButtonDown(UINT modKeys, TPoint& point);
void EvLButtonUp(UINT modKeys, TPoint& point);
void EvMouseMove(UINT modKeys, TPoint& point);
void EvDropFiles(TDropInfo dropInfo);
void EvSysColorChange();
void CmFileNew();
void CmFileOpen();
void CmFileSave();
void CmFileSaveAs();
void CmFilePrint();
void CmFilePrintSetup();
void CmViewTools();
void CeViewTools(TCommandEnabler& ce);
void CmViewLines();
void CeViewLines(TCommandEnabler& ce);
void CmTool(WPARAM);
void CmLine(WPARAM);
TPrintDialog::TData PrintData;
private:
BOOL Drawing;
TBrush* BkBrush;
TDrawTool* Tools[ToolCount];
TButtonPalette* ToolsPal;
TButtonPalette* LinesPal;
DECLARE_RESPONSE_TABLE(TCanvas);
};
DEFINE_RESPONSE_TABLE1(TCanvas, TWindow)
EV_WM_ERASEBKGND,
EV_WM_SIZE,
EV_WM_LBUTTONDOWN,
EV_WM_LBUTTONUP,
EV_WM_MOUSEMOVE,
EV_WM_DROPFILES,
EV_WM_SYSCOLORCHANGE,
EV_COMMAND_AND_ID(CM_TOOL+0, CmTool),
EV_COMMAND_AND_ID(CM_TOOL+1, CmTool),
EV_COMMAND_AND_ID(CM_TOOL+2, CmTool),
EV_COMMAND_AND_ID(CM_TOOL+3, CmTool),
EV_COMMAND_AND_ID(CM_TOOL+4, CmTool),
EV_COMMAND_AND_ID(CM_TOOL+5, CmTool),
EV_COMMAND_AND_ID(CM_LINE+1, CmLine),
EV_COMMAND_AND_ID(CM_LINE+3, CmLine),
EV_COMMAND_AND_ID(CM_LINE+5, CmLine),
EV_COMMAND_AND_ID(CM_LINE+7, CmLine),
EV_COMMAND_AND_ID(CM_LINE+9, CmLine),
EV_COMMAND_AND_ID(CM_LINE+11, CmLine),
EV_COMMAND(CM_FILENEW, CmFileNew),
EV_COMMAND(CM_FILEOPEN, CmFileOpen),
EV_COMMAND(CM_FILESAVE, CmFileSave),
EV_COMMAND(CM_FILESAVEAS, CmFileSaveAs),
EV_COMMAND(CM_FILEPRINT, CmFilePrint),
EV_COMMAND(CM_FILEPRINTERSETUP, CmFilePrintSetup),
EV_COMMAND(CM_VIEWTOOLS, CmViewTools),
EV_COMMAND_ENABLE(CM_VIEWTOOLS, CeViewTools),
EV_COMMAND(CM_VIEWLINES, CmViewLines),
EV_COMMAND_ENABLE(CM_VIEWLINES, CeViewLines),
END_RESPONSE_TABLE;
// --------------- TDrawTool ------------------------
TDrawTool::TDrawTool(const char* name)
: State(0), Window(0), Pen(0), Brush(0), DC(0)
{
Name = name;
}
void
TDrawTool::MouseDown(TWindow& window, const TPoint& point, TState* state)
{
TRACEX(PaintDrw,0,"Draw " << GetName() <<
" started at (" << point.x << "," << point.y << ")");
Window = &window;
State = state;
Window->SetCapture();
DC = new TClientDC(window);
Pen = new TPen(TColor(State->FgColor), State->PenSize);
Brush = new TBrush(TColor(State->BgColor));
State->DC->SelectObject(*State->Palette);
State->DC->RealizePalette();
State->DC->SelectObject(*Pen);
State->DC->SelectObject(*Brush);
LastPoint = point;
Bounds = TRect(point, point);
DrawBegin(point);
}
void
TDrawTool::MouseMove(const TPoint& point)
{
TRACEX(PaintDrw,1,"Draw " << GetName() <<
" extends to (" << point.x << "," << point.y << ")");
Bounds |= TRect(point.x, point.y, point.x, point.y);
DrawTo(point);
LastPoint = point;
}
void
TDrawTool::MouseUp()
{
TRACEX(PaintDrw,1,"Draw " << GetName() << " finished");
DrawEnd();
Window->ReleaseCapture();
State->DC->RestoreObjects();
delete Brush; Brush = 0;
delete Pen; Pen = 0;
delete DC; DC = 0;
State->Modified = TRUE;
Window->InvalidateRect(Bounds.
InflatedBy((State->PenSize+1)/2,(State->PenSize+1)/2), FALSE);
Window->UpdateWindow();
}
// --------------- TPenTool ------------------------
void
TPenTool::DrawBegin(const TPoint& point)
{
State->DC->MoveTo(point);
// Do parallel update onto screen
//
#if defined(PARALLEL_PEN)
// can't select a palette into to different device DCs
TmpPalette = new TPalette(*State->Dib);
DC->IntersectClipRect(TRect(TPoint(0,0), State->Dib->Size()));
DC->SelectObject(*TmpPalette);
DC->RealizePalette();
DC->SelectObject(*Pen);
DC->MoveTo(point);
#endif
}
void
TPenTool::DrawTo(const TPoint& point)
{
State->DC->LineTo(point);
#if defined(PARALLEL_PEN)
DC->LineTo(point);
#else
Window->InvalidateRect(TRect(LastPoint, point).Normalized().
InflatedBy((State->PenSize+1)/2,(State->PenSize+1)/2),FALSE);
Window->UpdateWindow();
#endif
}
void
TPenTool::DrawEnd()
{
State->DC->RestorePen();
#if defined(PARALLEL_PEN)
DC->RestorePen();
delete TmpPalette; TmpPalette = 0;
#endif
}
// --------------- TFillTool ------------------------
void
TFillTool::DrawBegin(const TPoint& point)
{
TBrush fgBrush(State->FgColor);
State->DC->SelectObject(fgBrush);
TColor surfaceColor(State->DC->GetPixel(point));
State->DC->ExtFloodFill(point, surfaceColor, FLOODFILLSURFACE);
Bounds = Window->GetClientRect();
State->DC->RestoreBrush();
}
// --------------- TBoxTool ------------------------
void
TBoxTool::DrawBegin(const TPoint& point)
{
X1 = X2 = point.x;
Y1 = Y2 = point.y;
DC->SelectStockObject(BLACK_PEN);
DC->SelectStockObject(NULL_BRUSH);
DC->SetROP2(R2_NOT);
DrawObject(*DC);
}
void
TBoxTool::DrawTo(const TPoint& point)
{
DrawObject(*DC);
X2 = point.x;
Y2 = point.y;
DrawObject(*DC);
}
void
TBoxTool::DrawEnd()
{
DrawObject(*DC);
DC->SetROP2(R2_COPYPEN);
State->DC->SelectObject(*Pen);
if (Filled)
State->DC->SelectObject(*Brush);
else
State->DC->SelectStockObject(NULL_BRUSH);
DrawObject(*State->DC);
}
// --------------- TRectTool ------------------------
void
TRectTool::DrawObject(TDC& dc)
{
dc.Rectangle(X1, Y1, X2, Y2);
}
// --------------- TEllipseTool ------------------------
void
TEllipseTool::DrawObject(TDC& dc)
{
dc.Ellipse(X1, Y1, X2, Y2);
}
// --------------- TPaletteWindow ------------------------
TPaletteWindow::TPaletteWindow(TWindow* parent, TState* state)
: TWindow(parent),
State(state)
{
Attr.Style |= WS_BORDER;
Attr.W = 50;
Attr.H = 50;
Attr.Id = ID_PALETTE;
}
void
TPaletteWindow::EvSize(UINT, TSize&)
{
TRect rect = GetClientRect();
Horz = TRUE; // Location==Top || Location==Bottom;
Cx = (Horz ? 17 : 3);
Cy = (Horz ? 3 : 17);
Dx = rect.right / Cx;
Dy = rect.bottom / Cy;
if (Horz)
Cx--;
else
Cy--;
Invalidate(FALSE);
}
void
TPaletteWindow::Paint(TDC& dc, BOOL, TRect&)
{
dc.SelectObject(*State->Palette);
dc.RealizePalette();
TRect rect = GetClientRect();
dc.SelectStockObject(BLACK_PEN);
// Paint color selection cells, each with a black frame
//
for (int i = 0; i < 16; i++)
for (int j = 0; j < 3; j++) {
TBrush brush(TColor(j*16+i));
dc.SelectObject(brush);
TPoint p = Horz ? TPoint(i*Dx, j*Dy) : TPoint(j*Dx, i*Dy);
dc.Rectangle(p, TSize(Dx+1, Dy+1));
dc.RestoreBrush();
}
// Paint pen & brush color display, frame first
//
dc.SelectStockObject(NULL_BRUSH);
TPoint p = Horz ? TPoint(Dx*16, 0) : TPoint(0, Dy*16);
dc.Rectangle(p, rect.BottomRight());
TPen pen(TColor(State->BgColor), 5);
dc.SelectObject(pen);
TBrush brush(TColor(State->FgColor));
dc.SelectObject(brush);
p += TSize(3,3);
dc.Rectangle(p, TPoint(rect.right-3, rect.bottom-3));
dc.RestoreObjects();
}
void
TPaletteWindow::SelectColor(TPoint& point, int& color)
{
point.x /= Dx;
point.y /= Dy;
if (point.x < Cx && point.y < Cy) {
int newColor = Horz ? point.x + point.y*Cx : point.x*Cy + point.y;
if (color != newColor) {
TColor c = State->Dib->GetColor(newColor);
InvalidateRect(Horz ? TRect(TPoint(Dx*Cx, 0), GetClientRect().BottomRight()) :
TRect(TPoint(0, Dy*Cy), GetClientRect().BottomRight()),
FALSE);
color = newColor;
}
}
}
void
TPaletteWindow::EvLButtonDown(UINT, TPoint& point)
{
SelectColor(point, State->FgColor);
}
void
TPaletteWindow::EvLButtonDblClk(UINT, TPoint& point)
{
static TColor CustColors[32];
int editColor = -1;
SelectColor(point, editColor);
if (editColor < 0)
return;
TChooseColorDialog::TData choose;
choose.Flags = CC_RGBINIT;
PALETTEENTRY pe;
State->Palette->GetPaletteEntry((WORD)editColor, pe);
choose.Color = pe;
choose.CustColors = CustColors;
if (TChooseColorDialog(this, choose).Execute() == IDOK) {
State->Dib->SetColor(editColor, choose.Color);
delete State->Palette;
State->Palette = new TPalette(*State->Dib);
Invalidate(FALSE);
TWindow* canvas = Parent->ChildWithId(ID_CANVAS);
if (canvas && canvas->HWindow)
canvas->Invalidate(FALSE);
}
}
void
TPaletteWindow::EvRButtonDown(UINT, TPoint& point)
{
SelectColor(point, State->BgColor);
}
void
TPaletteWindow::EvRButtonDblClk(UINT modKeys, TPoint& point)
{
EvLButtonDblClk(modKeys, point);
}
LRESULT
TPaletteWindow::EvSetRGB(WPARAM, LPARAM)
{
Invalidate(FALSE);
return 0;
}
#if defined(USE_LINEBAR)
// --------------- TLineBar ------------------------
TLineBar::TLineBar(TWindow* parent, TState* state)
: TWindow(parent),
State(state)
{
Attr.Style |= WS_BORDER;
Attr.W = 32;
Attr.H = 32;
}
void
TLineBar::Notch(TDC& dc, int x, int w, int y, int dy)
{
for (int l = 3; l >= 0; l--) {
dc.MoveTo(TPoint(x + w / 2 - l, y));
dc.LineTo(TPoint(x + w / 2 + l + 1, y));
y += dy;
}
}
void
TLineBar::Paint(TDC& dc, BOOL, TRect&)
{
int x = 4;
dc.SelectStockObject(WHITE_BRUSH);
dc.PatBlt(TRect(0, 0, Attr.W, Attr.H));
dc.SelectStockObject(BLACK_BRUSH);
for (int i = 0; i < LineCount; i++) {
int w = LineWidth[i];
dc.PatBlt(TRect(x, 5, x + w, 25));
if (w == State->PenSize) {
Notch(dc, x, w, 0, 1);
Notch(dc, x, w, 29, -1);
}
x += w + 4;
}
}
void
TLineBar::EvLButtonDown(UINT, TPoint& point)
{
int x = 2;
for (int i = 0; i < LineCount; i++) {
int w = LineWidth[i];
if (point.x >= x && point.x < x+w+4) {
TRACEX(PaintCmd,0,"Width = " << w);
State->PenSize = w;
Invalidate(FALSE);
return;
}
x += w + 4;
}
}
#endif
// --------------- TCanvas ------------------------
TCanvas::TCanvas()
: TWindow(0, 0, 0),
Drawing(FALSE)
{
BkBrush = 0;
EvSysColorChange();
State.DrawTool = 0;
State.Dib = 0;
State.Bitmap = 0;
State.DC = 0;
State.Palette = 0;
State.PenSize = DefPenSize;
State.FgColor = 0;
State.BgColor = 1;
State.Name = State.Title = "";
Scroller = 0;
Tools[0] = new TPenTool("Pen");
Tools[1] = new TFillTool("Fill");
Tools[2] = new TRectTool("Rect", FALSE);
Tools[3] = new TRectTool("FillRect", TRUE);
Tools[4] = new TEllipseTool("Ellipse", FALSE);
Tools[5] = new TEllipseTool("FillEllipse", TRUE);
State.DrawTool = Tools[0];
Attr.Id = ID_CANVAS;
#if !defined(USE_TOOLBAR)
TToolBox* tb = new TToolBox(0);
tb->Insert(*new TButtonGadget(CM_TOOL+0, CM_TOOL+0, TButtonGadget::Exclusive,
TRUE, TButtonGadget::Down));
tb->Insert(*new TButtonGadget(CM_TOOL+1, CM_TOOL+1, TButtonGadget::Exclusive, TRUE));
tb->Insert(*new TButtonGadget(CM_TOOL+2, CM_TOOL+2, TButtonGadget::Exclusive, TRUE));
tb->Insert(*new TButtonGadget(CM_TOOL+3, CM_TOOL+3, TButtonGadget::Exclusive, TRUE));
tb->Insert(*new TButtonGadget(CM_TOOL+4, CM_TOOL+4, TButtonGadget::Exclusive, TRUE));
tb->Insert(*new TButtonGadget(CM_TOOL+5, CM_TOOL+5, TButtonGadget::Exclusive, TRUE));
ToolsPal = new TButtonPalette(this, "", tb);
tb = new TToolBox(0);
tb->Insert(*new TButtonGadget(CM_LINE+1, CM_LINE+1, TButtonGadget::Exclusive,
TRUE, TButtonGadget::Down));
tb->Insert(*new TButtonGadget(CM_LINE+3, CM_LINE+3, TButtonGadget::Exclusive, TRUE));
tb->Insert(*new TButtonGadget(CM_LINE+5, CM_LINE+5, TButtonGadget::Exclusive, TRUE));
tb->Insert(*new TButtonGadget(CM_LINE+7, CM_LINE+7, TButtonGadget::Exclusive, TRUE));
tb->Insert(*new TButtonGadget(CM_LINE+9, CM_LINE+9, TButtonGadget::Exclusive, TRUE));
tb->Insert(*new TButtonGadget(CM_LINE+11, CM_LINE+11, TButtonGadget::Exclusive, TRUE));
LinesPal = new TButtonPalette(this, "", tb);
#else
ToolsPal = LinesPal = 0;
#endif
}
TCanvas::~TCanvas()
{
delete State.DC;
delete State.Palette;
delete State.Dib;
delete State.Bitmap;
delete BkBrush;
for (int i = 0; i < ToolCount; i++)
delete Tools[i];
}
void
TCanvas::SetupWindow()
{
TWindow::SetupWindow();
NewDib(DefWidth, DefHeight, DefNColors);
DragAcceptFiles(TRUE);
//
// A scroller on the client area would be nice...
//
//Scroller = new TScroller(this,1,1, State.Dib->Width(), State.Dib->Height());
SetFocus();
}
BOOL
TCanvas::CanClose()
{
return AbandonOk();
}
BOOL
TCanvas::AbandonOk()
{
if (!State.Modified)
return TRUE;
const char msgFrmt[] = "%s\nThe image has changed.\n\n"
"Do you want to save current changes?";
char msg[sizeof(msgFrmt)+20];
sprintf(msg, msgFrmt, State.Name.c_str());
int resp = MessageBox(msg, GetApplication()->GetName(),
MB_ICONEXCLAMATION|MB_YESNOCANCEL);
if (resp == IDYES)
CmFileSave();
return resp != IDCANCEL;
}
//
// Setup state info given a new dib. Assumes ownership of the dib.
//
void
TCanvas::SetupDib(TDib* dib, const char* name, const char* title)
{
//
// Make sure we can get the Dib DC and palette before we commit to this dib.
// Revert to a DDB and a memory DC if we can't create a DIB DC.
//
TDC* newDC;
TBitmap* newBM = 0;
TPalette* newPalette;
try {
newDC = new TDibDC(*dib);
}
catch (TGdiObject::TXGdi&) {
newDC = new TMemoryDC;
newBM = new TBitmap(TScreenDC(), *dib);
((TMemoryDC*)newDC)->SelectObject(*newBM);
newDC->SetDIBits(*newBM, *dib);
if (dib->NumColors() > NColors(WORD(newBM->Planes()*newBM->BitsPixel())))
MessageBox("Colors may have been lost during bitmap conversion.",
GetApplication()->GetName(), MB_ICONEXCLAMATION|MB_OK);
}
newPalette = new TPalette(*dib);
delete State.DC;
delete State.Palette;
delete State.Dib;
delete State.Bitmap;
State.DC = newDC;
State.Palette = newPalette;
State.Dib = dib;
State.Bitmap = newBM;
State.Name = name;
State.Title = title;
State.Modified = FALSE;
UpdateCaption();
AdjustScroller();
TWindow* palette = Parent->ChildWithId(ID_PALETTE);
if (palette && palette->HWindow)
palette->Invalidate(FALSE);
Invalidate(FALSE);
}
//
// Create a new dib & setup state info
//
void
TCanvas::NewDib(int width, int height, int nColors)
{
//
// Construct the dib, catching any exptions that might occur & displaying a
// warning
//
TDib* dib;
try {
dib = new TDib(width, height, nColors);
}
catch (TGdiObject::TXGdi& x) {
MessageBox("Could Not Create DIB", GetApplication()->GetName(), MB_OK);
return;
}
//
// Setup a nice palette
//
for (int i = 0; i < min(nColors, int(sizeof DefPalette)); i++)
dib->SetColor(i, DefPalette[i]);
SetupDib(dib, "", "(Untitled)");
TBrush brush(TColor(State.BgColor));
State.DC->SelectObject(*State.Palette);
State.DC->RealizePalette();
State.DC->SelectObject(brush);
State.DC->PatBlt(TRect(TPoint(0,0), State.Dib->Size()));
State.DC->RestoreObjects();
}
//
// Open a dib & setup state info given a dib filename & title
//
void
TCanvas::OpenDib(const char* fileName, const char* fileTitle)
{
TDib* dib;
try {
dib = new TDib(fileName);
}
catch (TGdiObject::TXGdi& x) {
MessageBox("Invalid Bitmap File", GetApplication()->GetName(), MB_OK);
return;
}
SetupDib(dib, fileName, fileTitle);
}
BOOL
TCanvas::SaveDib(const char* fileName)
{
if (State.Bitmap) {
delete State.Dib;
State.Dib = new TDib(*State.Bitmap, State.Palette);
}
if (State.Dib->WriteFile(fileName))
return TRUE;
MessageBox("Disk error saving bitmap!", GetApplication()->GetName(), MB_OK);
return FALSE;
}
void
TCanvas::UpdateCaption()
{
char captionBuffer[70];
if (State.Dib)
wsprintf(captionBuffer, "%s - %s [%dx%dx%d]", GetApplication()->GetName(),
(LPCSTR)State.Title.c_str(),
State.Dib->Width(), State.Dib->Height(), State.Dib->NumColors());
else
sprintf(captionBuffer, "%s - (Bad Dib!)", GetApplication()->GetName());
Parent->SetCaption(captionBuffer);
}
void
TCanvas::AdjustScroller()
{
if (!Scroller)
return;
TRect clientRect = GetClientRect();
// only show scrollbars when image is larger than
// the client area and we are not stretching to fit.
//
TPoint range(Max(State.Dib->Width()-clientRect.Width(), 0),
Max(State.Dib->Height()-clientRect.Height(), 0));
Scroller->SetRange(range.x, range.y);
Scroller->ScrollTo(0, 0);
if (!GetUpdateRect(clientRect, FALSE))
Invalidate(FALSE);
}
void
TCanvas::EvSize(UINT SizeType, TSize& Size)
{
TWindow::EvSize(SizeType, Size);
if (SizeType != SIZEICONIC)
AdjustScroller();
}
BOOL
TCanvas::EvEraseBkgnd(HDC /*hDC*/)
{
// Wait until paint to erase as we blit
//::FillRect(hDC, GetClientRect(), *BkBrush);
return TRUE;
}
void
TCanvas::Paint(TDC& dc, BOOL, TRect&)
{
TRect drect(TPoint(0,0), State.Dib->Size());
TRect crect = GetClientRect();
if (Scroller)
crect += TPoint((int)Scroller->XPos, (int)Scroller->YPos);
// optimize this painting!
//TRect prect(rect);
//drect &= prect;
dc.SelectObject(*State.Palette);
dc.RealizePalette();
// Blit the DDB or DIB from the working DC to the screen
//
if (State.Bitmap)
dc.BitBlt(drect, *State.DC, TPoint(0,0));
else
dc.SetDIBitsToDevice(drect, TPoint(0,0), *State.Dib);
// Paint around the canvas
//
dc.SelectObject(*BkBrush);
dc.PatBlt(TRect(drect.right, 0, crect.right, crect.bottom));
dc.PatBlt(TRect(0, drect.bottom, crect.right, crect.bottom));
dc.RestoreObjects();
}
void
TCanvas::EvLButtonDown(UINT modKeys, TPoint& point)
{
TWindow::EvLButtonDown(modKeys, point);
if (!Drawing) {
Drawing = TRUE;
State.DrawTool->MouseDown(*this, point, &State);
}
}
void
TCanvas::EvMouseMove(UINT, TPoint& point)
{
if (Drawing)
State.DrawTool->MouseMove(point);
}
void
TCanvas::EvLButtonUp(UINT, TPoint& point)
{
if (Drawing) {
State.DrawTool->MouseMove(point);
State.DrawTool->MouseUp();
Drawing = FALSE;
}
}
void
TCanvas::EvDropFiles(TDropInfo dropInfo)
{
int totalNumberOfFiles = dropInfo.DragQueryFileCount();
if (totalNumberOfFiles == 1 && AbandonOk()) {
char filePath[MAXPATH+1];
char fileTitle[MAXFILE];
dropInfo.DragQueryFile(0, filePath, MAXPATH + 1);
fnsplit(filePath, 0, 0, fileTitle, 0);
OpenDib(filePath, fileTitle);
}
dropInfo.DragFinish();
}
void
TCanvas::EvSysColorChange()
{
delete BkBrush;
BkBrush = new TBrush(::GetSysColor(COLOR_APPWORKSPACE)); //COLOR_WINDOW
}
void
TCanvas::CmTool(WPARAM toolCmd)
{
int i = toolCmd - CM_TOOL;
TRACEX(PaintCmd,0, "Tool = " << Tools[i]->GetName());
State.DrawTool = Tools[i];
SetCursor(GetModule(), toolCmd);
}
void
TCanvas::CmLine(WPARAM lineCmd)
{
State.PenSize = lineCmd - CM_LINE;
}
void
TCanvas::CmFileNew()
{
TRACEX(PaintCmd,0,"CmFileNew()");
if (!AbandonOk())
return;
static int width = DefWidth;
static int height = DefHeight;
static int ncolors = DefNColors;
if (TDibAttrDialog(this, width, height, ncolors).Execute() == IDOK)
NewDib(width, height, ncolors);
}
void
TCanvas::CmFileOpen()
{
TRACEX(PaintCmd,0,"CmFileOpen()");
if (!AbandonOk())
return;
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);
OpenDib(data.FileName, fileTitle);
}
}
void
TCanvas::CmFileSave()
{
TRACEX(PaintCmd,0,"CmFileSave()");
if (State.Modified) {
if (!State.Name.length()) {
CmFileSaveAs();
return;
}
if (SaveDib(State.Name.c_str()))
State.Modified = FALSE;
}
}
void
TCanvas::CmFileSaveAs()
{
TRACEX(PaintCmd,0,"CmFileSaveAs()");
TOpenSaveDialog::TData data (
OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,
"Bitmap Files (*.BMP)|*.bmp|",
0,
"",
"BMP"
);
if (TFileSaveDialog(this, data).Execute() == IDOK) {
if (SaveDib(data.FileName)) {
State.Name = data.FileName;
State.Modified = FALSE;
char fileTitle[MAXPATH];
TOpenSaveDialog::GetFileTitle(data.FileName, fileTitle, MAXPATH);
State.Title = fileTitle;
UpdateCaption();
}
}
}
void
TCanvas::CmFilePrint()
{
TRACEX(PaintCmd, 0, "CmFilePrint()");
PrintData.Flags &= ~PD_PRINTSETUP;
if (TPrintDialog(this, PrintData).Execute() == IDOK) {
MessageBox("No File|Print yet...", GetApplication()->GetName(), MB_OK);
}
}
void
TCanvas::CmFilePrintSetup()
{
TRACEX(PaintCmd, 0, "CmFilePrintSetup()");
PrintData.Flags |= PD_PRINTSETUP;
TPrintDialog(this, PrintData, 0).Execute();
}
void
TCanvas::CmViewTools()
{
if (ToolsPal->HWindow)
ToolsPal->Destroy();
else
ToolsPal->Create();
}
void
TCanvas::CeViewTools(TCommandEnabler& ce)
{
ce.SetCheck(ToolsPal->HWindow ?
TCommandEnabler::Checked : TCommandEnabler::Unchecked);
}
void
TCanvas::CmViewLines()
{
if (LinesPal->HWindow)
LinesPal->Destroy();
else
LinesPal->Create();
}
void
TCanvas::CeViewLines(TCommandEnabler& ce)
{
ce.SetCheck(LinesPal->HWindow ?
TCommandEnabler::Checked : TCommandEnabler::Unchecked);
}
//----------------------------------------------------------------------------
class TPaintApp : public TApplication {
public:
TPaintApp() : TApplication("OWL Paint") {}
void InitMainWindow();
};
void TPaintApp::InitMainWindow()
{
TCanvas& client = *new TCanvas;
TDecoratedFrame* frame = new TDecoratedFrame(0, Name, &client);
MainWindow = frame;
#if defined(USE_TOOLBAR)
TControlBar* cb = new TControlBar(frame);
cb->Insert(*new TButtonGadget(CM_TOOL+0, CM_TOOL+0, TButtonGadget::Exclusive,
FALSE, TButtonGadget::Down));
cb->Insert(*new TButtonGadget(CM_TOOL+1, CM_TOOL+1, TButtonGadget::Exclusive));
cb->Insert(*new TButtonGadget(CM_TOOL+2, CM_TOOL+2, TButtonGadget::Exclusive));
cb->Insert(*new TButtonGadget(CM_TOOL+3, CM_TOOL+3, TButtonGadget::Exclusive));
cb->Insert(*new TButtonGadget(CM_TOOL+4, CM_TOOL+4, TButtonGadget::Exclusive));
cb->Insert(*new TButtonGadget(CM_TOOL+5, CM_TOOL+5, TButtonGadget::Exclusive));
#if !defined(USE_LINEBAR)
cb->Insert(*new TSeparatorGadget);
cb->Insert(*new TButtonGadget(CM_LINE+1, CM_LINE+1, TButtonGadget::Exclusive));
cb->Insert(*new TButtonGadget(CM_LINE+3, CM_LINE+3, TButtonGadget::Exclusive,
FALSE, TButtonGadget::Down));
cb->Insert(*new TButtonGadget(CM_LINE+5, CM_LINE+5, TButtonGadget::Exclusive));
cb->Insert(*new TButtonGadget(CM_LINE+7, CM_LINE+7, TButtonGadget::Exclusive));
cb->Insert(*new TButtonGadget(CM_LINE+9, CM_LINE+9, TButtonGadget::Exclusive));
cb->Insert(*new TButtonGadget(CM_LINE+11, CM_LINE+11, TButtonGadget::Exclusive));
#endif
frame->Insert(*cb, TDecoratedFrame::Top);
#endif
frame->Insert(*new TPaletteWindow(frame, &client.State), TDecoratedFrame::Bottom);
#if defined(USE_LINEBAR)
frame->Insert(*new TLineBar(frame, &client.State), TDecoratedFrame::Bottom);
#endif
MainWindow->AssignMenu("PaintMenu");
MainWindow->Attr.AccelTable = "PaintAccels";
MainWindow->SetIcon(this, "PaintIcon");
}
int
OwlMain(int /*argc*/, char* /*argv*/ [])
{
TScreenDC screenDC;
DefNColors = (int)NColors(WORD(screenDC.GetDeviceCaps(BITSPIXEL)*screenDC.GetDeviceCaps(PLANES)));
return TPaintApp().Run();
}