/miniwindow.cpp
C++ | 4371 lines | 2829 code | 1085 blank | 457 comment | 411 complexity | 856a718eeabe706282ec0916edc9de95 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- // MiniWindow.cpp : implementation of the CMiniWindow class
- //
- #include "stdafx.h"
- #include "MUSHclient.h"
- #include "doc.h"
- #include "MUSHview.h"
- #include "scripting\errors.h"
- #include "color.h"
- #include "mainfrm.h"
- #define PNG_NO_CONSOLE_IO
- #include "png\png.h"
- // constructor
- CMiniWindow::CMiniWindow () :
- m_oldBitmap (NULL),
- m_Bitmap (NULL),
- m_iWidth (0), m_iHeight (0),
- m_iPosition (0), m_iFlags (0),
- m_iBackgroundColour (0), m_bShow (false),
- m_rect (0, 0, 0, 0),
- m_bTemporarilyHide (false),
- m_last_mouseposition (0, 0),
- m_last_mouse_update (0),
- m_client_mouseposition (0, 0)
- {
- dc.CreateCompatibleDC(NULL);
- dc.SetTextAlign (TA_LEFT | TA_TOP);
- m_tDateInstalled = CTime::GetCurrentTime(); // when miniwindow loaded
- } // end CMiniWindow::CMiniWindow (constructor)
- CMiniWindow::~CMiniWindow () // destructor
- {
- // get rid of old one if any
- if (m_Bitmap)
- {
- dc.SelectObject(m_oldBitmap); // swap old one back
- m_Bitmap->DeleteObject (); // delete the one we made
- delete m_Bitmap;
- }
- // delete our fonts
- for (FontMapIterator fit = m_Fonts.begin ();
- fit != m_Fonts.end ();
- fit++)
- delete fit->second;
- m_Fonts.clear ();
- // delete our images
- for (ImageMapIterator it = m_Images.begin ();
- it != m_Images.end ();
- it++)
- delete it->second;
- m_Images.clear ();
- // delete our hotspots
- for (HotspotMapIterator hit = m_Hotspots.begin ();
- hit != m_Hotspots.end ();
- hit++)
- delete hit->second;
- m_Hotspots.clear ();
- } // end CMiniWindow::~CMiniWindow (destructor)
- // a negative or zero value for the RH side of a rectange is considered offset from the right edge
- // eg. -1 is 1 pixel in from right, 0 is the RH edge.
- long CMiniWindow::FixRight (const long Right)
- {
- if (Right <= 0)
- return m_iWidth + Right;
- return Right;
- } // end CMiniWindow::FixRight
- static int BytesPerLine (int nWidth, int nBitsPerPixel)
- {
- return ( (nWidth * nBitsPerPixel + 31) & (~31) ) / 8;
- }
- // helper function to make normal/geometric pens
- // legacy behaviour is to do what we always did
- // however if an endcap or join mask bit is on we juse the ExtCreatePen function
- static void MakeAPen (CPen & pen, long PenColour, long PenStyle, long PenWidth)
- {
- // legacy behaviour
- if ((PenStyle & PS_ENDCAP_MASK) == 0 &&
- (PenStyle & PS_JOIN_MASK) == 0)
- {
- pen.CreatePen (PenStyle, PenWidth, PenColour);
- }
- else
- {
- LOGBRUSH logbrush;
- logbrush.lbStyle = BS_SOLID;
- logbrush.lbColor = PenColour;
- logbrush.lbHatch = 0; // not applicable
- pen.Attach (::ExtCreatePen (PenStyle | PS_GEOMETRIC, PenWidth, &logbrush, 0, NULL));
- }
- } // end of MakeAPen
- // a negative or zero value for the bottom of a rectange is considered offset from the bottom edge
- long CMiniWindow::FixBottom (const long Bottom)
- {
- if (Bottom <= 0)
- return m_iHeight + Bottom;
- return Bottom;
- } // end CMiniWindow::FixBottom
- /* positions:
- 0 = strech to output view size
- 1 = stretch with aspect ratio
- 2 = strech to owner size
- 3 = stretch with aspect ratio
-
- -- going clockwise here:
- -- top
- 4 = top left
- 5 = center left-right at top
- 6 = top right
- -- rh side
- 7 = on right, center top-bottom
- 8 = on right, at bottom
- -- bottom
- 9 = center left-right at bottom
- -- lh side
- 10 = on left, at bottom
- 11 = on left, center top-bottom
- -- middle
- 12 = center all
- 13 = tile
- */
- // create (or re-create) a mini-window
- void CMiniWindow::Create (long Left, long Top, long Width, long Height,
- short Position, long Flags,
- COLORREF BackgroundColour)
- {
-
- m_Location.x = Left ;
- m_Location.y = Top ;
- m_iWidth = Width ;
- m_iHeight = Height ;
- m_iPosition = Position ;
- m_iFlags = Flags ;
- m_iBackgroundColour = BackgroundColour;
- // get rid of old one if any
- if (m_Bitmap)
- {
- dc.SelectObject(m_oldBitmap); // swap old one back
- m_Bitmap->DeleteObject ();
- delete m_Bitmap;
- }
- m_Bitmap = new CBitmap;
- // CreateBitmap with zero-dimensions creates a monochrome bitmap, so force to be at least 1x1
- m_Bitmap->CreateBitmap (MAX (m_iWidth, 1), MAX (m_iHeight, 1), 1, GetDeviceCaps(dc, BITSPIXEL), NULL);
- m_oldBitmap = dc.SelectObject (m_Bitmap);
- dc.SetWindowOrg(0, 0);
- dc.FillSolidRect (0, 0, m_iWidth, m_iHeight, m_iBackgroundColour);
- m_bShow = false;
- // a newly created window has no hotspots
- if ((Flags & MINIWINDOW_KEEP_HOTSPOTS) == 0)
- DeleteAllHotspots ();
- } // end of MiniWindow::Create
- // set/clear the show flag so the window becomes visible
- void CMiniWindow::Show (bool bShow)
- {
- m_bShow = bShow;
- } // end of CMiniWindow::Show
- /*
- Actions:
- 1 = FrameRect ( 1 pixel )
- 2 = FillRect
- 3 = InvertRect
- 4 = 3D Rect (Colour1 is top and left edge colour, Colour2 is bottom and right edge colour)
- 5 = DrawEdge (draws a 3d-style edge with optional fill)
- Colour1 = style of edge:
- EDGE_RAISED: // 5
- EDGE_ETCHED: // 6
- EDGE_BUMP: // 9
- EDGE_SUNKEN: // 10
- Colour2 = where to draw it:
- BF_TOPLEFT 0x3
- BF_TOPRIGHT 0x6
- BF_BOTTOMLEFT 0x9
- BF_BOTTOMRIGHT 0xC
- BF_RECT 0xF
- BF_DIAGONAL 0x0010
- // For diagonal lines, the BF_RECT flags specify the end point of the
- // vector bounded by the rectangle parameter.
- BF_DIAGONAL_ENDTOPLEFT 0x13
- BF_DIAGONAL_ENDTOPRIGHT 0x16
- BF_DIAGONAL_ENDBOTTOMLEFT 0x19
- BF_DIAGONAL_ENDBOTTOMRIGHT 0x1C
- Additional Colour2 flags:
- BF_MIDDLE 0x0800 Fill in the middle
- BF_SOFT 0x1000 For softer buttons
- BF_ADJUST 0x2000 Calculate the space left over
- BF_FLAT 0x4000 For flat rather than 3D borders
- BF_MONO 0x8000 For monochrome borders
- 6 = Flood Fill Border (fills to border specified by Colour1)
- 7 = Flood Fill Surface (fills while on surface specified by Colour1)
- */
- // various rectangle operations
- long CMiniWindow::RectOp (short Action, long Left, long Top, long Right, long Bottom, long Colour1, long Colour2)
- {
- switch (Action)
- {
- case 1: // frame
- {
- CBrush br1;
- br1.CreateSolidBrush (Colour1);
- dc.FrameRect (CRect (Left, Top, FixRight (Right), FixBottom (Bottom)), &br1);
- break;
- }
- case 2: // fill
- {
- CBrush br1;
- br1.CreateSolidBrush (Colour1);
- dc.FillRect (CRect (Left, Top, FixRight (Right), FixBottom (Bottom)), &br1);
- break;
- }
- case 3: // invert
- {
- dc.InvertRect (CRect (Left, Top, FixRight (Right), FixBottom (Bottom)));
- break;
- }
- case 4: // 3D rect
- {
- dc.Draw3dRect (CRect (Left, Top, FixRight (Right), FixBottom (Bottom)), Colour1, Colour2);
- break;
- }
- case 5: // DrawEdge
- {
- switch (Colour1) // nEdge
- {
- // must be one of these 4 flags
- case EDGE_RAISED: // 5
- case EDGE_ETCHED: // 6
- case EDGE_BUMP: // 9
- case EDGE_SUNKEN: // 10
- break;
- default: return eBadParameter;
- }
- if ((Colour2 & 0xFF) > 0x1F)
- return eBadParameter;
- dc.DrawEdge (CRect (Left, Top, FixRight (Right), FixBottom (Bottom)), Colour1, Colour2);
- break;
- }
-
- case 6: // Flood fill border
- {
- dc.FloodFill (Left, Top, Colour1);
- break;
- }
- case 7: // Flood fill surface
- {
- dc.ExtFloodFill (Left, Top, Colour1, FLOODFILLSURFACE);
- break;
- }
- default: return eUnknownOption;
- } // end of switch
- return eOK;
- } // end of CMiniWindow::RectOp
-
- static long ValidatePenStyle (const long PenStyle, const long PenWidth)
- {
- switch (PenStyle & PS_STYLE_MASK)
- {
- // must be one of these flags
- case PS_SOLID: // 0
- case PS_NULL: // 5
- case PS_INSIDEFRAME: // 6
- break;
-
- case PS_DASH: // 1 /* ------- */
- case PS_DOT: // 2 /* ....... */
- case PS_DASHDOT: // 3 /* _._._._ */
- case PS_DASHDOTDOT: // 4 /* _.._.._ */
- if (PenWidth > 1)
- return ePenStyleNotValid;
- break;
- default: return ePenStyleNotValid;
- }
- switch (PenStyle & PS_ENDCAP_MASK)
- {
- // must be one of these flags
- case PS_ENDCAP_ROUND: // 0x000
- case PS_ENDCAP_SQUARE: // 0x100
- case PS_ENDCAP_FLAT: // 0x200
- break;
- default: return ePenStyleNotValid;
- }
- switch (PenStyle & PS_JOIN_MASK)
- {
- // must be one of these flags
- case PS_JOIN_ROUND: // 0x0000
- case PS_JOIN_BEVEL: // 0x1000
- case PS_JOIN_MITER: // 0x2000
- break;
- default: return ePenStyleNotValid;
- }
- return eOK;
- }
- long ValidateBrushStyle (const long BrushStyle,
- const long PenColour,
- const long BrushColour,
- CBrush & br)
- {
- LOGBRUSH lb;
- lb.lbColor = PenColour;
- switch (BrushStyle)
- {
- // must be one of these flags
- case BS_SOLID: // 0
- lb.lbStyle = BS_SOLID;
- lb.lbColor = BrushColour;
- break;
-
- case BS_NULL: // 1
- lb.lbStyle = BS_NULL;
- break;
- // hatched styles:
- case 2:
- lb.lbStyle = BS_HATCHED;
- lb.lbHatch = HS_HORIZONTAL;
- break;
- case 3:
- lb.lbStyle = BS_HATCHED;
- lb.lbHatch = HS_VERTICAL;
- break;
- case 4:
- lb.lbStyle = BS_HATCHED;
- lb.lbHatch = HS_FDIAGONAL;
- break;
- case 5:
- lb.lbStyle = BS_HATCHED;
- lb.lbHatch = HS_BDIAGONAL;
- break;
- case 6:
- lb.lbStyle = BS_HATCHED;
- lb.lbHatch = HS_CROSS;
- break;
- case 7:
- lb.lbStyle = BS_HATCHED;
- lb.lbHatch = HS_DIAGCROSS;
- break;
- // each byte is a line, so 0xAA would be 10101010 (top line)
- // 0x55 would be 01010101 (next line)
- case 8: // fine hatch
- {
- CBitmap bitmap;
- WORD wBits[] = { 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 };
- bitmap.CreateBitmap (8, 8, 1, 1, wBits);
- br.CreatePatternBrush (&bitmap);
- return eOK;
- }
- case 9: // medium hatch
- {
- CBitmap bitmap;
- WORD wBits[] = { 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, };
- bitmap.CreateBitmap (8, 8, 1, 1, wBits);
- br.CreatePatternBrush (&bitmap);
- return eOK;
- }
- case 10: // coarse hatch
- {
- CBitmap bitmap;
- WORD wBits[] = { 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0 };
- bitmap.CreateBitmap (8, 8, 1, 1, wBits);
- br.CreatePatternBrush (&bitmap);
- return eOK;
- }
- case 11: // waves - horizontal
- {
- CBitmap bitmap;
- WORD wBits[] = { 0xCC, 0x33, 0x00, 0x00, 0xCC, 0x33, 0x00, 0x00 };
- bitmap.CreateBitmap (8, 8, 1, 1, wBits);
- br.CreatePatternBrush (&bitmap);
- return eOK;
- }
- case 12: // waves - vertical
- {
- CBitmap bitmap;
- WORD wBits[] = { 0x11, 0x11, 0x22, 0x22, 0x11, 0x11, 0x22, 0x22 };
- bitmap.CreateBitmap (8, 8, 1, 1, wBits);
- br.CreatePatternBrush (&bitmap);
- return eOK;
- }
- default: return eBrushStyleNotValid;
- }
- br.CreateBrushIndirect (&lb);
- return eOK;
- }
- /*
- Actions:
- 1 = Ellipse
- 2 = Rectangle (can have thicker pen style and be filled)
- 3 = Round Rectangle
- 4 = Chord (a closed figure bounded by the intersection of an ellipse and a line segment)
- 5 = Pie (Draws a pie-shaped wedge by drawing an elliptical arc whose center and two endpoints are joined by lines)
- */
- // various circle/ellipse/pie operations
- long CMiniWindow::CircleOp (short Action,
- long Left, long Top, long Right, long Bottom,
- long PenColour, long PenStyle, long PenWidth,
- long BrushColour, long BrushStyle,
- long Extra1, long Extra2, long Extra3, long Extra4)
- {
- long iResult = eUnknownOption;
- if (ValidatePenStyle (PenStyle, PenWidth))
- return ePenStyleNotValid;
- // validate and create requested bruch
- CBrush br;
- if (ValidateBrushStyle (BrushStyle, PenColour, BrushColour, br))
- return eBrushStyleNotValid;
- // create requested pen
- CPen pen;
- MakeAPen (pen, PenColour, PenStyle, PenWidth);
-
- // select into DC
- CPen* oldPen = dc.SelectObject(&pen);
- CBrush* oldBrush = dc.SelectObject(&br);
- if (BrushStyle > 1 && BrushStyle <= 7)
- {
- dc.SetBkColor (BrushColour); // for hatched brushes this is the background colour
- }
- else
- if (BrushStyle > 7) // pattern brushes
- {
- dc.SetTextColor (BrushColour); // for patterned brushes
- dc.SetBkColor (PenColour); // for hatched brushes and patterned brushes
- }
- if (BrushColour != -1)
- dc.SetBkMode (OPAQUE);
- else
- dc.SetBkMode (TRANSPARENT);
- switch (Action)
-
- {
- case 1: // ellipse
- {
- dc.Ellipse (CRect (Left, Top, FixRight (Right), FixBottom (Bottom)));
- iResult = eOK;
- break;
- }
- case 2: // rectangle
- {
- dc.Rectangle (CRect (Left, Top, FixRight (Right), FixBottom (Bottom)));
- iResult = eOK;
- break;
- }
- case 3: // round rectangle
- {
- dc.RoundRect (CRect (Left, Top, FixRight (Right), FixBottom (Bottom)), CPoint (Extra1, Extra2));
- iResult = eOK;
- break;
- }
- case 4: // chord
- {
- dc.Chord (CRect (Left, Top, FixRight (Right), FixBottom (Bottom)),
- CPoint (Extra1, Extra2),
- CPoint (Extra3, Extra4));
- iResult = eOK;
- break;
- }
- case 5: // pie
- {
- dc.Pie (CRect (Left, Top, FixRight (Right), FixBottom (Bottom)),
- CPoint (Extra1, Extra2),
- CPoint (Extra3, Extra4));
- iResult = eOK;
- break;
- }
- } // end of switch
- // put things back
- dc.SelectObject (oldPen);
- dc.SelectObject (oldBrush);
- return iResult;
- } // end of CMiniWindow::CircleOp
-
- // add a font to our map of fonts by name (eg. "inventory")
- long CMiniWindow::Font (LPCTSTR FontId, // eg. "inventory"
- LPCTSTR FontName, // eg. "Courier New"
- double Size,
- BOOL Bold, BOOL Italic, BOOL Underline, BOOL Strikeout,
- short Charset, short PitchAndFamily)
- {
- FontMapIterator it = m_Fonts.find (FontId);
- if (it != m_Fonts.end ())
- {
- delete it->second; // delete existing font
- m_Fonts.erase (it);
- }
- // no font name, and zero point size requested - delete old font
- if (FontName [0] == 0 && Size == 0.0)
- return eOK;
- CFont * pFont = new CFont;
- int lfHeight = -MulDiv(Size ? Size : 10.0, dc.GetDeviceCaps(LOGPIXELSY), 72);
- if (pFont->CreateFont (lfHeight,
- 0, // int nWidth,
- 0, // int nEscapement,
- 0, // int nOrientation,
- Bold ? FW_BOLD : FW_NORMAL, // int nWeight,
- Italic, // BYTE bItalic,
- Underline, // BYTE bUnderline,
- Strikeout, // BYTE cStrikeOut,
- Charset,
- 0, // BYTE nOutPrecision,
- 0, // BYTE nClipPrecision,
- 0, // BYTE nQuality,
- PitchAndFamily,
- FontName) == 0)
- {
- delete pFont;
- return eCannotAddFont;
- }
- m_Fonts [FontId] = pFont;
- return eOK;
- } // end of CMiniWindow::Font
- static void SetUpVariantLong (VARIANT & tVariant, const long iContents)
- {
- VariantClear (&tVariant);
- tVariant.vt = VT_I4;
- tVariant.lVal = iContents;
- } // end of SetUpVariantLong
- static void SetUpVariantString (VARIANT & tVariant, const CString & strContents)
- {
- VariantClear (&tVariant);
- tVariant.vt = VT_BSTR;
- tVariant.bstrVal = strContents.AllocSysString ();
- } // end of SetUpVariantString
- static void SetUpVariantBool (VARIANT & tVariant, const BOOL iContents)
- {
- VariantClear (&tVariant);
- tVariant.vt = VT_BOOL;
- tVariant.boolVal = iContents;
- } // end of SetUpVariantBool
- static void SetUpVariantDate (VARIANT & tVariant, const COleDateTime iContents)
- {
- VariantClear (&tVariant);
- tVariant.vt = VT_DATE;
- tVariant.date = iContents;
- } // end of SetUpVariantDate
- // return info about the select font
- void CMiniWindow::FontInfo (LPCTSTR FontId, long InfoType, VARIANT & vaResult)
- {
- FontMapIterator it = m_Fonts.find (FontId);
- if (it == m_Fonts.end ())
- return; // no such font
- CFont* oldFont = dc.SelectObject(it->second); // select in the requested font
-
- TEXTMETRIC tm;
- dc.GetTextMetrics(&tm);
- CString rString;
- dc.GetTextFace (rString);
- switch (InfoType)
- {
- case 1: SetUpVariantLong (vaResult, tm.tmHeight); break;
- case 2: SetUpVariantLong (vaResult, tm.tmAscent); break;
- case 3: SetUpVariantLong (vaResult, tm.tmDescent); break;
- case 4: SetUpVariantLong (vaResult, tm.tmInternalLeading); break;
- case 5: SetUpVariantLong (vaResult, tm.tmExternalLeading); break;
- case 6: SetUpVariantLong (vaResult, tm.tmAveCharWidth); break;
- case 7: SetUpVariantLong (vaResult, tm.tmMaxCharWidth); break;
- case 8: SetUpVariantLong (vaResult, tm.tmWeight); break;
- case 9: SetUpVariantLong (vaResult, tm.tmOverhang); break;
- case 10: SetUpVariantLong (vaResult, tm.tmDigitizedAspectX); break;
- case 11: SetUpVariantLong (vaResult, tm.tmDigitizedAspectY); break;
- case 12: SetUpVariantLong (vaResult, tm.tmFirstChar); break;
- case 13: SetUpVariantLong (vaResult, tm.tmLastChar); break;
- case 14: SetUpVariantLong (vaResult, tm.tmDefaultChar); break;
- case 15: SetUpVariantLong (vaResult, tm.tmBreakChar); break;
- case 16: SetUpVariantLong (vaResult, tm.tmItalic); break;
- case 17: SetUpVariantLong (vaResult, tm.tmUnderlined); break;
- case 18: SetUpVariantLong (vaResult, tm.tmStruckOut); break;
- case 19: SetUpVariantLong (vaResult, tm.tmPitchAndFamily); break;
- case 20: SetUpVariantLong (vaResult, tm.tmCharSet); break;
- case 21: SetUpVariantString (vaResult, rString); break;
- default:
- vaResult.vt = VT_NULL;
- break;
- } // end of switch
- dc.SelectObject(oldFont);
- } // end of CMiniWindow::FontInfo
- // return list of fonts we installed
- void CMiniWindow::FontList (VARIANT & vaResult)
- {
- COleSafeArray sa; // for array list
- long iCount = 0;
-
- // put the arrays into the array
- if (!m_Fonts.empty ()) // cannot create empty dimension
- {
- sa.CreateOneDim (VT_VARIANT, m_Fonts.size ());
- for (FontMapIterator it = m_Fonts.begin ();
- it != m_Fonts.end ();
- it++)
- {
- // the array must be a bloody array of variants, or VBscript kicks up
- COleVariant v (it->first.c_str ());
- sa.PutElement (&iCount, &v);
- iCount++;
- }
- } // end of having at least one
- vaResult = sa.Detach ();
- } // end of CMiniWindow::FontList
- //helper function to calculate length of UTF8 string
- static long CalculateUTF8length (LPCTSTR Text, size_t length)
- {
-
- int iBad = _pcre_valid_utf8 ((unsigned char *) Text, length);
- if (iBad >= 0)
- return -1;
- // string is OK, calculate its length
- int i = 0; // length
- // this algorithm assumes the UTF-8 is OK, based on the earlier check
- for (register const unsigned char *p = (const unsigned char *) Text ;
- length-- > 0;
- i++)
- {
- register int ab; // additional bytes
- register int c = *p++; // this byte
- if (c < 128)
- continue; // zero additional bytes
- ab = _pcre_utf8_table4 [c & 0x3f]; /* Number of additional bytes */
- length -= ab; // we know string is valid already, so just skip the additional bytes (ab)
- p += ab;
- }
- return i;
- } // end of CalculateUTF8length
- // output text, ordinary or UTF8 - returns length of text
- long CMiniWindow::Text (LPCTSTR FontId, // which previously-created font
- LPCTSTR Text, // what to say
- long Left, long Top, long Right, long Bottom, // where to say it
- long Colour, // colour to show it in
- BOOL Unicode) // true if UTF8
- {
- FontMapIterator it = m_Fonts.find (FontId);
- if (it == m_Fonts.end ())
- return -2;
- size_t length = strlen (Text);
- long utf8_length = 0;
- // give up if no text
- if (length <= 0)
- return 0;
- // quick sanity check on our UTF8 stuff
- if (Unicode)
- {
- utf8_length = CalculateUTF8length (Text, length);
- if (utf8_length < 0)
- return -3; // ohno!
- }
- CFont* oldFont = dc.SelectObject(it->second); // select in the requested font
- CSize textsize;
- dc.SetTextColor (Colour);
- dc.SetBkMode (TRANSPARENT);
- if (Unicode)
- {
- vector<WCHAR> v (utf8_length); // get correct size vector
- int iUnicodeCharacters = MultiByteToWideChar (CP_UTF8, 0,
- Text, length, // input
- &v [0], utf8_length); // output
- ExtTextOutW (dc.m_hDC, Left, Top, ETO_CLIPPED, CRect (Left, Top, FixRight (Right), FixBottom (Bottom) ),
- &v [0], iUnicodeCharacters, NULL);
- // now calculate width of Unicode pixels
- GetTextExtentPoint32W(
- dc.m_hDC, // handle to device context
- &v [0], // pointer to text string
- iUnicodeCharacters, // number of characters in string
- &textsize // pointer to structure for string size
- );
- }
- else
- {
- dc.ExtTextOut (Left, Top, ETO_CLIPPED, CRect (Left, Top, FixRight (Right), FixBottom (Bottom)),
- Text, length, NULL);
- textsize = dc.GetTextExtent (Text, length);
- }
- dc.SelectObject(oldFont);
- return min (textsize.cx, FixRight (Right) - Left); // if clipped, length is width of rectangle
- } // end of CMiniWindow::Text
- // measure text, ordinary or UTF8
- long CMiniWindow::TextWidth (LPCTSTR FontId, // which previously-created font
- LPCTSTR Text, // what to measure
- BOOL Unicode) // true if UTF8
- {
- FontMapIterator it = m_Fonts.find (FontId);
- if (it == m_Fonts.end ())
- return -2;
- size_t length = strlen (Text);
- long utf8_length = 0;
- // give up if no text
- if (length <= 0)
- return 0;
- // quick sanity check on our UTF8 stuff
- if (Unicode)
- {
- utf8_length = CalculateUTF8length (Text, length);
- if (utf8_length < 0)
- return -3; // ohno!
- }
- CFont* oldFont = dc.SelectObject(it->second); // select in the requested font
- CSize textsize;
- if (Unicode)
- {
- vector<WCHAR> v (utf8_length); // get correct size vector
- int iUnicodeCharacters = MultiByteToWideChar (CP_UTF8, 0,
- Text, length, // input
- &v [0], utf8_length); // output
- // now calculate width of Unicode pixels
- GetTextExtentPoint32W(
- dc.m_hDC, // handle to device context
- &v [0], // pointer to text string
- iUnicodeCharacters, // number of characters in string
- &textsize // pointer to structure for string size
- );
- }
- else
- textsize = dc.GetTextExtent (Text, length);
- dc.SelectObject(oldFont);
- return textsize.cx;
- } // end of CMiniWindow::TextWidth
- // draws a straight line
- long CMiniWindow::Line (long x1, long y1, long x2, long y2,
- long PenColour, long PenStyle, long PenWidth)
- {
- if (ValidatePenStyle (PenStyle, PenWidth))
- return ePenStyleNotValid;
- dc.SetBkMode (TRANSPARENT);
- // create requested pen
- CPen pen;
- MakeAPen (pen, PenColour, PenStyle, PenWidth);
- CPen* oldPen = dc.SelectObject(&pen);
- dc.MoveTo (x1, y1);
- dc.LineTo (x2, y2); // note NOT: FixRight (x2), FixBottom (y2) (as at version 4.38)
- // put things back
- dc.SelectObject (oldPen);
- return eOK;
- } // end of CMiniWindow::Line
- // draws an arc
- long CMiniWindow::Arc (long Left, long Top, long Right, long Bottom,
- long x1, long y1,
- long x2, long y2,
- long PenColour, long PenStyle, long PenWidth)
- {
- if (ValidatePenStyle (PenStyle, PenWidth))
- return ePenStyleNotValid;
- dc.SetBkMode (TRANSPARENT);
- // create requested pen
- CPen pen;
- MakeAPen (pen, PenColour, PenStyle, PenWidth);
- CPen* oldPen = dc.SelectObject(&pen);
- dc.Arc(Left, Top, FixRight (Right), FixBottom (Bottom),
- x1, y1, // from
- FixRight (x2), FixBottom (y2)); // to
- // put things back
- dc.SelectObject (oldPen);
- return eOK;
- } // end of CMiniWindow::Arc
- // return info about the window
- void CMiniWindow::Info (long InfoType, VARIANT & vaResult)
- {
- switch (InfoType)
- {
- case 1: SetUpVariantLong (vaResult, m_Location.x); break; // left
- case 2: SetUpVariantLong (vaResult, m_Location.y); break; // top
- case 3: SetUpVariantLong (vaResult, m_iWidth); break; // width
- case 4: SetUpVariantLong (vaResult, m_iHeight); break; // height
- case 5: SetUpVariantBool (vaResult, m_bShow); break; // show flag
- case 6: SetUpVariantBool (vaResult, m_bTemporarilyHide); break; // is it hidden right now?
- case 7: SetUpVariantLong (vaResult, m_iPosition); break; // layout mode
- case 8: SetUpVariantLong (vaResult, m_iFlags); break; // flags
- case 9: SetUpVariantLong (vaResult, m_iBackgroundColour); break; // background colour
- case 10: SetUpVariantLong (vaResult, m_rect.left); break; // where it is right now
- case 11: SetUpVariantLong (vaResult, m_rect.top); break; // "
- case 12: SetUpVariantLong (vaResult, m_rect.right); break; // "
- case 13: SetUpVariantLong (vaResult, m_rect.bottom); break; // "
- case 14: SetUpVariantLong (vaResult, m_last_mouseposition.x); break; // last mouse x position
- case 15: SetUpVariantLong (vaResult, m_last_mouseposition.y); break; // last mouse y position
- case 16: SetUpVariantLong (vaResult, m_last_mouse_update); break; // last position update count
- case 17: SetUpVariantLong (vaResult, m_client_mouseposition.x); break; // last client mouse x position
- case 18: SetUpVariantLong (vaResult, m_client_mouseposition.y); break; // last client mouse y position
- case 19: SetUpVariantString (vaResult, m_sMouseOverHotspot.c_str ()); break; // mouse-over hotspot
- case 20: SetUpVariantString (vaResult, m_sMouseDownHotspot.c_str ()); break; // mouse-down hotspot
- case 21: SetUpVariantDate (vaResult, COleDateTime (m_tDateInstalled.GetTime ())); break;
- default:
- vaResult.vt = VT_NULL;
- break;
- } // end of switch
- } // end of CMiniWindow::Info
- // loads an image file, ready for drawing into window
- long CMiniWindow::LoadImage (LPCTSTR ImageId, LPCTSTR FileName)
- {
- ImageMapIterator it = m_Images.find (ImageId);
- if (it != m_Images.end ())
- {
- delete it->second; // delete existing image
- m_Images.erase (it);
- }
- CString strFileName = FileName;
- strFileName.TrimLeft ();
- strFileName.TrimRight ();
- // no file name means get rid of image
- if (strFileName.IsEmpty ())
- return eOK;
- // have to be long enough to have x.bmp
- if (strFileName.GetLength () < 5)
- return eBadParameter;
- // handle PNG files separately
- if (strFileName.Right (4).CompareNoCase (".png") == 0)
- return LoadPngImage (ImageId, FileName);
- // must be .bmp or .png file
- if (strFileName.Right (4).CompareNoCase (".bmp") != 0)
- return eBadParameter;
- HBITMAP hBmp = (HBITMAP)::LoadImage(
- NULL,
- FileName,
- IMAGE_BITMAP,
- 0,
- 0,
- LR_LOADFROMFILE|LR_CREATEDIBSECTION
- );
- if (hBmp)
- {
- CBitmap * pImage = new CBitmap;
- pImage->Attach (hBmp);
- m_Images [ImageId] = pImage;
- return eOK;
- } // end of having a bitmap loaded
- if (GetLastError () == 2)
- return eFileNotFound;
- return eUnableToLoadImage;
- } // end of CMiniWindow::LoadImage
- // loads an image from memory, ready for drawing into window
- long CMiniWindow::LoadImageMemory(LPCTSTR ImageId,
- unsigned char * Buffer,
- const size_t Length,
- const bool bAlpha)
- {
- ImageMapIterator it = m_Images.find (ImageId);
- if (it != m_Images.end ())
- {
- delete it->second; // delete existing image
- m_Images.erase (it);
- }
- HBITMAP hbmp;
-
- long result = LoadPngMemory (Buffer, Length, hbmp, bAlpha);
- if (result != eOK)
- return result;
- // make bitmap to add to images list
- CBitmap * pImage = new CBitmap;
- pImage->Attach (hbmp);
- m_Images [ImageId] = pImage;
- return eOK;
- } // end of CMiniWindow::LoadImageMemory
- static void user_error_fn(png_structp png_ptr,
- png_const_charp error_msg)
- {
- // AfxMessageBox (error_msg);
- }
- static void user_warning_fn(png_structp png_ptr,
- png_const_charp warning_msg)
- {
- // AfxMessageBox (warning_msg);
- }
- long CMiniWindow::LoadPngImage (LPCTSTR ImageId, LPCTSTR FileName)
- {
- HBITMAP hbmp;
-
- long result = LoadPng (FileName, hbmp);
- if (result != eOK)
- return result;
- // make bitmap to add to images list
- CBitmap * pImage = new CBitmap;
- pImage->Attach (hbmp);
- m_Images [ImageId] = pImage;
- return eOK;
- } // end of CMiniWindow::LoadPngImage
- // saves an image file
- long CMiniWindow::Write (LPCTSTR FileName)
- {
- CString strFileName = FileName;
- strFileName.TrimLeft ();
- strFileName.TrimRight ();
- if (strFileName.IsEmpty ())
- return eNoNameSpecified;
- // have to be long enough to have x.bmp
- if (strFileName.GetLength () < 5)
- return eBadParameter;
- // must be .bmp or .png file
- if (strFileName.Right (4).CompareNoCase (".bmp") != 0 &&
- strFileName.Right (4).CompareNoCase (".png") != 0)
- return eBadParameter;
- // get window data
- CDC gDC;
- gDC.CreateCompatibleDC(&dc);
- CBitmap gbmp;
- BITMAPINFO bmi;
- ZeroMemory (&bmi, sizeof bmi);
- bmi.bmiHeader.biSize = sizeof bmi;
- bmi.bmiHeader.biWidth = m_iWidth;
- bmi.bmiHeader.biHeight = m_iHeight;
- bmi.bmiHeader.biPlanes = 1;
- bmi.bmiHeader.biBitCount = 24;
- bmi.bmiHeader.biCompression = BI_RGB;
- bmi.bmiHeader.biSizeImage = m_iHeight * BytesPerLine (m_iWidth, 24);
- unsigned char * pA = NULL;
- HBITMAP hbmG = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void**) &pA, NULL, 0);
- HBITMAP hOldAbmp = (HBITMAP) SelectObject(gDC.m_hDC, hbmG);
- // copy image from miniwindow to bitmap
- gDC.BitBlt (0, 0, m_iWidth, m_iHeight, &dc, 0, 0, SRCCOPY);
- long iReturn = eOK;
- // must be .bmp or .png file
- if (strFileName.Right (4).CompareNoCase (".png") == 0)
- iReturn = WritePng (FileName, &bmi, pA);
- else
- { // write BMP file
- // create requested file
- CFile file;
- if( !file.Open (FileName, CFile::modeWrite | CFile::modeCreate))
- return eCouldNotOpenFile;
- BITMAPFILEHEADER hdr;
- ZeroMemory (&hdr, sizeof hdr);
- // Fill in the fields of the file header
- hdr.bfType = ((WORD) ('M' << 8) | 'B'); // is always "BM"
- hdr.bfOffBits = sizeof hdr + sizeof bmi.bmiHeader;
- hdr.bfSize = hdr.bfOffBits + bmi.bmiHeader.biSizeImage;
-
- try
- {
- // Write the file header
- file.Write( &hdr, sizeof hdr);
-
- // Write the bitmap info header
- file.Write( &bmi.bmiHeader, sizeof bmi.bmiHeader);
- // Write the bits
- file.Write( pA, bmi.bmiHeader.biSizeImage);
- }
- catch (CFileException * e)
- {
- e->Delete ();
- iReturn = eLogFileBadWrite;
- } // end of catching a file exception
- } // end of writing BMP file
- // finished with bitmap
- SelectObject(gDC.m_hDC, hOldAbmp);
- DeleteObject (hbmG);
- return iReturn;
- } // end of CMiniWindow::Write
- long CMiniWindow::WritePng (LPCTSTR FileName, const BITMAPINFO * bmi, unsigned char * pData)
- {
- // open file
- FILE *fp = fopen(FileName, "wb");
- if (!fp)
- return (eCouldNotOpenFile);
- // create PNG structure
- png_structp png_ptr = png_create_write_struct
- (PNG_LIBPNG_VER_STRING, NULL,
- user_error_fn, user_warning_fn);
- if (!png_ptr)
- {
- fclose (fp);
- return eLogFileBadWrite;
- }
- // create info structure
- png_infop info_ptr = png_create_info_struct(png_ptr);
- if (!info_ptr)
- {
- png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
- fclose (fp);
- return eLogFileBadWrite;
- }
-
- #pragma warning (push)
- #pragma warning (disable : 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
- // if png fails it will longjmp back to here, so we destroy the structure,
- // close the file, and wrap up
- if (setjmp(png_jmpbuf(png_ptr)))
- {
- png_destroy_write_struct(&png_ptr, &info_ptr);
- fclose (fp);
- return eLogFileBadWrite;
- }
- #pragma warning (pop)
- // initialize IO
- png_init_io (png_ptr, fp);
- // tell PNG the file format
- png_set_IHDR (png_ptr,
- info_ptr,
- bmi->bmiHeader.biWidth,
- bmi->bmiHeader.biHeight,
- 8, // bits per pixel
- PNG_COLOR_TYPE_RGB,
- PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_DEFAULT,
- PNG_FILTER_TYPE_DEFAULT);
- // set up pointer to each row of data
- vector<png_byte *> row_pointers;
- row_pointers.resize (bmi->bmiHeader.biHeight);
- long bpl = BytesPerLine (bmi->bmiHeader.biWidth, 24);
- long row;
- unsigned char * p = pData;
- // have to reverse row order
- for (row = 0; row < info_ptr->height; row++, p += bpl)
- row_pointers [bmi->bmiHeader.biHeight - row - 1] = p;
- // tell png where our pixel data is
- png_set_rows (png_ptr, info_ptr, &row_pointers [0]);
- // write out the image data
- png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_BGR, NULL);
- // wrap up
- png_write_end (png_ptr, info_ptr);
-
- // done with data
- png_destroy_write_struct (&png_ptr, &info_ptr);
- // done with file
- fclose (fp);
- return eOK;
- } // end of CMiniWindow::WritePng
- /*
- for monitors with 256 colours or less, consider:
- HDRAWDIB hdd = DrawDibOpen();
- DrawDibDraw(hdd, hPaintDC,0,0,BITMAP_WIDTH,BITMAP_HEIGHT,&m_BitmapInfo,m_pBits,0,0,BITMAP_WIDTH,BITMAP_HEIGHT,DDF_HALFTONE);
- DrawDibClose(hdd);
- */
- // draw a previously-loaded image into the window
- long CMiniWindow::DrawImage(LPCTSTR ImageId,
- long Left, long Top, long Right, long Bottom,
- short Mode,
- long SrcLeft, long SrcTop, long SrcRight, long SrcBottom)
- {
- ImageMapIterator it = m_Images.find (ImageId);
- if (it == m_Images.end ())
- return eImageNotInstalled;
- CBitmap * bitmap = it->second;
- dc.SetBkMode (TRANSPARENT);
- dc.SetStretchBltMode (HALFTONE); // looks better when squashed
- SetBrushOrgEx(dc.m_hDC, 0, 0, NULL); // as recommended after SetStretchBltMode
- BITMAP bi;
- bitmap->GetBitmap(&bi);
- CDC bmDC;
- bmDC.CreateCompatibleDC(&dc);
- CBitmap *pOldbmp = bmDC.SelectObject(bitmap);
- // adjust so that -1 means 1 from right
- if (SrcRight <= 0)
- SrcRight = bi.bmWidth + SrcRight;
- if (SrcBottom <= 0)
- SrcBottom = bi.bmHeight + SrcBottom;
- // calculate size of desired rectangle
- long iWidth = SrcRight - SrcLeft;
- long iHeight = SrcBottom - SrcTop;
- if (iWidth > 0 && iHeight > 0) // sanity check
- switch (Mode)
- {
- case 1: dc.BitBlt (Left, Top, iWidth, iHeight, &bmDC, SrcLeft, SrcTop, SRCCOPY);
- break; // straight copy
- case 2: dc.StretchBlt (Left, Top, FixRight (Right) - Left, FixBottom (Bottom) - Top, &bmDC,
- SrcLeft, SrcTop, SrcRight - SrcLeft, SrcBottom - SrcTop, SRCCOPY);
- break; // stretch
- case 3: // transparency, och!
- {
- COLORREF crOldBack = dc.SetBkColor (RGB (255, 255, 255)); // white
- COLORREF crOldText = dc.SetTextColor (RGB (0, 0, 0)); // black
- CDC dcTrans; // transparency mask
- // Create a memory dc for the mask
- dcTrans.CreateCompatibleDC(&dc);
- // Create the mask bitmap for the subset of the main image
- CBitmap bitmapTrans;
- bitmapTrans.CreateBitmap(iWidth, iHeight, 1, 1, NULL);
- // Select the mask bitmap into the appropriate dc
- CBitmap* pOldBitmapTrans = dcTrans.SelectObject(&bitmapTrans);
- // Our transparent pixel will be at 0,0 (top left corner) of original image (not subimage)
- COLORREF crOldBackground = bmDC.SetBkColor (::GetPixel (bmDC, 0, 0));
- // Build mask based on transparent colour at location 0, 0
- dcTrans.BitBlt (0, 0, iWidth, iHeight, &bmDC, SrcLeft, SrcTop, SRCCOPY);
- // Do the work
- dc.BitBlt (Left, Top, iWidth, iHeight, &bmDC, SrcLeft, SrcTop, SRCINVERT);
- dc.BitBlt (Left, Top, iWidth, iHeight, &dcTrans, 0, 0, SRCAND);
- dc.BitBlt (Left, Top, iWidth, iHeight, &bmDC, SrcLeft, SrcTop, SRCINVERT);
- // Restore settings
- dcTrans.SelectObject(pOldBitmapTrans);
- dc.SetBkColor(crOldBack);
- dc.SetTextColor(crOldText);
- bmDC.SetBkColor(crOldBackground);
- }
- break;
- default: return eBadParameter;
- } // end of switch
- bmDC.SelectObject(pOldbmp);
- return eOK;
- } // end of CMiniWindow::DrawImage
- // return list of images
- void CMiniWindow::ImageList(VARIANT & vaResult)
- {
- COleSafeArray sa; // for array list
- long iCount = 0;
-
- // put the arrays into the array
- if (!m_Images.empty ()) // cannot create empty dimension
- {
- sa.CreateOneDim (VT_VARIANT, m_Images.size ());
- for (ImageMapIterator it = m_Images.begin ();
- it != m_Images.end ();
- it++)
- {
- // the array must be a bloody array of variants, or VBscript kicks up
- COleVariant v (it->first.c_str ());
- sa.PutElement (&iCount, &v);
- iCount++;
- }
- } // end of having at least one
- vaResult = sa.Detach ();
- } // end of CMiniWindow::ImageList
- // return info about the selected image
- void CMiniWindow::ImageInfo (LPCTSTR ImageId, long InfoType, VARIANT & vaResult)
- {
- ImageMapIterator it = m_Images.find (ImageId);
- if (it == m_Images.end ())
- return; // no such Image
- CBitmap * bitmap = it->second;
- BITMAP bi;
- bitmap->GetBitmap(&bi);
- switch (InfoType)
- {
- case 1: SetUpVariantLong (vaResult, bi.bmType); break;
- case 2: SetUpVariantLong (vaResult, bi.bmWidth); break;
- case 3: SetUpVariantLong (vaResult, bi.bmHeight); break;
- case 4: SetUpVariantLong (vaResult, bi.bmWidthBytes);break;
- case 5: SetUpVariantLong (vaResult, bi.bmPlanes); break;
- case 6: SetUpVariantLong (vaResult, bi.bmBitsPixel); break;
- default:
- vaResult.vt = VT_NULL;
- break;
- } // end of switch
- } // end of CMiniWindow::ImageInfo
- // draw bezier curves
- long CMiniWindow::Bezier(LPCTSTR Points, long PenColour, long PenStyle, long PenWidth)
- {
- if (ValidatePenStyle (PenStyle, PenWidth))
- return ePenStyleNotValid;
- vector<string> v;
- StringToVector (Points, v, ",");
- int iCount = v.size ();
- // must have at least a start point (2 items), plus one extra (3 points)
- if (iCount < 8)
- return eInvalidNumberOfPoints;
- // and has to be 2 more than 6 items (1 more than 3n points)
- if ((iCount % 6) != 2)
- return eInvalidNumberOfPoints;
- iCount = iCount / 2; // number of points
- vector<POINT> points (iCount);
- int iCurrent = 0;
- for (vector<string>::const_iterator i = v.begin (); i != v.end (); i++)
- {
- if (!IsStringNumber (*i, true))
- return eInvalidPoint;
- points [iCurrent].x = atol (i->c_str ());
- i++; // we know this is safe becaue of earlier check (we must have pairs of numbers)
- if (!IsStringNumber (*i, true))
- return eInvalidPoint;
- points [iCurrent].y = atol (i->c_str ());
- iCurrent++; // onto next point
- }
- dc.SetBkMode (TRANSPARENT);
- // create requested pen
- CPen pen;
- MakeAPen (pen, PenColour, PenStyle, PenWidth);
- CPen* oldPen = dc.SelectObject(&pen);
- dc.PolyBezier(&points [0], iCount);
- // put things back
- dc.SelectObject (oldPen);
- return eOK;
- } // end of CMiniWindow::Bezier
- // draw a polygon (straight lines)
- long CMiniWindow::Polygon(LPCTSTR Points,
- long PenColour, short PenStyle, long PenWidth,
- long BrushColour, long BrushStyle,
- BOOL Close,
- BOOL Winding)
- {
- if (ValidatePenStyle (PenStyle, PenWidth))
- return ePenStyleNotValid;
- // validate and create requested bruch
- CBrush br;
- if (ValidateBrushStyle (BrushStyle, PenColour, BrushColour, br))
- return eBrushStyleNotValid;
- vector<string> v;
- StringToVector (Points, v, ",");
- int iCount = v.size ();
- // must have at least a start point (2 items), plus one extra (1 point)
- if (iCount < 4)
- return eInvalidNumberOfPoints;
- // it has to be divisible by 2
- if ((iCount % 2) != 0)
- return eInvalidNumberOfPoints;
- iCount = iCount / 2; // number of points
- vector<POINT> points (iCount);
- int iCurrent = 0;
- for (vector<string>::const_iterator i = v.begin (); i != v.end (); i++)
- {
- if (!IsStringNumber (*i, true))
- return eInvalidPoint;
- points [iCurrent].x = atol (i->c_str ());
- i++; // we know this is safe becaue of earlier check (we must have pairs of numbers)
- if (!IsStringNumber (*i, true))
- return eInvalidPoint;
- points [iCurrent].y = atol (i->c_str ());
- iCurrent++; // onto next point
- }
- // create requested pen
- CPen pen;
- MakeAPen (pen, PenColour, PenStyle, PenWidth);
- // select pen and brush into device context
- CPen* oldPen = dc.SelectObject(&pen);
- CBrush* oldBrush = dc.SelectObject(&br);
- dc.SetPolyFillMode (Winding ? WINDING : ALTERNATE);
- if (BrushStyle > 1 && BrushStyle <= 7)
- {
- dc.SetBkColor (BrushColour); // for hatched brushes this is the background colour
- }
- else
- if (BrushStyle > 7) // pattern brushes
- {
- dc.SetTextColor (BrushColour); // for patterned brushes
- dc.SetBkColor (PenColour); // for hatched brushes and patterned brushes
- }
- if (BrushColour != -1)
- dc.SetBkMode (OPAQUE);
- else
- dc.SetBkMode (TRANSPARENT);
- if (Close)
- dc.Polygon(&points [0], iCount);
- else
- dc.Polyline(&points [0], iCount);
- // put things back
- dc.SelectObject (oldPen);
- dc.SelectObject (oldBrush);
- return eOK;
- } // end of CMiniWindow::Polygon
-
- // reposition window
- long CMiniWindow::Position(long Left, long Top,
- short Position,
- long Flags)
- {
- m_Location.x = Left ;
- m_Location.y = Top ;
- m_iPosition = Position ;
- m_iFlags = Flags ;
- return eOK;
- } // end of CMiniWindow::Position
- /*
- Cursor values:
- 0: arrow
- 1: hand
- 2: I-beam
- 3: + symbol
- 4: wait (hour-glass)
- 5: up arrow
- 6: arrow nw-se
- 7: arrow ne-sw
- 8: arrow e-w
- 9: arrow n-s
- 10: arrow - all ways
- 11: (X) no, no, I won't do that, but ...
- 12: help (? symbol)
- Flags:
- 0x01 : report all mouseovers, not just when first entering the hotspot
- */
- // add a hotspot for handling mouse-over, mouse up/down events
- long CMiniWindow::AddHotspot(CMUSHclientDoc * pDoc,
- LPCTSTR HotspotId,
- string sPluginID,
- long Left, long Top, long Right, long Bottom,
- LPCTSTR MouseOver,
- LPCTSTR CancelMouseOver,
- LPCTSTR MouseDown,
- LPCTSTR CancelMouseDown,
- LPCTSTR MouseUp,
- LPCTSTR TooltipText,
- long Cursor,
- long Flags)
- {
- if (strlen (MouseOver) > 0 && CheckLabel (MouseOver, true))
- return eInvalidObjectLabel;
- if (strlen (CancelMouseOver) > 0 && CheckLabel (CancelMouseOver, true))
- return eInvalidObjectLabel;
- if (strlen (MouseDown) > 0 && CheckLabel (MouseDown, true))
- return eInvalidObjectLabel;
- if (strlen (CancelMouseDown) > 0 && CheckLabel (CancelMouseDown, true))
- return eInvalidObjectLabel;
- if (strlen (MouseUp) > 0 && CheckLabel (MouseUp, true))
- return eInvalidObjectLabel;
- // can't switch plugins here :)
- if (!m_sCallbackPlugin.empty () && m_sCallbackPlugin != sPluginID)
- return eHotspotPluginChanged;
- m_sCallbackPlugin = sPluginID;
- HotspotMapIterator it = m_Hotspots.find (HotspotId);
- if (it != m_Hotspots.end ())
- {
- delete it->second; // delete existing hotspot
- m_Hotspots.erase (it);
- if (m_sMouseOverHotspot == HotspotId)
- m_sMouseOverHotspot.erase ();
- if (m_sMouseDownHotspot == HotspotId)
- m_sMouseDownHotspot.erase ();
- }
- CHotspot * pHotspot = new CHotspot;
- pHotspot->m_rect = CRect (Left, Top, FixRight (Right), FixBottom (Bottom));
- pHotspot->m_sMouseOver = MouseOver;
- pHotspot->m_sCancelMouseOver = CancelMouseOver;
- pHotspot->m_sMouseDown = MouseDown;
- pHotspot->m_sCancelMouseDown = CancelMouseDown;
- pHotspot->m_sMouseUp = MouseUp;
- pHotspot->m_sTooltipText = TooltipText;
- pHotspot->m_Cursor = Cursor;
- pHotspot->m_Flags = Flags;
- // if not in a plugin, look in main world for hotspot callbacks, and remember the dispatch ID
- if (sPluginID.empty ())
- {
- CString strErrorMessage;
- pHotspot->m_dispid_MouseOver = pDoc->GetProcedureDispid (MouseOver, "mouse over", "", strErrorMessage);
- pHotspot->m_dispid_CancelMouseOver = pDoc->GetProcedureDispid (CancelMouseOver, "cancel mouse over", "", strErrorMessage);
- pHotspot->m_dispid_MouseDown = pDoc->GetProcedureDispid (MouseDown, "mouse down", "", strErrorMessage);
- pHotspot->m_dispid_CancelMouseDown = pDoc->GetProcedureDispid (CancelMouseDown, "cancel mouse down", "", strErrorMessage);
- pHotspot->m_dispid_MouseUp = pDoc->GetProcedureDispid (MouseUp, "mouse up", "", strErrorMessage);
- }
-
- m_Hotspots [HotspotId] = pHotspot;
- return eOK;
- } // end of CMiniWindow::AddHotspot
- // remove a previously-installed hotspot
- long CMiniWindow::DeleteHotspot(LPCTSTR HotspotId)
- {
- HotspotMapIterator it = m_Hotspots.find (HotspotId);
- if (it == m_Hotspots.end ())
- return eHotspotNotInstalled; // no such hotspot
- delete it->second;
- m_Hotspots.erase (it);
- if (m_sMouseOverHotspot == HotspotId)
- m_sMouseOverHotspot.erase ();
- if (m_sMouseDownHotspot == HotspotId)
- m_sMouseDownHotspot.erase ();
- if (m_Hotspots.empty ())
- m_sCallbackPlugin.erase ();
- return eOK;
- } // end of CMiniWindow::DeleteHotspot
- // return list of all hotspots in this miniwindow
- void CMiniWindow::HotspotList(VARIANT & vaResult)
- {
- COleSafeArray sa; // for array list
- long iCount = 0;
-
- // put the arrays into the array
- if (!m_Hotspots.empty ()) // cannot create empty dimension
- {
- sa.CreateOneDim (VT_VARIANT, m_Hotspots.size ());
- for (HotspotMapIterator it = m_Hotspots.begin ();
- it != m_Hotspots.end ();
- it++)
- {
- // the array must be a bloody array of variants, or VBscript kicks up
- COleVariant v (it->first.c_str ());
- sa.PutElement (&iCount, &v);
- iCount++;
- }
- } // end of having at least one
- vaResult = sa.Detach ();
- } // end of CMiniWindow::HotspotList
- // delete all hotspots
- long CMiniWindow::DeleteAllHotspots()
- {
- // delete our hotspots
- for (HotspotMapIterator hit = m_Hotspots.begin ();
- hit != m_Hots…
Large files files are truncated, but you can click here to view the full file