/**************************************************************************\ * * Copyright (c) 1998 Microsoft Corporation * * Abstract: * * Pen API related declarations * * Revision History: * * 12/09/1998 andrewgo * Flesh out pen interfaces. * * 12/08/1998 andrewgo * Created it. * \**************************************************************************/ #ifndef _PEN_HPP #define _PEN_HPP //-------------------------------------------------------------------------- // Abstract base class for various pen types //-------------------------------------------------------------------------- class GpLineTexture; class GpCustomLineCap; class GpPen : public GpObject { protected: VOID SetValid(BOOL valid) { GpObject::SetValid(valid ? ObjectTagPen : ObjectTagInvalid); } public: // Constructors GpPen( const GpColor& color, REAL penWidth, GpUnit unit = UnitWorld ); GpPen( const GpBrush* brush, REAL penWidth, GpUnit = UnitWorld ); GpPen( GpLineTexture* lineTexture, REAL penWidth, GpUnit = UnitWorld ); // Make a copy of the pen object GpPen* Clone(); // Virtual destructor virtual ~GpPen() { if(Brush) delete Brush; if(DevicePen.CustomStartCap) delete DevicePen.CustomStartCap; if(DevicePen.CustomEndCap) delete DevicePen.CustomEndCap; GpFree(DevicePen.DashArray); GpFree(DevicePen.CompoundArray); } // Get the lock object GpLockable *GetObjectLock() const { return &Lockable; } // Check if the pen object is valid virtual BOOL IsValid() const { return GpObject::IsValid(ObjectTagPen); } // Determine if pens are equivalent virtual BOOL IsEqual(const GpPen * pen) const; virtual ObjectType GetObjectType() const { return ObjectTypePen; } virtual UINT GetDataSize() const; virtual GpStatus GetData(IStream * stream) const; virtual GpStatus SetData(const BYTE * dataBuffer, UINT size); virtual GpStatus ColorAdjust( GpRecolor * recolor, ColorAdjustType type ); // Set/get fill attributes VOID Set( const GpColor& color, REAL penWidth, GpUnit = UnitWorld ); GpStatus SetColor(GpColor* color); GpStatus GetColor(ARGB *argb) const; GpStatus SetBrush(GpBrush* brush); GpBrush* GetBrush() { return Brush; } GpBrush* GetClonedBrush() { if(Brush) { return Brush->Clone(); } else return NULL; } GpPenType GetPenType(); GpStatus SetLineTexture(GpLineTexture* lineTexture); GpLineTexture* GetLineTexture(); // Set/get pen transform GpStatus SetTransform(const GpMatrix& matrix) { GpStatus status = Ok; // Keep the transform invertible if (matrix.IsInvertible()) { DevicePen.Xform = matrix; UpdateUid(); } else status = InvalidParameter; return status; } GpStatus GetTransform(GpMatrix* matrix) const { *matrix = DevicePen.Xform; return Ok; } GpStatus ResetTransform() { if (!DevicePen.Xform.IsIdentity()) { DevicePen.Xform.Reset(); UpdateUid(); } return Ok; } GpStatus MultiplyTransform(const GpMatrix& matrix, GpMatrixOrder order = MatrixOrderPrepend); GpStatus TranslateTransform(REAL dx, REAL dy, GpMatrixOrder order = MatrixOrderPrepend) { DevicePen.Xform.Translate(dx, dy, order); UpdateUid(); return Ok; } GpStatus ScaleTransform(REAL sx, REAL sy, GpMatrixOrder order = MatrixOrderPrepend) { DevicePen.Xform.Scale(sx, sy, order); UpdateUid(); return Ok; } GpStatus RotateTransform(REAL angle, GpMatrixOrder order = MatrixOrderPrepend) { DevicePen.Xform.Rotate(angle, order); UpdateUid(); return Ok; } // See if the pen has a non-identity transform. BOOL HasTransform() const { return !DevicePen.Xform.IsIdentity(); } // Set/get line caps: start, end, and dash VOID SetStartCap(GpLineCap startCap) { DevicePen.StartCap = startCap; if(DevicePen.CustomStartCap) { delete DevicePen.CustomStartCap; DevicePen.CustomStartCap = NULL; } UpdateUid(); } VOID SetEndCap(GpLineCap endCap) { DevicePen.EndCap = endCap; if(DevicePen.CustomEndCap) { delete DevicePen.CustomEndCap; DevicePen.CustomEndCap = NULL; } UpdateUid(); } GpLineCap GetStartCap() const { return DevicePen.StartCap; } GpLineCap GetEndCap() const { return DevicePen.EndCap; } VOID SetLineCap(GpLineCap startCap, GpLineCap endCap, GpDashCap dashCap) { DevicePen.StartCap = startCap; DevicePen.EndCap = endCap; SetDashCap(dashCap); UpdateUid(); } GpStatus SetCustomStartCap(const GpCustomLineCap* customCap); GpStatus GetCustomStartCap(GpCustomLineCap** customCap); GpStatus SetCustomEndCap(const GpCustomLineCap* customCap); GpStatus GetCustomEndCap(GpCustomLineCap** customCap); // Set/get line join VOID SetLineJoin(GpLineJoin lineJoin) { DevicePen.Join = lineJoin; UpdateUid(); } GpLineJoin GetLineJoin() const { return DevicePen.Join; } VOID SetMiterLimit(REAL miterLimit) { DevicePen.MiterLimit = max(1.0f, miterLimit); UpdateUid(); } REAL GetMiterLimit() const { return DevicePen.MiterLimit; } GpStatus SetPenAlignment(GpPenAlignment penMode) { // Compound Inset pens aren't implemented yet. // The code for correctly handling minimum width compound sub lines // is missing. if((penMode==PenAlignmentInset) && (DevicePen.CompoundCount!=0)) { return NotImplemented; } DevicePen.PenAlignment = penMode; UpdateUid(); return Ok; } GpPenAlignment GetPenAlignment() const { return DevicePen.PenAlignment; } // Set/get dash attributes GpDashStyle GetDashStyle() const { return DevicePen.DashStyle; } GpDashCap GetDashCap() const { // Note: Internally we use a GpLineCap type to store the dash cap type. // So we need to convert between GpLineCap and GpDashCap. // However, we should change the internal usage to GpDashCap in v2. // - JBronsk GpDashCap dashCap = DashCapFlat; switch (DevicePen.DashCap) { case LineCapRound: dashCap = DashCapRound; break; case LineCapTriangle: dashCap = DashCapTriangle; break; // all others map to DashCapFlat } return dashCap; } VOID SetDashCap(GpDashCap dashCap); GpStatus SetDashStyle(GpDashStyle dashStyle); VOID SetDashOffset(REAL dashOffset) { DevicePen.DashOffset = dashOffset; UpdateUid(); } REAL GetDashOffset() const { return DevicePen.DashOffset; } INT GetDashCount() const { return DevicePen.DashCount; } GpStatus GetDashArray(REAL* dashArray, INT count) const; DpPen * GetDevicePen() { return & DevicePen; } VOID SetWidth(REAL penWidth) { DevicePen.Width = penWidth; UpdateUid(); } REAL GetWidth() const { return DevicePen.Width; } REAL GetMaximumJoinWidth( REAL sharpestAngle, const GpMatrix* matrix, REAL dpiX, REAL dpiY) const; REAL GetMaximumCapWidth( const GpMatrix* matrix, REAL dpiX, REAL dpiY) const; VOID SetUnit(GpUnit unit) { // UnitDisplay is device-dependent and cannot be used for a pen size ASSERT(unit != UnitDisplay); DevicePen.Unit = unit; UpdateUid(); } GpUnit GetUnit() const { return DevicePen.Unit; } GpStatus SetDashArray(const REAL* dashArray, INT count); INT GetCompoundCount() const { return DevicePen.CompoundCount; } GpStatus SetCompoundArray(const REAL* compoundArray, INT count); GpStatus GetCompoundArray(REAL* compoundArray, INT count); BOOL IsOpaque() const { return Brush->IsOpaque(); } BOOL IsSolid() const { return Brush->IsSolid(); } COLORREF ToCOLORREF() const { return Brush->ToCOLORREF(); } REAL GetCapDelta(); static GpPen * GetPen(const DpPen * pen) { return (GpPen *) ((BYTE *) pen - offsetof(GpPen, DevicePen)); } static REAL ComputeMiterLength( REAL angle, REAL miterLimit ); VOID AdjustDashArrayForCaps( REAL dashUnit, REAL *dashArray, INT dashCount ) const; REAL GetDashCapInsetLength( REAL dashUnit ) const; private: VOID InitDefaultState(REAL penWidth, GpUnit unit); GpStatus SetDashStyleWithDashCap(GpDashStyle dashStyle, GpLineCap dashCap); // GetMaximumWidth is used only for UnitWorld. GpStatus GetMaximumWidth(REAL* width, const GpMatrix* matrix) const; protected: mutable GpLockable Lockable; GpBrush * Brush; DpPen DevicePen; GpPen() { DevicePen.InitDefaults(); SetValid(TRUE); } GpPen(const GpPen* pen); }; #endif _PEN_HPP