home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
deans.zip
/
PAINTBRU.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1994-09-14
|
90KB
|
2,797 lines
//
// NAME: CIDLib_PaintBrush.Cpp
//
// DESCRIPTION:
//
// This module implements the PAINTBRUSH class, which is the means by which
// graphical output is accomplished to windows.
//
//
// AUTHOR: Dean Roddey
//
// CREATE DATE: 09/26/93
//
// COPYRIGHT: 1992..1994, 'CIDCorp
//
// CAVEATS/GOTCHAS:
//
// MODIFICATION LOG:
//
// -----------------------------------------------------------------------------
// Local defines
// -----------------------------------------------------------------------------
#define CIDGUI_PAINTBRUSH_CPP
#define INCL_GPICONTROL
#define INCL_GPILCIDS
#define INCL_GPILOGCOLORTABLE
#define INCL_GPIPATHS
#define INCL_GPIPRIMITIVES
#define INCL_WINWINDOWMGR
#define INCL_CIDGUI_ERRORIDS
#define INCL_CIDGUI_FACOBJECT
#define INCL_CIDGUI_FONTS
#define INCL_CIDGUI_GRAPHICS
#define INCL_CIDLIB_MEMORY
#define INCL_CIDLIB_METRICS
#define INCL_CIDLIB_PROCESS
#define INCL_CIDLIB_TEXTFILES
// -----------------------------------------------------------------------------
// Facility specific includes
// -----------------------------------------------------------------------------
#include "CIDGui_.Hpp"
// -----------------------------------------------------------------------------
// Local data declarations
//
// __apszLineDesc
// A list of description strings for the line types.
//
// __apszMixDesc
// A list of description strings for the mix mode enum.
//
// __apszPatDesc
// A list of description strings for the pattern types.
// -----------------------------------------------------------------------------
tCIDLib::CH* __apszLineDesc[] = {
"Default"
, "Dot"
, "ShortDash"
, "DashDot"
, "DoubleDot"
, "LongDash"
, "DashDoubleDot"
, "Solid"
, "Invisible"
};
const tCIDLib::CARD4 c4LineMax = (sizeof(__apszLineDesc)
/sizeof(__apszLineDesc[0]));
tCIDLib::CH* __apszMixDesc[] = {
"Default"
, "Or"
, "OverPaint"
, "?3"
, "Xor"
, "Leavalone"
, "And"
, "SubTract"
, "MaskSrcNot"
, "Zero"
, "NotMergeSrc"
, "NotXorSrc"
, "Invert"
, "MergeSrcNot"
, "NotCopySrc"
, "MergeNotSrc"
, "NotMaskSrc"
, "One"
};
const tCIDLib::CARD4 c4MixMax = (sizeof(__apszMixDesc)
/sizeof(__apszMixDesc[0]));
tCIDLib::CH* __apszPatDesc[] = {
"Default"
, "Dense1"
, "Dense2"
, "Dense3"
, "Dense4"
, "Dense5"
, "Dense6"
, "Dense7"
, "Dense8"
, "Vert"
, "Horiz"
, "Diag1"
, "Diag2"
, "Diag3"
, "Diag4"
, "NoShade"
, "Solid"
, "Halftone"
, "Hatch"
, "DiagHatch"
};
const tCIDLib::CARD4 c4PatMax = (sizeof(__apszPatDesc)
/sizeof(__apszPatDesc[0]));
// -----------------------------------------------------------------------------
// Global functions
// -----------------------------------------------------------------------------
//
// FUNCTION/METHOD NAME: operator<<(strbDest, eMix)
//
// DESCRIPTION:
//
// This method will format the passed mix mode to the passed string.
// ---------------------------------------
// INPUT: eMix is the mix mode to use
//
// OUTPUT: strbDest is the destination string to format to
//
// RETURN: A reference to the string
//
STRGBUF& PROCEXP operator<<(STRGBUF& strbDest, tCIDGui::eMIXMODES eMix)
{
if (eMix > c4MixMax)
{
facCIDGui.LogErr( __FILE__
, "operator<<"
, __LINE__
, GUIERR_GEN_NOT_VALID_VALUE
, tCIDLib::eSEV_PROCESS_FATAL
, tCIDLib::eCLASS_BADPARMS
, CARDINAL(eMix)
, STRG16("Mix Mode"));
}
strbDest << __apszMixDesc[eMix];
return strbDest;
}
OTXTFILE& PROCEXP operator<<(OTXTFILE& otfDest, tCIDGui::eMIXMODES eMix)
{
STRG64 strTmp;
strTmp << eMix;
otfDest << strTmp;
return otfDest;
}
//
// FUNCTION/METHOD NAME: operator<<(strbDest, eLineStyle)
//
// DESCRIPTION:
//
// This method will format the passed line style into the string buffer
// ---------------------------------------
// INPUT: eLineStyle is the line style to format
//
// OUTPUT: strbDest is the buffer to format into
//
// RETURN: A reference to the string buffer
//
STRGBUF& PROCEXP operator<<(STRGBUF& strbDest
, tCIDGui::eLINESTYLES eLineStyle)
{
// Check for valid ranges
if (eLineStyle > c4LineMax)
{
facCIDGui.LogErr( __FILE__
, "operator<<"
, __LINE__
, GUIERR_GEN_NOT_VALID_VALUE
, tCIDLib::eSEV_PROCESS_FATAL
, tCIDLib::eCLASS_BADPARMS
, INTEGER(eLineStyle)
, STRG16("Line Style"));
}
strbDest << __apszLineDesc[eLineStyle];
return strbDest;
}
OTXTFILE& PROCEXP operator<<( OTXTFILE& otfDest
, tCIDGui::eLINESTYLES eLineStyle)
{
STRG64 strTmp;
strTmp << eLineStyle;
otfDest << strTmp;
return otfDest;
}
//
// FUNCTION/METHOD NAME: operator<<(strbDest, ePattern)
//
// DESCRIPTION:
//
// This method will format the passed pattern to the passed string buffer
// object.
// ---------------------------------------
// INPUT: ePattern is the pattern to format
//
// OUTPUT: strbDest is the destination string.
//
// RETURN: A reference to the string
//
STRGBUF& PROCEXP operator<<(STRGBUF& strbDest, tCIDGui::ePATTERNS ePattern)
{
// Check for valid ranges
if (ePattern > c4PatMax)
{
facCIDGui.LogErr( __FILE__
, "operator<<"
, __LINE__
, GUIERR_GEN_NOT_VALID_VALUE
, tCIDLib::eSEV_PROCESS_FATAL
, tCIDLib::eCLASS_BADPARMS
, INTEGER(ePattern)
, STRG16("Pattern"));
}
strbDest << __apszPatDesc[ePattern];
return strbDest;
}
OTXTFILE& PROCEXP operator<<(OTXTFILE& otfDest, tCIDGui::ePATTERNS ePattern)
{
STRG64 strTmp;
strTmp << ePattern;
otfDest << strTmp;
return otfDest;
}
// -----------------------------------------------------------------------------
// CLASS: FONT
// PREFIX: fnt
//
// This class is just for local use. Objects of this class are used as the
// nodes of the PAINTBRUSH class' list of active fonts.
// -----------------------------------------------------------------------------
class FONT : public CIDOBJECT
{
public :
// ---------------------------------------------------------------------
// Constructors and Destructors.
//
// FONT
// The constructor just saves away the font name, font id, PS, and
// the font metrics. The name must be unique for this window and
// would ideally be unique for the process.
//
// ~FONT
// The destructor destroys the logical font.
// ---------------------------------------------------------------------
FONT (
const STRG16& strName
, const FONTINFO& finfInfo
, HPS hpsWnd
, tCIDLib::INT4 i4FontId
);
~FONT ();
// ---------------------------------------------------------------------
// Public, inherited methods
//
// FormatToStr
// Formats some debug info about this window to the string buffer.
// ---------------------------------------------------------------------
STDVPUBMETHODS(FONT,CIDOBJECT,tCIDLib::eFALSE);
virtual tCIDLib::VOID FormatToStr
(
STRGBUF& strbDest
) const;
protected :
// ---------------------------------------------------------------------
// Declare our friends
//
// PAINTBRUSH
// We let PAINTBRUSH access our data members directly since we
// exist only for his benefit and he can use all the speed he can
// get.
// ---------------------------------------------------------------------
friend class PAINTBRUSH;
// ---------------------------------------------------------------------
// Protected data members
//
// _hpsWnd
// This is the PS of the window we belong to, which is needed in
// order to destroy the font.
//
// _i4FontId
// The logical font id of this font
//
// _finfInfo
// The FONTINFO object for this font.
//
// _strName
// This holds the name of this font, which is given by the caller
// when the font is created. It must be unique.
// ---------------------------------------------------------------------
HPS _hpsWnd;
tCIDLib::INT4 _i4FontId;
FONTINFO _finfInfo;
STRG16 _strName;
};
// -----------------------------------------------------------------------------
// FONT: Constructors and Destructors
// -----------------------------------------------------------------------------
//
// FUNCTION/METHOD NAME: FONT(strName, finfInfo, hpsWnd, i4FontId)
//
// DESCRIPTION:
//
// This constructor just needs to store away the passed info.
// ---------------------------------------
// INPUT: strName is the name that the caller gave to the font
// finfInfo is the FONTINFO object for the font. This makes it easy
// to provide font info about a font quickly.
// hpsWnd is the presentation space of the window.
// i4FontId is the logical font id of the font.
//
// OUTPUT: None
//
// RETURN: None
//
FONT::FONT( const STRG16& strName
, const FONTINFO& finfInfo
, HPS hpsWnd
, tCIDLib::INT4 i4FontId) :
_i4FontId(i4FontId)
, _finfInfo(finfInfo)
, _hpsWnd(hpsWnd)
, _strName(strName)
{
// Bump up the font id count in the core metrics
_pmtrGUICore->OffsetCard(tCIDGui_::eCOREMETRIC_FNTIDCOUNT, 1);
}
//
// FUNCTION/METHOD NAME: ~FONT()
//
// DESCRIPTION:
//
// This destructor will delete the logical font. The PAINTBRUSH object needs
// to have reset the PS to the default font.
// ---------------------------------------
// INPUT: None
//
// OUTPUT: None
//
// RETURN: None
//
FONT::~FONT()
{
_DeleteFontId(_hpsWnd, _i4FontId, _strName);
// Bump down the font id count in the core metrics
_pmtrGUICore->OffsetCard(tCIDGui_::eCOREMETRIC_FNTIDCOUNT, -1);
}
// -----------------------------------------------------------------------------
// FONT: Public, inherited methods
// -----------------------------------------------------------------------------
//
// FUNCTION/METHOD NAME: FormatToStr(strbDest) const
//
// DESCRIPTION:
//
// This method will format the data members into the passed string buffer
// ---------------------------------------
// INPUT: None
//
// OUTPUT: strbDest is the buffer to format into
//
// RETURN: None
//
tCIDLib::VOID PROCEXP FONT::FormatToStr(STRGBUF& strbDest) const
{
// Format the info
strbDest << _finfInfo << ", ID=" << _i4FontId << ", Name=" << _strName;
}
// -----------------------------------------------------------------------------
// CLASS: PAINTBRUSH
// PREFIX: ptb
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// PAINTBRUSH: Constructors/Destructors
// -----------------------------------------------------------------------------
//
// FUNCTION/METHOD NAME: PAINTBRUSH(wndTarget)
//
// DESCRIPTION:
//
// This constructor is the only public constructor for PAINTBRUSH objects. It
// just stores away the window handle and creates a PS. The PS is put into
// RGB mode.
// ---------------------------------------
// INPUT: wndTarget is the target window that we are paint into.
//
// OUTPUT: None
//
// RETURN: None
//
PROCEXP PAINTBRUSH::PAINTBRUSH(WINDOW& wndTarget) :
__eType(ePS_TEMPORARY)
, __hPS(0)
, __llstFonts(tCIDGui::i4MaxFontIds, tCIDLib::eDEL_DELETE)
, __wndTarget(wndTarget)
{
// Get a PS from the target window
__hPS = WinGetPS(wndTarget);
if (!__hPS)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH"
, __LINE__
, "WinGetPS failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Set the PS to RGB mode
if (!GpiCreateLogColorTable(__hPS, 0, LCOLF_RGB, 0, 0, 0))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH"
, __LINE__
, "GpiCreateLogColorTable failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Bump up the count of paint brushes in the metrics
_pmtrGUICore->OffsetCard(tCIDGui_::eCOREMETRIC_PBRUSHCOUNT, 1);
}
//
// FUNCTION/METHOD NAME: PAINTBRUSH(hPS, wndTarget, eType)
//
// DESCRIPTION:
//
// This is a special, protected constructor that is provided for our
// friends who need to create PAINTBRUSH objects after the fact for
// existing PSs.
//
// NOTE: This guy is protected!!!
// ---------------------------------------
// INPUT: hPS is the PS that already exists
// wndTarget is the target window that we are drawing to
// eType indicates what type of PS. For this call it will almost
// always be ePS_PAINT or ePS_PERSISTENT
//
// OUTPUT: None
//
// RETURN: None
//
PROCEXP PAINTBRUSH::PAINTBRUSH(HPS hPS, WINDOW& wndTarget, ePSTYPE eType) :
__eType(eType)
, __hPS(hPS)
, __llstFonts(tCIDGui::i4MaxFontIds, tCIDLib::eDEL_DELETE)
, __wndTarget(wndTarget)
{
// Set the PS to RGB mode
if (!GpiCreateLogColorTable(__hPS, 0, LCOLF_RGB, 0, 0, 0))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH"
, __LINE__
, "GpiCreateLogColorTable failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Bump up the count of paint brushes in the metrics
_pmtrGUICore->OffsetCard(tCIDGui_::eCOREMETRIC_PBRUSHCOUNT, 1);
}
//
// FUNCTION/METHOD NAME: PAINTBRUSH()
//
// DESCRIPTION:
//
// This guy aborts if it is called. We have to use bogus info to create
// some members because they must be created.
// ---------------------------------------
// INPUT: None
//
// OUTPUT: None
//
// RETURN: None
//
PROCEXP PAINTBRUSH::PAINTBRUSH() :
__llstFonts(1, tCIDLib::eDEL_DELETE)
, __wndTarget(NUL_WINDOW)
{
facCIDGui.LogMsg( __FILE__
, "PAINTBRUSH"
, __LINE__
, "PAINTBRUSH default constructor cannot be called"
, tCIDLib::eSEV_PROCESS_FATAL);
}
//
// FUNCTION/METHOD NAME: ~PAINTBRUSH()
//
// DESCRIPTION:
//
// This guy will destroy the PS according to what type it is and whether
// it ever got created.
// ---------------------------------------
// INPUT: None
//
// OUTPUT: None
//
// RETURN: None
//
PROCEXP PAINTBRUSH::~PAINTBRUSH()
{
// Clean up the PS
if (__hPS)
{
// Make sure that we go back to the default font
if (!GpiSetCharSet(__hPS, LCID_DEFAULT))
{
facCIDGui.LogLastSysErr(__FILE__
, "~PAINTBRUSH"
, __LINE__
, "GpiSetCharSet failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
//
// Flush the font list. It is in delete mode so it will delete the
// FONT objects, which will delete their associated logical font
// ids.
//
__llstFonts.Flush();
// According to what type of PS, destroy it
if (__eType == ePS_PAINT)
{
if (!WinEndPaint(__hPS))
{
facCIDGui.LogLastSysErr(__FILE__
, "~PAINTBRUSH"
, __LINE__
, "WinEndPaint failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
else if (__eType == ePS_TEMPORARY)
{
if (!WinReleasePS(__hPS))
{
facCIDGui.LogLastSysErr(__FILE__
, "~PAINTBRUSH"
, __LINE__
, "WinReleasePS failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
else if (__eType == ePS_PERSISTENT)
{
if (!GpiDestroyPS(__hPS))
{
facCIDGui.LogLastSysErr(__FILE__
, "~PAINTBRUSH"
, __LINE__
, "GpiDestroyPS failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
__hPS = 0;
}
// Bump down the count of paint brushes in the metrics
_pmtrGUICore->OffsetCard(tCIDGui_::eCOREMETRIC_PBRUSHCOUNT, -1);
}
// -----------------------------------------------------------------------------
// PAINTBRUSH: Public, inherited methods
// -----------------------------------------------------------------------------
//
// FUNCTION/METHOD NAME: FormatToStr(strbDest) const
//
// DESCRIPTION:
//
// This method will format the data members into the passed string buffer
// ---------------------------------------
// INPUT: None
//
// OUTPUT: strbDest is the buffer to format into
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::FormatToStr(STRGBUF& strbDest) const
{
// Format our PS info into the string
strbDest << "PS=" << CARDINAL(__hPS, tCIDLib::eRADIX_HEX);
}
// -----------------------------------------------------------------------------
// PAINTBRUSH: Public, non-virtual methods
// -----------------------------------------------------------------------------
//
// FUNCTION/METHOD NAME: areaString(strbText, c4Start, c4End)
//
// DESCRIPTION:
//
// This method will return a 0 based area that will contain the indicated
// substring of the passed string using the current font and character
// attributes. There is another version that just does the whole string,
// which calls this version with the whole string length.
// ---------------------------------------
// INPUT: strbText is the text to measure
// c4Start is the starting index of the substring to get the area for
// c4End is the ending index of the substring to get the area for.
//
// OUTPUT: None
//
// RETURN: An AREA object that contains the text
//
AREA PROCEXP PAINTBRUSH::areaString(const STRGBUF& strbText) const
{
return areaString(strbText, 0, strbText.c4Length()-1);
}
AREA PROCEXP PAINTBRUSH::areaString(const STRGBUF& strbText
, tCIDLib::CARD4 c4Start
, tCIDLib::CARD4 c4End) const
{
POINTL aptlBox[TXTBOX_COUNT];
STRING strTmp("", strbText.c4Length());
// Pull out the indicated substring
strTmp.CopySubStr(strbText, c4Start, c4End);
if (!GpiQueryTextBox( __hPS
, strTmp.c4Length()
, strTmp.pSZ()
, TXTBOX_COUNT
, aptlBox))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::areaString"
, __LINE__
, "GpiQueryTextBox failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
//
// This guy returns points that take into account where the baseline will
// be written, but we don't want that. So we need to adjust the y of both
// corners by the y of the lower left corner.
//
aptlBox[TXTBOX_TOPRIGHT].x -= aptlBox[TXTBOX_BOTTOMLEFT].x;
aptlBox[TXTBOX_TOPRIGHT].y -= aptlBox[TXTBOX_BOTTOMLEFT].y;
aptlBox[TXTBOX_BOTTOMLEFT].x = 0;
aptlBox[TXTBOX_BOTTOMLEFT].y = 0;
return AREA(aptlBox[TXTBOX_BOTTOMLEFT], aptlBox[TXTBOX_TOPRIGHT]);
}
//
// FUNCTION/METHOD NAME: Box(pntTo, c4Rounding)
// Box(pntFrom, pntTo, c4Rounding)
// Box(areaBox, c4Rounding)
//
// DESCRIPTION:
//
// There are three versions that:
//
// 1) Draw from the current position to the pntTo
// 2) From from the pntFrom to the pntTo
// 3) Draw a box that covers the passed area
//
// The foreground color is used for the fill.
// ---------------------------------------
// INPUT: pntFrom is the point to draw from
// pntTo is the point to draw to
// areaBox is the area to draw the box over
// c4Rounding is the amount of rounding to apply
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::Box( const POINT& pntTo
, tCIDLib::CARD4 c4Rounding)
{
if (GpiBox( __hPS
, DRO_FILL
, pntTo
, c4Rounding
, c4Rounding) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Box"
, __LINE__
, "GpiBox failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
tCIDLib::VOID PROCEXP PAINTBRUSH::Box( const POINT& pntFrom
, const POINT& pntTo
, tCIDLib::CARD4 c4Rounding)
{
if (!GpiMove(__hPS, pntFrom))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Box"
, __LINE__
, "GpiMove failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
if (GpiBox( __hPS
, DRO_FILL
, pntTo
, c4Rounding
, c4Rounding) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Box"
, __LINE__
, "GpiBox failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
tCIDLib::VOID PROCEXP PAINTBRUSH::Box( const AREA& areaBox
, tCIDLib::CARD4 c4Rounding)
{
POINTL ptlFrom, ptlTo;
// Covert the area to 2 pointls
areaBox.ToPtls(ptlFrom, ptlTo);
if (!GpiMove(__hPS, &ptlFrom))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Box"
, __LINE__
, "GpiMove failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
if (GpiBox( __hPS
, DRO_FILL
, &ptlTo
, c4Rounding
, c4Rounding) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Box"
, __LINE__
, "GpiBox failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
//
// FUNCTION/METHOD NAME: c4EnumFonts( strbFaceName, eFlags, eSignificant
// , llstTarget)
//
// DESCRIPTION:
//
// This method will return a linked list of FONTINFO objects for all of the
// available fonts that match the passed criteria.
// ---------------------------------------
// INPUT: strbFaceName is the face name to look for. If it is "", then all
// face names are accepted.
// eFlags is a set of selection criteria to find fonts that match
// a particular format.
// eSignificant is a bit mask that indicates which flags in the
// eFlags parm are valid.
//
// OUTPUT: llstTarget is the target linked list that will be filled in with
// the matching fonts. It is flushed before the new fonts are
// added.
//
// RETURN: The number of fonts found
//
tCIDLib::CARD4
PROCEXP PAINTBRUSH::c4EnumFonts(const STRGBUF& strbFaceName
, tCIDGui::eFONTFLAGS eSelection
, tCIDGui::eFONTFLAGS eSelSignificant
, LINKLIST& llstTarget)
{
return _c4EnumFonts(__hPS
, strbFaceName
, eSelection
, eSelSignificant
, llstTarget);
}
//
// FUNCTION/METHOD NAME: CreateFont(finfNew, eFAttrs, strName)
//
// DESCRIPTION:
//
// This method will create a font for this window. The font will be given the
// passed name for future reference.
// ---------------------------------------
// INPUT: finfNew is the FONTINFO object that contains the info on the type
// of font to create.
// eFAttrs are the font creation attributes to use
// strName is the name to give to the font. It must be unique for this
// window, and preferably for the process. This name is how the
// client accesses the font hereafter.
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP
PAINTBRUSH::CreateFont( const FONTINFO& finfNew
, tCIDGui::eFATTRS eFAttrs
, const STRG16& strName)
{
//
// The first thing to do is to see if the PS is valid at this time. If
// not then abort.
//
if (!__hPS)
{
facCIDGui.LogErr( __FILE__
, "PAINTBRUSH::CreateFont"
, __LINE__
, GUIERR_GEN_REQUIRES_VALID_PS
, strName
, tCIDLib::eSEV_PROCESS_FATAL
, tCIDLib::eCLASS_BADPARMS);
}
// Make sure that the font name is unique for this window.
if (_plnodFindFnt(strName))
{
facCIDGui.LogErr( __FILE__
, "PAINTBRUSH::CreateFont"
, __LINE__
, GUIERR_FONT_NAME_NOT_UNIQUE
, tCIDLib::eSEV_PROCESS_FATAL
, tCIDLib::eCLASS_BADPARMS
, strName);
}
// Create a logical font id using the passed font info
tCIDLib::INT4 i4FontId = _i4CreateLogFont(__hPS, eFAttrs, finfNew);
//
// Create a FONT object using the info we have and put it into the list
// for this window.
//
__llstFonts.plnodAppendNode(new FONT(strName, finfNew, __hPS, i4FontId));
}
//
// FUNCTION/METHOD NAME: DisplayText(strbText)
//
// DESCRIPTION:
//
// This method will display the passed text string at the current location
// using the currently set attributes.
// ---------------------------------------
// INPUT: strbText is the string to display
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::DisplayText(const STRGBUF& strbText)
{
if (GpiCharString( __hPS
, strbText.c4Length()
, strbText.pSZ()) == GPI_ERROR)
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::DisplayText"
, __LINE__
, "GpiCharString failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
//
// FUNCTION/METHOD NAME: DisplayText(strbText, pntPos)
//
// DESCRIPTION:
//
// This method will display the passed text string at the indicated location
// using the currently set attributes.
// ---------------------------------------
// INPUT: strbText is the string to display
// pntPos is the position to display the text. This is the baseline
// position!
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::DisplayText( const STRGBUF& strbText
, const POINT& pntPos)
{
if (GpiCharStringAt(__hPS
, pntPos
, strbText.c4Length()
, strbText.pSZ()) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::DisplayText"
, __LINE__
, "GpiCharStringAt failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
//
// FUNCTION/METHOD NAME: DisplayText( strbText, areaClip, eHJustify
// , eVJustify, eFlags)
//
// DESCRIPTION:
//
// This method will display the passed text string using the current attributes
// and clipped and justified to the passed area.
// ---------------------------------------
// INPUT: strbText is the string to display
// areaClip is the area to clipp the output to
// eHJustify is the horizontal justification
// eVJustify is the verical justification
// eFlags is a set of flags that control the display options.
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID
PROCEXP PAINTBRUSH::DisplayText(const STRGBUF& strbText
, const AREA& areaClip
, tCIDLib::eHJUSTIFY eHJustify
, tCIDLib::eVJUSTIFY eVJustify
, tCIDGui::eTEXTFLAGS eFlags)
{
RECTL rectlClip;
ULONG ulFlags = eFlags;
if (eHJustify == tCIDLib::eHJUSTIFY_RIGHT)
ulFlags = DT_RIGHT;
else if (eHJustify == tCIDLib::eHJUSTIFY_CENTER)
ulFlags = DT_CENTER;
if (eVJustify == tCIDLib::eVJUSTIFY_BOTTOM)
ulFlags |= DT_BOTTOM;
else if (eVJustify == tCIDLib::eHJUSTIFY_CENTER)
ulFlags |= DT_CENTER;
// Use colors in PS
ulFlags |= DT_TEXTATTRS;
areaClip.ToRectl(rectlClip, tCIDGui::eRECTL_NONINCLUSIVE);
WinDrawText(__hPS
, -1
, strbText.pSZ()
, &rectlClip
, 0, 0
, ulFlags);
}
//
// FUNCTION/METHOD NAME: DrawBorder(eBorder, areaPos, c4Width)
//
// DESCRIPTION:
//
// This method will draw the indicated border type into the area passed,
// using the current drawing attributes
//
// NOTE: This guy is based on other calls that all save and restore the
// graphical attributes of the paintbrush so we don't need to save
// and restore anything other than the colors.
// ---------------------------------------
// INPUT: eBorder is the border type to draw
// areaPos is the position
// c4Width is the width of the border
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID
PROCEXP PAINTBRUSH::DrawBorder( tCIDGui::eBORDERS eBorder
, const AREA& areaPos
, tCIDLib::CARD4 c4Width)
{
tCIDLib::INT4 i4Tmp;
if ((!c4Width) || (c4Width > 512))
{
facCIDGui.LogMsg( __FILE__
, "PAINTBRUSH::DrawBorder"
, __LINE__
, "Border width was 0 or > 512"
, tCIDLib::eSEV_WARNING);
return;
}
// Get the current foreground/background colors
RGBCLR rgbFgn(rgbFgnColor());
RGBCLR rgbBgn(rgbBgnColor());
// Get a copy of the area we can modify
AREA areaDraw(areaPos);
switch(eBorder)
{
case tCIDGui::eBORDER_DIALOG :
case tCIDGui::eBORDER_SOLID :
//
// This one is easy, we just need to draw a solid border around
// the passed area.
//
Stroke(areaPos, c4Width);
break;
case tCIDGui::eBORDER_SIZING :
break;
case tCIDGui::eBORDER_3D :
//
// This one is a raised border followed by a sunken border. Each
// one is half the width, with the raised side getting the odd
// pel if there is one.
//
if (c4Width < 2)
c4Width = 2;
// Get half the width, plus any odd pel
i4Tmp = tCIDLib::INT4(c4Width >> 1);
if (c4Width & 1)
i4Tmp++;
//
// Draw the raised and sunken borders. The call bumps in the
// passed area by the size of the border, so we just call again
// to draw inside it.
//
_Draw3DBorder(tCIDLib::eTRUE, areaDraw, i4Tmp, rgbBgn, rgbFgn);
i4Tmp = tCIDLib::INT4(c4Width >> 1);
_Draw3DBorder(tCIDLib::eFALSE, areaDraw, i4Tmp, rgbBgn, rgbFgn);
break;
case tCIDGui::eBORDER_RAISED :
case tCIDGui::eBORDER_SUNKEN :
//
// Draw either a raised or sunken border.
//
_Draw3DBorder( eBorder == tCIDGui::eBORDER_RAISED ?
tCIDLib::eTRUE : tCIDLib::eFALSE
, areaDraw
, c4Width
, rgbBgn
, rgbFgn);
break;
case tCIDGui::eBORDER_NONE :
default :
break;
}
// Restore the old colors
SetFgnColor(rgbFgn);
SetBgnColor(rgbBgn);
}
//
// FUNCTION/METHOD NAME: eBgnMixMode() const
// eBgnMixMode(eNewMode)
//
// DESCRIPTION:
//
// This method will get/set the background mix mode of the window. The
// window must be in paint mode.
// ---------------------------------------
// INPUT: eNewMode is the mode to set, when setting
//
// OUTPUT: None
//
// RETURN: The new or current background mix mode.
//
tCIDGui::eMIXMODES PROCEXP PAINTBRUSH::eBgnMixMode() const
{
tCIDLib::INT4 i4Mix = GpiQueryBackMix(__hPS);
if (i4Mix == BM_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::eBgnMixMode"
, __LINE__
, "GpiQueryBackMix failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
return tCIDGui::eMIXMODES(i4Mix);
}
tCIDGui::eMIXMODES
PROCEXP PAINTBRUSH::eBgnMixMode(tCIDGui::eMIXMODES eNewMixMode)
{
if (!GpiSetBackMix(__hPS, eNewMixMode))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::eBgnMixMode"
, __LINE__
, "GpiSetBackMix failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
return eNewMixMode;
}
//
// FUNCTION/METHOD NAME: eFgnMixMode() const
// eFgnMixMode(eNewMode)
//
// DESCRIPTION:
//
// This method will get/set the foreground mix mode of the window. The
// window must be in paint mode.
// ---------------------------------------
// INPUT: eNewMode is the mode to set, when setting
//
// OUTPUT: None
//
// RETURN: The new or current foreground mix mode.
//
tCIDGui::eMIXMODES PROCEXP PAINTBRUSH::eFgnMixMode() const
{
tCIDLib::INT4 i4Mix = GpiQueryMix(__hPS);
if (i4Mix == FM_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::eFgnMixMode"
, __LINE__
, "GpiQueryMix failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
return tCIDGui::eMIXMODES(i4Mix);
}
tCIDGui::eMIXMODES
PROCEXP PAINTBRUSH::eFgnMixMode(tCIDGui::eMIXMODES eNewMixMode)
{
if (!GpiSetMix(__hPS, eNewMixMode))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::eFgnMixMode"
, __LINE__
, "GpiSetMix failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
return eNewMixMode;
}
//
// FUNCTION/METHOD NAME: eLineStyle()
// eLineStyle(eLineStyle)
//
// DESCRIPTION:
//
// This method will set/get the current line style
// ---------------------------------------
// INPUT: eLineType is the new line style to set.
//
// OUTPUT: None
//
// RETURN: The current or new line style
//
tCIDGui::eLINESTYLES PROCEXP PAINTBRUSH::eLineStyle() const
{
LONG lType = GpiQueryLineType(__hPS);
if (lType == LINETYPE_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::eLineStyle"
, __LINE__
, "GpiQueryLineType failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
return tCIDGui::eLINESTYLES(lType);
}
tCIDGui::eLINESTYLES PROCEXP
PAINTBRUSH::eLineStyle(tCIDGui::eLINESTYLES eNewStyle) const
{
if (!GpiSetLineType(__hPS, eNewStyle))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::eLineStyle"
, __LINE__
, "GpiSetLineType failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
return eNewStyle;
}
//
// FUNCTION/METHOD NAME: Ellipse(pntCenter, c4Radius)
// Ellipse(areaCircle)
//
// DESCRIPTION:
//
// This method will draw an ellipse using either a center point and radius or
// an area.
// ---------------------------------------
// INPUT: pntCenter is the center point to draw from
// c4Radius is the radius of the ellipse from the center point
// areaCircle is the area to fit the circle into.
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::Ellipse( const POINT& pntCenter
, tCIDLib::CARD4 c4Radius)
{
ARCPARAMS rArcParams;
FIXED Fixed;
// Make sure that the arc params get reset
GRAPHATTR(*this, tCIDGui::eGATTRSET_ARCPARAMS);
SetMemory(&rArcParams, 0, sizeof(ARCPARAMS));
rArcParams.lP = c4Radius;
rArcParams.lQ = c4Radius;
if (!GpiSetArcParams(__hPS, &rArcParams))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Ellipse"
, __LINE__
, "GpiSetArcParams failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Init the scaling data to not do any
Fixed = MAKEFIXED(1, 0);
// Set the position to the center point
GpiMove(__hPS, pntCenter);
// And draw the arc
if (GpiFullArc(__hPS, DRO_OUTLINEFILL, Fixed) == GPI_ERROR)
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Ellipse"
, __LINE__
, "GpiFullArc failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
tCIDLib::VOID PROCEXP PAINTBRUSH::Ellipse(const AREA& areaCircle)
{
ARCPARAMS rArcParams;
FIXED Fixed;
POINTL ptlTmp;
// Make sure that the arc params get reset
GRAPHATTR(*this, tCIDGui::eGATTRSET_ARCPARAMS);
SetMemory(&rArcParams, 0, sizeof(ARCPARAMS));
rArcParams.lP = areaCircle.c4CX() >> 1;
rArcParams.lQ = areaCircle.c4CY() >> 1;
if (!GpiSetArcParams(__hPS, &rArcParams))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Ellipse"
, __LINE__
, "GpiSetArcParams failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Init the scaling data to not do any
Fixed = MAKEFIXED(1, 0);
//
// Set the current position to the center of the area
//
areaCircle.pntCenter().ToPtl(ptlTmp);
GpiMove(__hPS, &ptlTmp);
// And draw the arc
if (GpiFullArc(__hPS, DRO_OUTLINEFILL, Fixed) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Ellipse"
, __LINE__
, "GpiFullArc failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
//
// FUNCTION/METHOD NAME: ePattern() const
// ePattern(ePattern)
//
// DESCRIPTION:
//
// This method will get/set the current pattern
// ---------------------------------------
// INPUT: None
//
// OUTPUT: None
//
// RETURN: The current or new pattern
//
tCIDGui::ePATTERNS PROCEXP PAINTBRUSH::ePattern() const
{
LONG liTmp = GpiQueryPattern(__hPS);
if (liTmp == PATSYM_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::ePattern"
, __LINE__
, "GpiQueryPattern failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
return tCIDGui::ePATTERNS(liTmp);
}
tCIDGui::ePATTERNS PROCEXP PAINTBRUSH::ePattern(tCIDGui::ePATTERNS ePattern)
{
if (!GpiSetPattern(__hPS, ePattern))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::ePattern"
, __LINE__
, "GpiSetPattern failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
return ePattern;
}
//
// FUNCTION/METHOD NAME: FillCurPath(eFill)
// FillCurPath(rgbFillClr. eFill)
//
// DESCRIPTION:
//
// This method will fill the current path using either the passed color or
// the current foreground color. The first version is inline, and just calls
// this one with the current foreground color.
// ---------------------------------------
// INPUT: rgbFillClr is the optional color parm
// eFill is the fill type to use
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP
PAINTBRUSH::FillCurPath(const RGBCLR& rgbFillClr
, tCIDGui::ePATHFILL eFill)
{
tCIDLib::INT4 i4Save = GpiQueryColor(__hPS);
GpiSetColor(__hPS, rgbFillClr);
SetFgnColor(rgbFillClr);
if (!GpiFillPath(__hPS, 1, eFill))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::FillCurPath"
, __LINE__
, "GpiFillPath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
GpiSetColor(__hPS, i4Save);
}
//
// FUNCTION/METHOD NAME: finfCurrent() const
//
// DESCRIPTION:
//
// This method will return a FONTINFO object with info on the currently
// installed font, i.e. the one that is being used to draw with.
// ---------------------------------------
// INPUT: None
//
// OUTPUT: None
//
// RETURN: A font info object
//
FONTINFO PROCEXP PAINTBRUSH::finfCurrent() const
{
return _finfCurFont(__hPS);
}
//
// FUNCTION/METHOD NAME: Line(pntTo)
//
// DESCRIPTION:
//
// This method will draw a line from the current position to the indicated
// point, using the currently set drawing attributes. The current position
// will be left at pntTo.
// ---------------------------------------
// INPUT: pntTo is the destination point of the line.
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::Line(const POINT& pntTo)
{
if (!GpiLine(__hPS, pntTo))
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Line"
, __LINE__
, "GpiLine failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
//
// FUNCTION/METHOD NAME: Line(pntFrom, pntTo)
//
// DESCRIPTION:
//
// This method will draw a line from the indicated from position to the
// indicated to position, using the currently set drawing attributes. The
// current position will be left at pntTo.
// ---------------------------------------
// INPUT: pntTo is the destination point of the line.
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::Line( const POINT& pntFrom
, const POINT& pntTo)
{
if (!GpiMove(__hPS, pntFrom))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Line"
, __LINE__
, "GpiMove failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
if (!GpiLine(__hPS, pntTo))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Line"
, __LINE__
, "GpiLine failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
//
// FUNCTION/METHOD NAME: pntCurPos()
//
// DESCRIPTION:
//
// This method will get the current position.
// ---------------------------------------
// INPUT: None
//
// OUTPUT: None
//
// RETURN: The current position
//
POINT PROCEXP PAINTBRUSH::pntCurPos() const
{
POINTL ptlPos;
if (!GpiQueryCurrentPosition(__hPS, &ptlPos))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::pntCurPos"
, __LINE__
, "GpiQueryCurrentPosition failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
return POINT(ptlPos.x, ptlPos.y);
}
//
// FUNCTION/METHOD NAME: pntRelativePos(i4XOfs, i4YOfs)
//
// DESCRIPTION:
//
// This method will move the current position by the relative offsets given.
// ---------------------------------------
// INPUT: i4XOfs, i4YOfs are the offsets to apply to the current position
//
// OUTPUT: None
//
// RETURN: A POINT object that contains the new position.
//
POINT PROCEXP PAINTBRUSH::pntRelativePos( tCIDLib::INT4 i4XOfs
, tCIDLib::INT4 i4YOfs)
{
POINTL ptlPos;
// Query the current position
if (!GpiQueryCurrentPosition(__hPS, &ptlPos))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::pntRelativePos"
, __LINE__
, "GpiQueryCurrentPosition failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Adjust the result
ptlPos.x += i4XOfs;
ptlPos.y += i4YOfs;
// And move to the new position
if (!GpiMove(__hPS, &ptlPos))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::pntCurPos"
, __LINE__
, "GpiMove failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
return POINT(ptlPos.x, ptlPos.y);
}
//
// FUNCTION/METHOD NAME: PolyLine(apntList, c4Pnts)
//
// DESCRIPTION:
//
// This method will draw a line composed of c4Pnts. The first point is drawn
// to from the current position.
// ---------------------------------------
// INPUT: apntList is an array of POINT objects
// c4Pnts is the number of points in the array.
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::PolyLine( POINT* apntList
, tCIDLib::CARD4 c4Pnts)
{
//
// Allocate a buffer of POINTL structures to hold the points. Then
// convert the passed points to the POINTLs.
//
POINTL* aptlTmp = new POINTL[c4Pnts];
for (tCIDLib::CARD4 c4Ind = 0; c4Ind < c4Pnts; c4Ind++)
apntList[c4Ind].ToPtl(aptlTmp[c4Ind]);
// Ask PM to draw the lines
if (GpiPolyLine(__hPS, c4Pnts, aptlTmp) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::PolyLine"
, __LINE__
, "GpiPolyLine failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Get rid of the temp array
delete aptlTmp;
}
//
// FUNCTION/METHOD NAME: PolyLineDisjoint(apntList, c4Pnts)
//
// DESCRIPTION:
//
// This method will draw a set of line segments. The passed array of POINT
// objects is looked at as pairs of end points. The c4Points value is the
// number of pairs, so it should be the number of points.
// ---------------------------------------
// INPUT: apntList is the list of end points.
// c4Pnts is the number of end point pairs.
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID
PROCEXP PAINTBRUSH::PolyLineDisjoint( POINT* apntList
, tCIDLib::CARD4 c4Pnts)
{
//
// Allocate a buffer of POINTL structures to hold the points. Then
// convert the passed points to the POINTLs.
//
POINTL* aptlTmp = new POINTL[c4Pnts];
for (tCIDLib::CARD4 c4Ind = 0; c4Ind < c4Pnts; c4Ind++)
apntList[c4Ind].ToPtl(aptlTmp[c4Ind]);
// Ask PM to draw the lines
if (GpiPolyLineDisjoint(__hPS, c4Pnts, aptlTmp) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::PolyLineDisjoint"
, __LINE__
, "GpiPolyLineDisjoint failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Get rid of the temp array
delete aptlTmp;
}
//
// FUNCTION/METHOD NAME: ResetAttrs()
//
// DESCRIPTION:
//
// This method will reset the graphical attributes of this window
// ---------------------------------------
// INPUT: None
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::ResetAttrs()
{
if (!GpiResetPS(__hPS, GRES_ATTRS))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::ResetAttrs"
, __LINE__
, "GpiResetPS failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
//
// FUNCTION/METHOD NAME: ResetClipPath()
//
// DESCRIPTION:
//
// This method will reset the clip path to infinity.
// ---------------------------------------
// INPUT: None
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::ResetClipPath()
{
// Reset the clip path to infinite
if (!GpiSetClipPath(__hPS, 0, SCP_RESET))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::ResetClipPath"
, __LINE__
, "GpiSetClipPath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
//
// FUNCTION/METHOD NAME: rgbBgnColor()
// rgbFgnColor()
//
// DESCRIPTION:
//
// These methods will get the color that will be used for background or
// or foreground output.
// ---------------------------------------
// INPUT: rgbNew is the new background color.
//
// OUTPUT: None
//
// RETURN: None
//
RGBCLR PROCEXP PAINTBRUSH::rgbBgnColor() const
{
LONG liClr = GpiQueryBackColor(__hPS);
return RGBCLR(liClr);
}
RGBCLR PROCEXP PAINTBRUSH::rgbFgnColor() const
{
LONG liClr = GpiQueryColor(__hPS);
return RGBCLR(liClr);
}
//
// FUNCTION/METHOD NAME: SetBgnColor(rgbNew)
// SetFgnColor(rgbNew)
//
// DESCRIPTION:
//
// These methods will set the foreground and background colors.
// ---------------------------------------
// INPUT: rgbNew is the new color to set
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::SetBgnColor(const RGBCLR& rgbNew)
{
if (!GpiSetBackColor(__hPS, rgbNew))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetBgnColor"
, __LINE__
, "GpiSetBackColor"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
tCIDLib::VOID PROCEXP PAINTBRUSH::SetFgnColor(const RGBCLR& rgbNew)
{
if (!GpiSetColor(__hPS, rgbNew))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetFgnColor"
, __LINE__
, "GpiSetColor failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
//
// FUNCTION/METHOD NAME: SetCurPos(pntNew)
// SetCurPos(i4XPos, i4YPos)
//
// DESCRIPTION:
//
// These methods will set the current output position.
// ---------------------------------------
// INPUT: pntNew is the new point to set
// i4XPos, i4YPos are the new x,y position to set
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::SetCurPos(const POINT& pntNew)
{
if (!GpiMove(__hPS, pntNew))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetCurPos"
, __LINE__
, "GpiMove failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
tCIDLib::VOID PROCEXP PAINTBRUSH::SetCurPos(tCIDLib::INT4 i4XPos
, tCIDLib::INT4 i4YPos)
{
POINTL ptlTmp;
ptlTmp.x = i4XPos;
ptlTmp.y = i4YPos;
if (!GpiMove(__hPS, &ptlTmp))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetCurPos"
, __LINE__
, "GpiMove failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
//
// FUNCTION/METHOD NAME: SetClipPath(eFillType, eClipOpts)
// SetClipPath(areaToClip, eFillType, eClipOpts)
// SetClipPath(pntFrom, pntTo, eFillType, eClipOpts)
//
// DESCRIPTION:
//
// This method will create a new path using the passed area. The path options
// control how this clip path is mixed with existing clip paths. The path can
// be described as an AREA, two POINTs, or the existing path can be used.
// ---------------------------------------
// INPUT: areaToClip is the area to use for the path.
// pntFrom, pntTo are another means of indicating the path, via two
// points that indicate the corners of an area.
// eFillType is the fill type to use
// eClipOpts are the path control option flags.
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP
PAINTBRUSH::SetClipPath(tCIDGui::ePATHFILL eFillType
, tCIDGui::eCLIPOPTS eClipOpts)
{
// Set the path as the clip path. This implicitly closes the path
if (!GpiSetClipPath(__hPS, 1, tCIDLib::CARD4(eClipOpts | eFillType)))
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetClipPath"
, __LINE__
, "GpiSetClipPath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
tCIDLib::VOID
PROCEXP PAINTBRUSH::SetClipPath(const POINT& pntFrom
, const POINT& pntTo
, tCIDGui::ePATHFILL eFillType
, tCIDGui::eCLIPOPTS eClipOpts)
{
// Just make an area and call the other versin
AREA areaClip(pntFrom, pntTo);
SetClipPath(areaClip, eFillType, eClipOpts);
}
tCIDLib::VOID PROCEXP
PAINTBRUSH::SetClipPath( const AREA& areaToClip
, tCIDGui::ePATHFILL eFillType
, tCIDGui::eCLIPOPTS eClipOpts)
{
POINTL ptl1, ptl2;
POINTL aptlBox[3];
// Get POINTLs from the area
areaToClip.ToPtls(ptl1, ptl2);
if (!GpiMove(__hPS, &ptl1))
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetClipPath"
, __LINE__
, "GpiMove failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
if (!GpiBeginPath(__hPS, 1))
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetClipPath"
, __LINE__
, "GpiBeginPath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Create a list of points to draw the clip box
aptlBox[0].x = ptl1.x;
aptlBox[0].y = ptl2.y;
aptlBox[1].x = ptl2.x;
aptlBox[1].y = ptl2.y;
aptlBox[2].x = ptl2.x;
aptlBox[2].y = ptl1.y;
if (GpiPolyLine(__hPS, 3, aptlBox) == GPI_ERROR)
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetClipPath"
, __LINE__
, "GpiPolyLine failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// End the path to close it off
if (!GpiEndPath(__hPS))
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetClipPath"
, __LINE__
, "GpiEndPath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Set the path as the clip path. This implicitly closes the path
if (!GpiSetClipPath(__hPS, 1, tCIDLib::CARD4(eClipOpts | eFillType)))
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetClipPath"
, __LINE__
, "GpiSetClipPath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
//
// FUNCTION/METHOD NAME: SetCurFont(strName)
//
// DESCRIPTION:
//
// This method will set the indicated font as the current font for this
// window object.
// ---------------------------------------
// INPUT: strName is the name that was given to the font when the CreateFont
// method was called.
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::SetCurFont(const STRG16& strName)
{
// Try to find a font with this name
LLSTNODE* plnodFont = _plnodFindFnt(strName);
if (!plnodFont)
{
facCIDGui.LogErr( __FILE__
, "PAINTBRUSH::SetCurFont"
, __LINE__
, GUIERR_FONT_NAME_NOT_FOUND
, tCIDLib::eSEV_PROCESS_FATAL
, tCIDLib::eCLASS_BADPARMS
, strName);
}
// Get the font object out of it
FONT* pfntTmp = (FONT*)plnodFont->pobjData();
// Set our font as the current one.
if (!GpiSetCharSet(__hPS, pfntTmp->_i4FontId))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetCurFont"
, __LINE__
, strName
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
//
// FUNCTION/METHOD NAME: SetDefaultFont()
//
// DESCRIPTION:
//
// This method will reset the font to the default
// ---------------------------------------
// INPUT: None
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::SetDefaultFont()
{
if (!GpiSetCharSet(__hPS, LCID_DEFAULT))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetDefaultFont"
, __LINE__
, "GpiSetCharSet failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
//
// FUNCTION/METHOD NAME: SetPath(areaToClip)
//
// DESCRIPTION:
//
// This method will create a new path using the passed area.
// ---------------------------------------
// INPUT: areaToClip is the area to use for the path.
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::SetPath(const AREA& areaToClip)
{
POINTL ptl1, ptl2;
POINTL aptlBox[3];
// Get POINTLs from the area
areaToClip.ToPtls(ptl1, ptl2);
if (!GpiMove(__hPS, &ptl1))
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetPath"
, __LINE__
, "GpiMove failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
if (!GpiBeginPath(__hPS, 1))
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetPath"
, __LINE__
, "GpiBeginPath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Create a list of points to draw the clip box
aptlBox[0].x = ptl1.x;
aptlBox[0].y = ptl2.y;
aptlBox[1].x = ptl2.x;
aptlBox[1].y = ptl2.y;
aptlBox[2].x = ptl2.x;
aptlBox[2].y = ptl1.y;
if (GpiPolyLine(__hPS, 3, aptlBox) == GPI_ERROR)
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetPath"
, __LINE__
, "GpiPolyLine failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// End the path to close it off
if (!GpiEndPath(__hPS))
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::SetPath"
, __LINE__
, "GpiEndPath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
//
// FUNCTION/METHOD NAME: SetPel(i4XPos, i4YPos, rgbClr)
// SetPel(pntPos, rgbClr)
//
// DESCRIPTION:
//
// This method will set the indicated pel to the passed color
// ---------------------------------------
// INPUT: i4XPos, i4YPos is the position to plot
// pntPos is the position to plot
// rgbClr is the color to plot
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID
PROCEXP PAINTBRUSH::SetPel( tCIDLib::INT4 i4XPos
, tCIDLib::INT4 i4YPos
, const RGBCLR& rgbClr)
{
RGBCLR rgbSave(rgbFgnColor());
SetFgnColor(rgbClr);
POINTL ptlTmp;
ptlTmp.x = i4XPos;
ptlTmp.y = i4YPos;
GpiSetPel(__hPS, &ptlTmp);
SetFgnColor(rgbSave);
}
tCIDLib::VOID PROCEXP PAINTBRUSH::SetPel( const POINT& pntPos
, const RGBCLR& rgbClr)
{
RGBCLR rgbSave(rgbFgnColor());
SetFgnColor(rgbClr);
POINTL ptlTmp;
pntPos.ToPtl(ptlTmp);
GpiSetPel(__hPS, &ptlTmp);
SetFgnColor(rgbSave);
}
//
// FUNCTION/METHOD NAME: StringCharOfs(strbText, c4Ind, i4XStart, i4XEnd)
//
// DESCRIPTION:
//
// This method will calculate the start and end x offset of a particuar char
// of the passed string, using the current drawing attributes. The position
// is from the start of the string, so the returned values are usually added
// to the position where the string was drawn.
// ---------------------------------------
// INPUT: strbText is the string whose char is being calculated
// c4Ind is the index of the char to get
//
// OUTPUT: i4XStart, i4XEnd are filled in with the x offsets of the character
//
// RETURN: None
//
tCIDLib::VOID PAINTBRUSH::StringCharOfs(const STRGBUF& strbText
, tCIDLib::CARD4 c4Ind
, tCIDLib::INT4& i4XStart
, tCIDLib::INT4& i4XEnd)
{
// Probe the string to catch any indexing errors
strbText[c4Ind];
// Array for the text box call
POINTL aptlBox[TXTBOX_COUNT];
// Make a string that we can mangle
STRING strTmp(strbText);
//
// Make a small asciiz string that holds just the character at c4Ind
//
tCIDLib::CH szChar[2];
szChar[0] = strTmp[c4Ind];
szChar[1] = 0;
//
// Cap the string at the passed index and get the length of that. This
// will be the starting offset
//
strTmp[c4Ind] = 0;
// Get the size of this portion of the string
if (!GpiQueryTextBox( __hPS
, strTmp.c4Length()
, strTmp.pSZ()
, TXTBOX_COUNT
, aptlBox))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::areaString"
, __LINE__
, "GpiQueryTextBox failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Store away the left x as the starting x
i4XStart = aptlBox[TXTBOX_BOTTOMRIGHT].x;
//
// Now get the size of the 1 char string that we saved away before
// capping of the temp string object.
//
if (!GpiQueryTextBox( __hPS
, 1
, szChar
, TXTBOX_COUNT
, aptlBox))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::areaString"
, __LINE__
, "GpiQueryTextBox failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// The ending x is the starting x plus the size of the 1 char
i4XEnd = i4XStart + (aptlBox[TXTBOX_TOPRIGHT].x-aptlBox[TXTBOX_TOPLEFT].x);
}
//
// FUNCTION/METHOD NAME: Stroke(areaTarget, c4Width, c4Rounding)
//
// DESCRIPTION:
//
// This method will stroke a line around the target area using the current
// drawing attributes. The line will be c4Width pixels wide, with its outer
// most pixel lying on the area border.
// ---------------------------------------
// INPUT: areaTarget is the area to stroke
// c4Width is the width of the line to draw.
// c4Rounding controls how deeply rounded the corners are
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::Stroke( const AREA& areaTarget
, tCIDLib::CARD4 c4Width
, tCIDLib::CARD4 c4Rounding)
{
if (!c4Width)
{
facCIDGui.LogMsg( __FILE__
, "PAINTBRUSH::Stroke"
, __LINE__
, "0 width stroked"
, tCIDLib::eSEV_WARNING);
return;
}
AREA areaTmp(areaTarget);
POINTL ptl1, ptl2;
tCIDLib::INT4 i4Tmp;
// Save the attributes that we will change
tCIDLib::INT4 i4GeomWidth = GpiQueryLineWidthGeom(__hPS);
//
// Watch for a width of 1 and handle it in a more efficient manner by
// just doing an outline box.
//
if (c4Width == 1)
{
// Set the geometric line width
GpiSetLineWidthGeom(__hPS, 1);
// Convert the passed area to two POINTLs
areaTmp.ToPtls(ptl1, ptl2);
// Move to the first position
if (!GpiMove(__hPS, &ptl1))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Stroke"
, __LINE__
, "GpiMove failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
if (GpiBox( __hPS
, DRO_OUTLINE
, &ptl2
, c4Rounding
, c4Rounding) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Stroke"
, __LINE__
, "GpiBox failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
return;
}
//
// We need to play with the area so that the geometric line that we draw
// will not go outside of the area. When we stroke the path, the line is
// centered on the actual path, so subtract half of the width from each
// side. If it is an odd value, subtract another one.
//
i4Tmp = c4Width >> 1;
if (c4Width & 1)
i4Tmp++;
areaTmp.AdjustSides(-i4Tmp, -i4Tmp);
// Convert the passed area to two POINTLs
areaTmp.ToPtls(ptl1, ptl2);
// Move to the first position
if (!GpiMove(__hPS, &ptl1))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Stroke"
, __LINE__
, "GpiMove failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Start the path bracket and do a box to create the path
if (!GpiBeginPath(__hPS, 1))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Stroke"
, __LINE__
, "GpiBeginPath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
if (GpiBox(__hPS, DRO_OUTLINE, &ptl2, c4Rounding, c4Rounding) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Stroke"
, __LINE__
, "GpiBox failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Close the path
GpiEndPath(__hPS);
// Set the geometric line width
if (!GpiSetLineWidthGeom(__hPS, LONG(c4Width)))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Stroke"
, __LINE__
, "GpiSetLineWidthGeom failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
if (GpiStrokePath(__hPS, 1, 0) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Stroke"
, __LINE__
, "GpiStrokePath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
GpiSetLineWidthGeom(__hPS, i4GeomWidth);
}
//
// FUNCTION/METHOD NAME: Stroke(pntOrg, c4Width, c4XRadius, c4YRadius)
//
// DESCRIPTION:
//
// This method will stroke an elliptical line of the indicated width, starting
// at the given origin and using the passed x and y radii.
// ---------------------------------------
// INPUT: pntOrg is the center point of the ellipse
//
// OUTPUT: None
//
// RETURN: None
//
tCIDLib::VOID PROCEXP PAINTBRUSH::Stroke( const POINT& pntOrg
, tCIDLib::CARD4 c4Width
, tCIDLib::CARD4 c4XRadius
, tCIDLib::CARD4 c4YRadius)
{
if (!c4Width)
{
facCIDGui.LogMsg( __FILE__
, "PAINTBRUSH::Stroke"
, __LINE__
, "0 width stroked"
, tCIDLib::eSEV_WARNING);
return;
}
ARCPARAMS rArcParams;
FIXED Fixed;
tCIDLib::INT4 i4Tmp;
// Make sure that the arc and line params get reset
GRAPHATTR gattrSaveArc(*this, tCIDGui::eGATTRSET_ARCPARAMS);
GRAPHATTR gattrSaveLine(*this, tCIDGui::eGATTRSET_ARCPARAMS);
// Set up new arc params
SetMemory(&rArcParams, 0, sizeof(ARCPARAMS));
rArcParams.lP = c4XRadius;
rArcParams.lQ = c4YRadius;
// Init the scaling data to not do any
Fixed = MAKEFIXED(1, 0);
// Set the position to the center point
GpiMove(__hPS, pntOrg);
//
// If the width is 1, we can do things a lot faster by just doing a
// regular ellipse, without any geometric lines.
//
if (c4Width == 1)
{
GpiSetArcParams(__hPS, &rArcParams);
// And draw the arc
if (GpiFullArc(__hPS, DRO_OUTLINE, Fixed) == GPI_ERROR)
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Stroke"
, __LINE__
, "GpiFullArc failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
return;
}
//
// We need to play with the area so that the geometric line that we
// draw will not go outside of the area. When we stroke the path, the
// line is centered on the actual path, so subtract half of the width
// from each side. If it is an odd value, subtract another one.
//
i4Tmp = c4Width >> 1;
if (c4Width & 1)
i4Tmp++;
rArcParams.lP = c4XRadius - i4Tmp;
rArcParams.lQ = c4YRadius - i4Tmp;
GpiSetArcParams(__hPS, &rArcParams);
// Start the path bracket and do a full arc
if (!GpiBeginPath(__hPS, 1))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Stroke"
, __LINE__
, "GpiBeginPath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// And draw the arc
if (GpiFullArc(__hPS, DRO_OUTLINE, Fixed) == GPI_ERROR)
{
// It failed, so we need to log a message and abort
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Stroke"
, __LINE__
, "GpiFullArc failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Close the path
GpiEndPath(__hPS);
// Set the geometric line width
if (!GpiSetLineWidthGeom(__hPS, LONG(c4Width)))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Stroke"
, __LINE__
, "GpiSetLineWidthGeom failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
if (GpiStrokePath(__hPS, 1, 0) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::Stroke"
, __LINE__
, "GpiStrokePath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
// -----------------------------------------------------------------------------
// PAINTBRUSH: Protected, non-virtual methods
// -----------------------------------------------------------------------------
//
// FUNCTION/METHOD NAME: _Draw3DBorder( bRaised, areaPos, i4Width, rgbBgn
// , rgbFgn)
//
// DESCRIPTION:
//
// This method is for local use and is a low level function for drawing 3D
// borders very quickly. This is done a lot so it is worth being very
// efficient. It also helps the public DrawBorders() function which has a
// need to draw both raised and sunken borders on the same call.
// ---------------------------------------
// INPUT: bRaised indicates whether the border should be raised or sunken.
// areaPos is the area around which the border should go.
// i4Width is the width of the border
// rgbBgn, rgbFgn are the colors to use
//
// OUTPUT: areaPos is deflated to account for the border drawn. This is
// because the caller might want to call again immediately to
// draw another border inside this one.
//
// RETURN: None
//
tCIDLib::VOID
PROCEXP PAINTBRUSH::_Draw3DBorder( tCIDLib::eBOOL bRaised
, AREA& areaPos
, tCIDLib::INT4 i4Width
, const RGBCLR& rgbBgn
, const RGBCLR& rgbFgn)
{
POINTL aptlPath[6], aptlPathSave[6];
// Get the area to an array of POINTLs.
areaPos.ToPtlArray(aptlPath);
// Copy the path list to a backup
CopyMemory(aptlPathSave, aptlPath, sizeof(aptlPath));
// Make sure that the changed attributes get restored
tCIDLib::INT4 i4OldBClr = GpiQueryColor(__hPS);
tCIDLib::INT4 i4OldFClr = GpiQueryColor(__hPS);
// Get quick access to new colors
tCIDLib::INT4 i4BgnClr = rgbBgn;
tCIDLib::INT4 i4FgnClr = rgbFgn;
//
// Handle the special cases of widths of 1 or 2 which are not thick
// enough to deal with via the normal code. We just do the left and
// upper sides as a line and the right and bottom sides as a line
// for a width of 1. If 2, then we just do the same thing inward
// one more pel.
//
tCIDLib::INT4 i4Cnt = i4Width;
if (i4Cnt < 3)
{
while (i4Cnt)
{
if (bRaised)
GpiSetColor(__hPS, i4FgnClr);
else
GpiSetColor(__hPS, i4BgnClr);
GpiMove(__hPS, &aptlPath[0]);
if (!GpiPolyLine(__hPS, 2, &aptlPath[1]))
{
}
if (bRaised)
GpiSetColor(__hPS, i4BgnClr);
else
GpiSetColor(__hPS, i4FgnClr);
if (!GpiPolyLine(__hPS, 2, &aptlPath[3]))
{
}
aptlPath[0].x++;
aptlPath[0].y++;
aptlPath[1].x++;
aptlPath[1].y--;
aptlPath[2].x--;
aptlPath[2].y--;
aptlPath[3].x--;
aptlPath[3].y++;
aptlPath[4].x++;
aptlPath[4].y++;
i4Cnt--;
}
}
else
{
//
// For speed we drop into raw PM here. We need to do this as
// two filled paths. We start by building up a path for the
// upper and left sides. The first 3 are already ok.
//
aptlPath[3].x = aptlPath[2].x-(i4Width-1);
aptlPath[3].y = aptlPath[2].y-(i4Width-1);
aptlPath[4].x = aptlPath[1].x+(i4Width-1);
aptlPath[4].y = aptlPath[1].y-(i4Width-1);
aptlPath[5].x = aptlPath[0].x+(i4Width-1);
aptlPath[5].y = aptlPath[0].y+(i4Width-1);
//
// Set the color according to the border type.
//
if (bRaised)
GpiSetColor(__hPS, i4FgnClr);
else
GpiSetColor(__hPS, i4BgnClr);
// Start off in the lower left corner
GpiMove(__hPS, &aptlPath[0]);
// Start the path bracket and do a polyline to create the path
if (!GpiBeginPath(__hPS, 1))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::DrawBorder"
, __LINE__
, "GpiBeginPath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
if (GpiPolyLine(__hPS, 5, &aptlPath[1]) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::DrawBorder"
, __LINE__
, "GpiPolyLine failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
GpiEndPath(__hPS);
// Fill and outline the path using the set colors
if (GpiFillPath(__hPS, 1, FPATH_ALTERNATE) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::DrawBorder"
, __LINE__
, "GpiFillPath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
// Set up the line segments for the left and bottom sides
aptlPath[0].x = aptlPathSave[3].x;
aptlPath[0].y = aptlPathSave[3].y;
aptlPath[1].x = aptlPathSave[0].x;
aptlPath[1].y = aptlPathSave[0].y;
aptlPath[2].x = aptlPathSave[0].x+(i4Width-1);
aptlPath[2].y = aptlPathSave[0].y+(i4Width-1);
aptlPath[3].x = aptlPathSave[3].x-(i4Width-1);
aptlPath[3].y = aptlPathSave[3].y+(i4Width-1);
aptlPath[4].x = aptlPathSave[2].x-(i4Width-1);
aptlPath[4].y = aptlPathSave[2].y-(i4Width-1);
if (bRaised)
GpiSetColor(__hPS, i4BgnClr);
else
GpiSetColor(__hPS, i4FgnClr);
// Start at the upper right corner
GpiMove(__hPS, &aptlPathSave[2]);
//
// Start the path bracket and do a polyline to create the path. Note
// that the current position
//
if (!GpiBeginPath(__hPS, 1))
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::DrawBorder"
, __LINE__
, "GpiBeginPath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
if (GpiPolyLine(__hPS, 5, aptlPath) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::DrawBorder"
, __LINE__
, "GpiPolyLine failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
GpiEndPath(__hPS);
// Fill and outline the path using the set colors
if (GpiFillPath(__hPS, 1, FPATH_ALTERNATE) == GPI_ERROR)
{
facCIDGui.LogLastSysErr(__FILE__
, "PAINTBRUSH::DrawBorder"
, __LINE__
, "GpiFillPath failed"
, tCIDLib::eSEV_PROCESS_FATAL);
}
}
// Bump in the area
areaPos.AdjustSides(-i4Width, -i4Width);
// Put back the old colors
GpiSetColor(__hPS, i4OldFClr);
GpiSetBackColor(__hPS, i4OldBClr);
}
//
// FUNCTION/METHOD NAME: _plnodFindFnt(strName)
// _plnodFindFnt(i4FontId)
//
// DESCRIPTION:
//
// This method will look for the font with the passed name or id and return
// the linked list node if found, else 0.
//
// NOTE: This guy does not need to be exported.
// ---------------------------------------
// INPUT: strName is the name to look for.
// i4FontId is the font id to look for.
//
// OUTPUT: None
//
// RETURN: A ponter to the linked list node or 0
//
LLSTNODE* PAINTBRUSH::_plnodFindFnt(const STRG16& strName)
{
FONT* pfntTmp;
LLSTNODE* plnodTmp = __llstFonts.plnodHead();
while (plnodTmp)
{
pfntTmp = (FONT*)plnodTmp->pobjData();
if (pfntTmp->_strName == strName)
return plnodTmp;
plnodTmp = plnodTmp->plnodNext();
}
return 0;
}
LLSTNODE* PAINTBRUSH::_plnodFindFnt(tCIDLib::INT4 i4FontId)
{
FONT* pfntTmp;
LLSTNODE* plnodTmp = __llstFonts.plnodHead();
while (plnodTmp)
{
pfntTmp = (FONT*)plnodTmp->pobjData();
if (pfntTmp->_i4FontId == i4FontId)
return plnodTmp;
plnodTmp = plnodTmp->plnodNext();
}
return 0;
}